From 91eaa14433de9c0ef6d0122e935ecd2c81817e99 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Sun, 29 Sep 2024 13:55:56 +0800 Subject: [PATCH 1/5] fix compile error: Register: smp Register: nsh Register: sh Register: getprime Register: ostest Espressif HAL for 3rd Party Platforms: b4c723a119344b4b71d69819019d55637fb570fd common/xtensa_cpupause.c: In function 'xtensa_pause_handler': common/xtensa_cpupause.c:240:3: warning: implicit declaration of function 'xtensa_savestate'; did you mean 'xtensa_setps'? [-Wimplicit-function-declaration] 240 | xtensa_savestate(tcb->xcp.regs); | ^~~~~~~~~~~~~~~~ | xtensa_setps common/xtensa_cpupause.c:243:3: warning: implicit declaration of function 'xtensa_restorestate'; did you mean 'xtensa_context_restore'? [-Wimplicit-function-declaration] 243 | xtensa_restorestate(tcb->xcp.regs); | ^~~~~~~~~~~~~~~~~~~ | xtensa_context_restore Signed-off-by: hujun5 --- arch/xtensa/src/common/xtensa_cpupause.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/xtensa/src/common/xtensa_cpupause.c b/arch/xtensa/src/common/xtensa_cpupause.c index 37f749c44f24d..3709e45da8e56 100644 --- a/arch/xtensa/src/common/xtensa_cpupause.c +++ b/arch/xtensa/src/common/xtensa_cpupause.c @@ -244,11 +244,7 @@ void xtensa_pause_handler(void) leave_critical_section(flags); } - tcb = current_task(cpu); - xtensa_savestate(tcb->xcp.regs); nxsched_process_delivered(cpu); - tcb = current_task(cpu); - xtensa_restorestate(tcb->xcp.regs); } /**************************************************************************** From 3e9c8c0d294442384182ebdc2a8abc14e06c4b27 Mon Sep 17 00:00:00 2001 From: ligd Date: Fri, 26 Jul 2024 23:14:13 +0800 Subject: [PATCH 2/5] arch: change nxsched_suspend/resume_scheduler() called position for the citimon stats: thread 0: thread 1: enter_critical (t0) up_switch_context note suspend thread0 (t1) thread running IRQ happen, in ISR: post thread0 up_switch_context note resume thread0 (t2) ISR continue f1 ISR continue f2 ... ISR continue fn leave_critical (t3) You will see, the thread 0, critical_section time is: (t1 - t0) + (t3 - t2) BUT, this result contains f1 f2 .. fn time spent, it is wrong to tell user thead0 hold the critical lots of time but actually not belong to it. Resolve: change the nxsched_suspend/resume_scheduler to real hanppends Signed-off-by: ligd --- arch/arm/src/arm/arm_doirq.c | 5 +++ arch/arm/src/armv6-m/arm_doirq.c | 5 +++ arch/arm/src/armv7-a/arm_doirq.c | 5 +++ arch/arm/src/armv7-a/arm_syscall.c | 10 ++++-- arch/arm/src/armv7-m/arm_doirq.c | 5 +++ arch/arm/src/armv7-r/arm_doirq.c | 5 +++ arch/arm/src/armv7-r/arm_syscall.c | 8 ++++- arch/arm/src/armv8-m/arm_doirq.c | 5 +++ arch/arm/src/armv8-r/arm_doirq.c | 8 ++++- arch/arm/src/armv8-r/arm_syscall.c | 8 ++++- arch/arm/src/common/arm_switchcontext.c | 19 +----------- arch/arm64/src/common/arm64_doirq.c | 5 +++ arch/arm64/src/common/arm64_switchcontext.c | 19 +----------- arch/arm64/src/common/arm64_syscall.c | 10 ++++-- arch/ceva/src/common/ceva_doirq.c | 5 +++ arch/ceva/src/common/ceva_switchcontext.c | 12 ------- arch/risc-v/src/common/riscv_doirq.c | 5 +++ arch/risc-v/src/common/riscv_switchcontext.c | 12 ------- arch/x86/src/qemu/qemu_handlers.c | 5 +++ arch/x86_64/src/common/x86_64_switchcontext.c | 21 +++++-------- arch/x86_64/src/intel64/intel64_handlers.c | 5 +++ arch/xtensa/src/common/xtensa_irqdispatch.c | 5 +++ arch/xtensa/src/common/xtensa_switchcontext.c | 31 +------------------ 23 files changed, 108 insertions(+), 110 deletions(-) diff --git a/arch/arm/src/arm/arm_doirq.c b/arch/arm/src/arm/arm_doirq.c index 6cc7da46bdef2..55e056a8ee2ac 100644 --- a/arch/arm/src/arm/arm_doirq.c +++ b/arch/arm/src/arm/arm_doirq.c @@ -103,6 +103,11 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) addrenv_switch(NULL); #endif + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/arm/src/armv6-m/arm_doirq.c b/arch/arm/src/armv6-m/arm_doirq.c index 566d9390a00e3..3065a4f4dad09 100644 --- a/arch/arm/src/armv6-m/arm_doirq.c +++ b/arch/arm/src/armv6-m/arm_doirq.c @@ -75,6 +75,11 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (regs != tcb->xcp.regs) { + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/arm/src/armv7-a/arm_doirq.c b/arch/arm/src/armv7-a/arm_doirq.c index 460bb9a6c478a..97feb8b8f61f6 100644 --- a/arch/arm/src/armv7-a/arm_doirq.c +++ b/arch/arm/src/armv7-a/arm_doirq.c @@ -98,6 +98,11 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) addrenv_switch(NULL); #endif + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/arm/src/armv7-a/arm_syscall.c b/arch/arm/src/armv7-a/arm_syscall.c index 9a8df57bdd8dd..e2791e1817ceb 100644 --- a/arch/arm/src/armv7-a/arm_syscall.c +++ b/arch/arm/src/armv7-a/arm_syscall.c @@ -579,12 +579,18 @@ uint32_t *arm_syscall(uint32_t *regs) addrenv_switch(NULL); #endif + cpu = this_cpu(); + tcb = current_task(cpu); + + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[cpu]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task. g_running_tasks[] is only used by * assertion logic for reporting crashes. */ - cpu = this_cpu(); - tcb = current_task(cpu); g_running_tasks[cpu] = tcb; /* Restore the cpu lock */ diff --git a/arch/arm/src/armv7-m/arm_doirq.c b/arch/arm/src/armv7-m/arm_doirq.c index c1370659c9e74..5c31de792ecf0 100644 --- a/arch/arm/src/armv7-m/arm_doirq.c +++ b/arch/arm/src/armv7-m/arm_doirq.c @@ -75,6 +75,11 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (regs != tcb->xcp.regs) { + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/arm/src/armv7-r/arm_doirq.c b/arch/arm/src/armv7-r/arm_doirq.c index 7b08a7dd56326..dae25dd47e852 100644 --- a/arch/arm/src/armv7-r/arm_doirq.c +++ b/arch/arm/src/armv7-r/arm_doirq.c @@ -77,6 +77,11 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (regs != tcb->xcp.regs) { + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/arm/src/armv7-r/arm_syscall.c b/arch/arm/src/armv7-r/arm_syscall.c index 66d2181618478..d7dcdbcfe9728 100644 --- a/arch/arm/src/armv7-r/arm_syscall.c +++ b/arch/arm/src/armv7-r/arm_syscall.c @@ -566,11 +566,17 @@ uint32_t *arm_syscall(uint32_t *regs) if (regs != tcb->xcp.regs) { + cpu = this_cpu(); + + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[cpu]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task. g_running_tasks[] is only used by * assertion logic for reporting crashes. */ - cpu = this_cpu(); g_running_tasks[cpu] = tcb; /* Restore the cpu lock */ diff --git a/arch/arm/src/armv8-m/arm_doirq.c b/arch/arm/src/armv8-m/arm_doirq.c index e35cbb0eef8cc..3e2fe2e961ff0 100644 --- a/arch/arm/src/armv8-m/arm_doirq.c +++ b/arch/arm/src/armv8-m/arm_doirq.c @@ -124,6 +124,11 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (regs != tcb->xcp.regs) { + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/arm/src/armv8-r/arm_doirq.c b/arch/arm/src/armv8-r/arm_doirq.c index 2863292052b90..98c5dc4bc22d0 100644 --- a/arch/arm/src/armv8-r/arm_doirq.c +++ b/arch/arm/src/armv8-r/arm_doirq.c @@ -72,10 +72,16 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) /* Deliver the IRQ */ irq_dispatch(irq, regs); - tcb = this_task(); if (regs != tcb->xcp.regs) { + tcb = this_task(); + + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/arm/src/armv8-r/arm_syscall.c b/arch/arm/src/armv8-r/arm_syscall.c index 1f82dc20e7b02..285613ed4b057 100644 --- a/arch/arm/src/armv8-r/arm_syscall.c +++ b/arch/arm/src/armv8-r/arm_syscall.c @@ -565,11 +565,17 @@ uint32_t *arm_syscall(uint32_t *regs) if (regs != tcb->xcp.regs) { + cpu = this_cpu(); + + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[cpu]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task. g_running_tasks[] is only used by * assertion logic for reporting crashes. */ - cpu = this_cpu(); g_running_tasks[cpu] = tcb; /* Restore the cpu lock */ diff --git a/arch/arm/src/common/arm_switchcontext.c b/arch/arm/src/common/arm_switchcontext.c index ab266f29fb8f0..946e6441c81b2 100644 --- a/arch/arm/src/common/arm_switchcontext.c +++ b/arch/arm/src/common/arm_switchcontext.c @@ -55,27 +55,10 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) { - /* Update scheduler parameters */ - - nxsched_suspend_scheduler(rtcb); - /* Are we in an interrupt handler? */ - if (up_interrupt_context()) + if (!up_interrupt_context()) { - /* Update scheduler parameters */ - - nxsched_resume_scheduler(tcb); - } - - /* No, then we will need to perform the user context switch */ - - else - { - /* Update scheduler parameters */ - - nxsched_resume_scheduler(tcb); - /* Switch context to the context of the task at the head of the * ready to run list. */ diff --git a/arch/arm64/src/common/arm64_doirq.c b/arch/arm64/src/common/arm64_doirq.c index af0a5abe444c2..9806c2c41c043 100644 --- a/arch/arm64/src/common/arm64_doirq.c +++ b/arch/arm64/src/common/arm64_doirq.c @@ -96,6 +96,11 @@ uint64_t *arm64_doirq(int irq, uint64_t * regs) addrenv_switch(NULL); #endif + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/arm64/src/common/arm64_switchcontext.c b/arch/arm64/src/common/arm64_switchcontext.c index b5ab2234d19c3..51210b228cc64 100644 --- a/arch/arm64/src/common/arm64_switchcontext.c +++ b/arch/arm64/src/common/arm64_switchcontext.c @@ -55,27 +55,10 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) { - /* Update scheduler parameters */ - - nxsched_suspend_scheduler(rtcb); - /* Are we in an interrupt handler? */ - if (up_interrupt_context()) + if (!up_interrupt_context()) { - /* Update scheduler parameters */ - - nxsched_resume_scheduler(tcb); - } - - /* No, then we will need to perform the user context switch */ - - else - { - /* Update scheduler parameters */ - - nxsched_resume_scheduler(tcb); - /* Switch context to the context of the task at the head of the * ready to run list. */ diff --git a/arch/arm64/src/common/arm64_syscall.c b/arch/arm64/src/common/arm64_syscall.c index 318e7e0cf60f3..5a6c91b0c4c5f 100644 --- a/arch/arm64/src/common/arm64_syscall.c +++ b/arch/arm64/src/common/arm64_syscall.c @@ -236,6 +236,9 @@ uint64_t *arm64_syscall_switch(uint64_t * regs) if ((uint64_t *)f_regs != ret_regs) { + cpu = this_cpu(); + tcb = current_task(cpu); + #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, @@ -246,12 +249,15 @@ uint64_t *arm64_syscall_switch(uint64_t * regs) addrenv_switch(NULL); #endif + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[cpu]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task. g_running_tasks[] is only used by * assertion logic for reporting crashes. */ - cpu = this_cpu(); - tcb = current_task(cpu); g_running_tasks[cpu] = tcb; /* Restore the cpu lock */ diff --git a/arch/ceva/src/common/ceva_doirq.c b/arch/ceva/src/common/ceva_doirq.c index acd5ca82b670c..c977dc138e8d5 100644 --- a/arch/ceva/src/common/ceva_doirq.c +++ b/arch/ceva/src/common/ceva_doirq.c @@ -78,6 +78,11 @@ uint32_t *ceva_doirq(int irq, uint32_t *regs) if (regs != up_current_regs()) { + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(this_task()); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/ceva/src/common/ceva_switchcontext.c b/arch/ceva/src/common/ceva_switchcontext.c index 4b55564427886..3f5311064f770 100644 --- a/arch/ceva/src/common/ceva_switchcontext.c +++ b/arch/ceva/src/common/ceva_switchcontext.c @@ -69,10 +69,6 @@ void ceva_switchcontext(uint32_t **saveregs, uint32_t *restoreregs) void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) { - /* Update scheduler parameters */ - - sched_suspend_scheduler(rtcb); - /* Are we in an interrupt handler? */ if (up_current_regs()) @@ -83,10 +79,6 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) rtcb->xcp.regs = up_current_regs(); - /* Update scheduler parameters */ - - sched_resume_scheduler(tcb); - /* Then switch contexts */ up_set_current_regs(tcb->xcp.regs); @@ -96,10 +88,6 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) else { - /* Update scheduler parameters */ - - sched_resume_scheduler(tcb); - /* Switch context to the context of the task at the head of the * ready to run list. */ diff --git a/arch/risc-v/src/common/riscv_doirq.c b/arch/risc-v/src/common/riscv_doirq.c index c02d1196e8371..bbb1db9fb0ac2 100644 --- a/arch/risc-v/src/common/riscv_doirq.c +++ b/arch/risc-v/src/common/riscv_doirq.c @@ -111,6 +111,11 @@ uintreg_t *riscv_doirq(int irq, uintreg_t *regs) addrenv_switch(NULL); #endif + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(tcb); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/risc-v/src/common/riscv_switchcontext.c b/arch/risc-v/src/common/riscv_switchcontext.c index d7df00ef86bea..16252b8a2ad89 100644 --- a/arch/risc-v/src/common/riscv_switchcontext.c +++ b/arch/risc-v/src/common/riscv_switchcontext.c @@ -57,10 +57,6 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) { - /* Update scheduler parameters */ - - nxsched_suspend_scheduler(rtcb); - /* Are we in an interrupt handler? */ if (up_interrupt_context()) @@ -71,10 +67,6 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) riscv_savecontext(rtcb); - /* Update scheduler parameters */ - - nxsched_resume_scheduler(tcb); - /* Then switch contexts. Any necessary address environment * changes will be made when the interrupt returns. */ @@ -86,10 +78,6 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) else { - /* Update scheduler parameters */ - - nxsched_resume_scheduler(tcb); - /* Then switch contexts */ riscv_switchcontext(rtcb, tcb); diff --git a/arch/x86/src/qemu/qemu_handlers.c b/arch/x86/src/qemu/qemu_handlers.c index 3e9175ea0e379..091d75ff74b11 100644 --- a/arch/x86/src/qemu/qemu_handlers.c +++ b/arch/x86/src/qemu/qemu_handlers.c @@ -116,6 +116,11 @@ static uint32_t *common_handler(int irq, uint32_t *regs) addrenv_switch(NULL); #endif + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(this_task()); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/x86_64/src/common/x86_64_switchcontext.c b/arch/x86_64/src/common/x86_64_switchcontext.c index d876f20a30e5b..6a31ca1287031 100644 --- a/arch/x86_64/src/common/x86_64_switchcontext.c +++ b/arch/x86_64/src/common/x86_64_switchcontext.c @@ -59,10 +59,6 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) { int cpu; - /* Update scheduler parameters */ - - nxsched_suspend_scheduler(rtcb); - /* Are we in an interrupt handler? */ if (up_interrupt_context()) @@ -75,10 +71,6 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) x86_64_restore_auxstate(tcb); - /* Update scheduler parameters */ - - nxsched_resume_scheduler(tcb); - /* Then switch contexts. Any necessary address environment * changes will be made when the interrupt returns. */ @@ -94,6 +86,8 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) else if (!up_saveusercontext(rtcb->xcp.regs)) { + cpu = this_cpu(); + x86_64_restore_auxstate(tcb); #ifdef CONFIG_ARCH_ADDRENV @@ -105,19 +99,20 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) addrenv_switch(tcb); #endif - /* Update scheduler parameters */ - - nxsched_resume_scheduler(tcb); /* Restore the cpu lock */ - restore_critical_section(tcb, this_cpu()); + restore_critical_section(tcb, cpu); + + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[cpu]); + nxsched_resume_scheduler(current_task(cpu)); /* Record the new "running" task. g_running_tasks[] is only used by * assertion logic for reporting crashes. */ - cpu = this_cpu(); g_running_tasks[cpu] = current_task(cpu); /* Then switch contexts */ diff --git a/arch/x86_64/src/intel64/intel64_handlers.c b/arch/x86_64/src/intel64/intel64_handlers.c index a4ad29c015e7f..0fc0225211bd9 100644 --- a/arch/x86_64/src/intel64/intel64_handlers.c +++ b/arch/x86_64/src/intel64/intel64_handlers.c @@ -97,6 +97,11 @@ static uint64_t *common_handler(int irq, uint64_t *regs) addrenv_switch(NULL); #endif + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[cpu]); + nxsched_resume_scheduler(this_task()); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/xtensa/src/common/xtensa_irqdispatch.c b/arch/xtensa/src/common/xtensa_irqdispatch.c index 99856c1ed8bd4..daca91ba3eac8 100644 --- a/arch/xtensa/src/common/xtensa_irqdispatch.c +++ b/arch/xtensa/src/common/xtensa_irqdispatch.c @@ -82,6 +82,11 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs) addrenv_switch(NULL); #endif + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(g_running_tasks[this_cpu()]); + nxsched_resume_scheduler(this_task()); + /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting * crashes. diff --git a/arch/xtensa/src/common/xtensa_switchcontext.c b/arch/xtensa/src/common/xtensa_switchcontext.c index 0f5c4ab865e84..a98e3e1069c37 100644 --- a/arch/xtensa/src/common/xtensa_switchcontext.c +++ b/arch/xtensa/src/common/xtensa_switchcontext.c @@ -57,39 +57,10 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) { - /* Update scheduler parameters */ - - nxsched_suspend_scheduler(rtcb); - /* Are we in an interrupt handler? */ - if (up_current_regs()) + if (!up_current_regs()) { - /* Yes, then we have to do things differently. - * Just copy the current_regs into the OLD rtcb. - */ - - xtensa_savestate(rtcb->xcp.regs); - - /* Update scheduler parameters */ - - nxsched_resume_scheduler(tcb); - - /* Then switch contexts. Any necessary address environment - * changes will be made when the interrupt returns. - */ - - xtensa_restorestate(tcb->xcp.regs); - } - - /* No, then we will need to perform the user context switch */ - - else - { - /* Reset scheduler parameters */ - - nxsched_resume_scheduler(tcb); - /* Switch context to the context of the task at the head of the * ready to run list. */ From fe22f7945c5c70034cc9d2341f4aa331f3d25b7a Mon Sep 17 00:00:00 2001 From: ligd Date: Fri, 27 Sep 2024 13:24:10 +0800 Subject: [PATCH 3/5] xtesa: fix lost save & restore states caused by merge code this is caused by: 35c8c80a00a99ff0e19d51eaa74165bd830a36f8 Signed-off-by: ligd --- arch/xtensa/src/common/xtensa_switchcontext.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/xtensa/src/common/xtensa_switchcontext.c b/arch/xtensa/src/common/xtensa_switchcontext.c index a98e3e1069c37..ad84e86ef0386 100644 --- a/arch/xtensa/src/common/xtensa_switchcontext.c +++ b/arch/xtensa/src/common/xtensa_switchcontext.c @@ -59,7 +59,24 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) { /* Are we in an interrupt handler? */ - if (!up_current_regs()) + if (up_current_regs()) + { + /* Yes, then we have to do things differently. + * Just copy the current_regs into the OLD rtcb. + */ + + xtensa_savestate(rtcb->xcp.regs); + + /* Then switch contexts. Any necessary address environment + * changes will be made when the interrupt returns. + */ + + xtensa_restorestate(tcb->xcp.regs); + } + + /* No, then we will need to perform the user context switch */ + + else { /* Switch context to the context of the task at the head of the * ready to run list. From a63d9093b07e37ec971cbf000862c003ddf942ec Mon Sep 17 00:00:00 2001 From: hujun5 Date: Fri, 27 Sep 2024 11:42:44 +0800 Subject: [PATCH 4/5] xtensa: g_current_regs is only used to determine if we are in irq, with other functionalities removed. reason: by doing this we can reduce context switch time, When we exit from an interrupt handler, we directly use tcb->xcp.regs before text data bss dec hex filename 178368 876 130604 309848 4ba58 nuttx after text data bss dec hex filename 178120 876 130212 309208 4b7d8 nuttx szie change -248 Signed-off-by: hujun5 --- arch/xtensa/src/common/xtensa.h | 7 - arch/xtensa/src/common/xtensa_cpupause.c | 12 +- arch/xtensa/src/common/xtensa_irqdispatch.c | 22 +- .../xtensa/src/common/xtensa_schedsigaction.c | 327 ++---------------- arch/xtensa/src/common/xtensa_swint.c | 19 +- arch/xtensa/src/common/xtensa_switchcontext.c | 19 +- 6 files changed, 52 insertions(+), 354 deletions(-) diff --git a/arch/xtensa/src/common/xtensa.h b/arch/xtensa/src/common/xtensa.h index 0d49184bdbd58..bae9bd1f814ff 100644 --- a/arch/xtensa/src/common/xtensa.h +++ b/arch/xtensa/src/common/xtensa.h @@ -103,13 +103,6 @@ #define IDLETHREAD_STACKSIZE ((CONFIG_IDLETHREAD_STACKSIZE + 15) & ~15) #define IDLETHREAD_STACKWORDS (IDLETHREAD_STACKSIZE >> 2) -/* In the Xtensa model, the state is saved in stack, - * only a reference stored in TCB. - */ - -#define xtensa_savestate(regs) ((regs) = up_current_regs()) -#define xtensa_restorestate(regs) up_set_current_regs(regs) - /* Context switching via system calls ***************************************/ #define xtensa_context_restore(regs)\ diff --git a/arch/xtensa/src/common/xtensa_cpupause.c b/arch/xtensa/src/common/xtensa_cpupause.c index 3709e45da8e56..1eeb13c5844db 100644 --- a/arch/xtensa/src/common/xtensa_cpupause.c +++ b/arch/xtensa/src/common/xtensa_cpupause.c @@ -102,11 +102,7 @@ int up_cpu_paused_save(void) sched_note_cpu_paused(tcb); #endif - /* Save the current context at current_regs into the TCB at the head - * of the assigned task list for this CPU. - */ - - xtensa_savestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } @@ -186,11 +182,7 @@ int up_cpu_paused_restore(void) nxsched_resume_scheduler(tcb); - /* Then switch contexts. Any necessary address environment changes - * will be made when the interrupt returns. - */ - - xtensa_restorestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } diff --git a/arch/xtensa/src/common/xtensa_irqdispatch.c b/arch/xtensa/src/common/xtensa_irqdispatch.c index daca91ba3eac8..c3023994c8dc5 100644 --- a/arch/xtensa/src/common/xtensa_irqdispatch.c +++ b/arch/xtensa/src/common/xtensa_irqdispatch.c @@ -44,6 +44,8 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs) { + struct tcb_s *tcb = this_task(); + #ifdef CONFIG_SUPPRESS_INTERRUPTS board_autoled_on(LED_INIRQ); PANIC(); @@ -62,15 +64,23 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs) up_set_current_regs(regs); + if (irq != XTENSA_IRQ_SWINT) + { + /* we are not trigger by syscall */ + + tcb->xcp.regs = regs; + } + /* Deliver the IRQ */ irq_dispatch(irq, regs); + tcb = this_task(); /* Check for a context switch. If a context switch occurred, then * current_regs will have a different value than it did on entry. */ - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously @@ -92,14 +102,8 @@ uint32_t *xtensa_irq_dispatch(int irq, uint32_t *regs) * crashes. */ - g_running_tasks[this_cpu()] = this_task(); - } - - /* Restore the cpu lock */ - - if (regs != up_current_regs()) - { - regs = up_current_regs(); + g_running_tasks[this_cpu()] = tcb; + regs = tcb->xcp.regs; } /* Set current_regs to NULL to indicate that we are no longer in an diff --git a/arch/xtensa/src/common/xtensa_schedsigaction.c b/arch/xtensa/src/common/xtensa_schedsigaction.c index c69fe20d8fc09..2d3a381583d3a 100644 --- a/arch/xtensa/src/common/xtensa_schedsigaction.c +++ b/arch/xtensa/src/common/xtensa_schedsigaction.c @@ -78,11 +78,9 @@ * ****************************************************************************/ -#ifndef CONFIG_SMP void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) { sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); - DEBUGASSERT(tcb != NULL && sigdeliver != NULL); /* Refuse to handle nested signal actions */ @@ -90,321 +88,33 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) { tcb->xcp.sigdeliver = sigdeliver; - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); - /* First, handle some special cases when the signal is being delivered - * to the currently executing task. + * to task that is currently executing on any CPU. */ - if (tcb == this_task()) + if (tcb == this_task() && !up_interrupt_context()) { - /* CASE 1: We are not in an interrupt handler and a task is - * signaling itself for some reason. - */ - - if (!up_current_regs()) - { - /* In this case just deliver the signal now. - * REVISIT: Signal handler will run in a critical section! - */ - - sigdeliver(tcb); - tcb->xcp.sigdeliver = NULL; - } - - /* CASE 2: We are in an interrupt handler AND the interrupted - * task is the same as the one that must receive the signal, then - * we will have to modify the return state as well as the state - * in the TCB. - * - * Hmmm... there looks like a latent bug here: The following logic - * would fail in the strange case where we are in an interrupt - * handler, the thread is signaling itself, but a context switch - * to another task has occurred so that current_regs does not - * refer to the thread of this_task()! + /* In this case just deliver the signal now. + * REVISIT: Signal handler will run in a critical section! */ - else - { - /* Save the context registers. These will be restored by the - * signal trampoline after the signals have been delivered. - * - * NOTE: that hi-priority interrupts are not disabled. - */ - - xtensa_savestate(tcb->xcp.saved_regs); - - /* Duplicate the register context. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - - up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS); - - memcpy(up_current_regs(), tcb->xcp.saved_regs, - XCPTCONTEXT_SIZE); - - /* Then set up to vector to the trampoline with interrupts - * disabled - */ - - up_current_regs()[REG_PC] = (uint32_t)xtensa_sig_deliver; -#ifdef __XTENSA_CALL0_ABI__ - up_current_regs()[REG_PS] = (uint32_t) - (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM); -#else - up_current_regs()[REG_PS] = (uint32_t) - (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | - PS_WOE | PS_CALLINC(1)); -#endif -#ifndef CONFIG_BUILD_FLAT - xtensa_raiseprivilege(up_current_regs()); -#endif - - up_current_regs()[REG_A1] = (uint32_t)(up_current_regs() + - XCPTCONTEXT_REGS); - } + sigdeliver(tcb); + tcb->xcp.sigdeliver = NULL; } - - /* Otherwise, we are (1) signaling a task is not running from an - * interrupt handler or (2) we are not in an interrupt handler and the - * running task is signaling some non-running task. - */ - else { - /* Save the context registers. These will be restored by the - * signal trampoline after the signals have been delivered. - * - * NOTE: that hi-priority interrupts are not disabled. - */ - - tcb->xcp.saved_regs = tcb->xcp.regs; - - /* Duplicate the register context. These will be - * restored by the signal trampoline after the signal has been - * delivered. - */ - - tcb->xcp.regs = (void *)((uint32_t)tcb->xcp.regs - - XCPTCONTEXT_SIZE); - memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); - - tcb->xcp.regs[REG_A1] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; - /* Then set up to vector to the trampoline with interrupts - * disabled - */ - - tcb->xcp.regs[REG_PC] = (uint32_t)xtensa_sig_deliver; -#ifdef __XTENSA_CALL0_ABI__ - tcb->xcp.regs[REG_PS] = (uint32_t) - (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM); -#else - tcb->xcp.regs[REG_PS] = (uint32_t) - (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | - PS_WOE | PS_CALLINC(1)); -#endif -#ifndef CONFIG_BUILD_FLAT - xtensa_raiseprivilege(tcb->xcp.regs); -#endif - } - } -} -#endif /* !CONFIG_SMP */ - #ifdef CONFIG_SMP -void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) -{ - int cpu; - int me; + int cpu = tcb->cpu; + int me = this_cpu(); - sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); - - /* Refuse to handle nested signal actions */ - - if (!tcb->xcp.sigdeliver) - { - tcb->xcp.sigdeliver = sigdeliver; - - /* First, handle some special cases when the signal is being delivered - * to task that is currently executing on any CPU. - */ - - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); - - if (tcb->task_state == TSTATE_TASK_RUNNING) - { - me = this_cpu(); - cpu = tcb->cpu; - - /* CASE 1: We are not in an interrupt handler and a task is - * signaling itself for some reason. - */ - - if (cpu == me && !up_current_regs()) + if (cpu != me) { - /* In this case just deliver the signal now. - * REVISIT: Signal handler will run in a critical section! - */ + /* Pause the CPU */ - sigdeliver(tcb); - tcb->xcp.sigdeliver = NULL; + up_cpu_pause(cpu); } - - /* CASE 2: The task that needs to receive the signal is running. - * This could happen if the task is running on another CPU OR if - * we are in an interrupt handler and the task is running on this - * CPU. In the former case, we will have to PAUSE the other CPU - * first. But in either case, we will have to modify the return - * state as well as the state in the TCB. - */ - - else - { - /* If we signaling a task running on the other CPU, we have - * to PAUSE the other CPU. - */ - - if (cpu != me) - { - /* Pause the CPU */ - - up_cpu_pause(cpu); - - /* Now tcb on the other CPU can be accessed safely */ - - /* Copy tcb->xcp.regs to tcp.xcp.saved_regs. These will be - * restored by the signal trampoline after the signal has - * been delivered. - * - * NOTE: that hi-priority interrupts are not disabled. - */ - - tcb->xcp.saved_regs = tcb->xcp.regs; - - /* The Inter-Processor Interrupt that pauses the other CPU - * generates a level-1 interrupt which sets the PS.EXCM. - * This level-1 interrupt is treated as an Exception and - * the bit PS.EXCM bit is automatically reset on return - * from Exception. However, this is not the case here - * because we are changing the execution to the signal - * trampoline. Restoring the PS register with PS.EXCM bit - * set would cause any other exception to deviate execution - * to the DEC (double exception vector), avoiding it to be - * treated correctly. According to xtensa ISA: "The process - * of taking an interrupt does not clear the interrupt - * request. The process does set PS.EXCM to 1, which - * disables level-1 interrupts in the interrupt handler. - * Typically, PS.EXCM is reset to 0 by the handler, after - * it has set up the stack frame and masked the interrupt." - * Clean the saved PS.EXCM to 1) avoid an exception from - * being properly treated and 2) avoid interrupts to be - * masked while delivering the signal. - */ - - if ((tcb->xcp.saved_regs[REG_PS] & PS_EXCM_MASK) != 0) - { - tcb->xcp.saved_regs[REG_PS] &= ~PS_EXCM_MASK; - } - - /* Duplicate the register context. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - - tcb->xcp.regs = (void *) - ((uint32_t)tcb->xcp.regs - - XCPTCONTEXT_SIZE); - memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, - XCPTCONTEXT_SIZE); - - tcb->xcp.regs[REG_A1] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; - - /* Then set up to vector to the trampoline with interrupts - * disabled - */ - - tcb->xcp.regs[REG_PC] = (uint32_t)xtensa_sig_deliver; -#ifdef __XTENSA_CALL0_ABI__ - tcb->xcp.regs[REG_PS] = (uint32_t) - (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM); -#else - tcb->xcp.regs[REG_PS] = (uint32_t) - (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | - PS_WOE | PS_CALLINC(1)); -#endif -#ifndef CONFIG_BUILD_FLAT - xtensa_raiseprivilege(tcb->xcp.regs); #endif - } - else - { - /* tcb is running on the same CPU */ - - /* Copy tcb->xcp.regs to tcp.xcp.saved_regs. These will be - * restored by the signal trampoline after the signal has - * been delivered. - * - * NOTE: that hi-priority interrupts are not disabled. - */ - - xtensa_savestate(tcb->xcp.saved_regs); - - /* Duplicate the register context. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - - up_set_current_regs(up_current_regs() - XCPTCONTEXT_REGS); - memcpy(up_current_regs(), tcb->xcp.saved_regs, - XCPTCONTEXT_SIZE); - - up_current_regs()[REG_A1] = (uint32_t)(up_current_regs() - + XCPTCONTEXT_REGS); - - /* Then set up to vector to the trampoline with interrupts - * disabled - */ - - up_current_regs()[REG_PC] = (uint32_t)xtensa_sig_deliver; -#ifdef __XTENSA_CALL0_ABI__ - up_current_regs()[REG_PS] = (uint32_t) - (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM); -#else - up_current_regs()[REG_PS] = (uint32_t) - (PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | - PS_WOE | PS_CALLINC(1)); -#endif -#ifndef CONFIG_BUILD_FLAT - xtensa_raiseprivilege(up_current_regs()); -#endif - } - - /* NOTE: If the task runs on another CPU(cpu), adjusting - * global IRQ controls will be done in the pause handler - * on the CPU(cpu) by taking a critical section. - * If the task is scheduled on this CPU(me), do nothing - * because this CPU already took a critical section - */ - - /* RESUME the other CPU if it was PAUSED */ - if (cpu != me) - { - up_cpu_resume(cpu); - } - } - } - - /* Otherwise, we are (1) signaling a task is not running from an - * interrupt handler or (2) we are not in an interrupt handler and the - * running task is signaling some other non-running task. - */ - - else - { /* Save the context registers. These will be restored by the * signal trampoline after the signals have been delivered. * @@ -413,6 +123,11 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.saved_regs = tcb->xcp.regs; + if ((tcb->xcp.saved_regs[REG_PS] & PS_EXCM_MASK) != 0) + { + tcb->xcp.saved_regs[REG_PS] &= ~PS_EXCM_MASK; + } + /* Duplicate the register context. These will be * restored by the signal trampoline after the signal has been * delivered. @@ -442,7 +157,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifndef CONFIG_BUILD_FLAT xtensa_raiseprivilege(tcb->xcp.regs); #endif + +#ifdef CONFIG_SMP + /* RESUME the other CPU if it was PAUSED */ + + if (cpu != me) + { + up_cpu_resume(cpu); + } +#endif } } } -#endif /* CONFIG_SMP */ diff --git a/arch/xtensa/src/common/xtensa_swint.c b/arch/xtensa/src/common/xtensa_swint.c index d62a93ded1ea5..943a772430773 100644 --- a/arch/xtensa/src/common/xtensa_swint.c +++ b/arch/xtensa/src/common/xtensa_swint.c @@ -35,6 +35,7 @@ #include "sched/sched.h" #include "chip.h" #include "signal/signal.h" +#include "sched/sched.h" #include "xtensa.h" /**************************************************************************** @@ -57,11 +58,13 @@ int xtensa_swint(int irq, void *context, void *arg) { uint32_t *regs = (uint32_t *)context; + struct tcb_s *tcb = this_task(); uint32_t cmd; - DEBUGASSERT(regs != NULL && regs == up_current_regs()); + DEBUGASSERT(regs != NULL); cmd = regs[REG_A2]; + tcb->xcp.regs = regs; /* The syscall software interrupt is called with A2 = system call command * and A3..A9 = variable number of arguments depending on the system call. @@ -116,7 +119,7 @@ int xtensa_swint(int irq, void *context, void *arg) case SYS_restore_context: { DEBUGASSERT(regs[REG_A3] != 0); - up_set_current_regs((uint32_t *)regs[REG_A3]); + tcb->xcp.regs = (uint32_t *)regs[REG_A3]; } break; @@ -141,7 +144,7 @@ int xtensa_swint(int irq, void *context, void *arg) { DEBUGASSERT(regs[REG_A3] != 0 && regs[REG_A4] != 0); *(uint32_t **)regs[REG_A3] = regs; - up_set_current_regs((uint32_t *)regs[REG_A4]); + tcb->xcp.regs = (uint32_t *)regs[REG_A4]; } break; @@ -419,9 +422,9 @@ int xtensa_swint(int irq, void *context, void *arg) break; } - if ((up_current_regs()[REG_PS] & PS_EXCM_MASK) != 0) + if ((tcb->xcp.regs[REG_PS] & PS_EXCM_MASK) != 0) { - up_current_regs()[REG_PS] &= ~PS_EXCM_MASK; + tcb->xcp.regs[REG_PS] &= ~PS_EXCM_MASK; } /* Report what happened. That might difficult in the case of a context @@ -429,10 +432,10 @@ int xtensa_swint(int irq, void *context, void *arg) */ #ifdef CONFIG_DEBUG_SYSCALL_INFO - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { svcinfo("SYSCALL Return: Context switch!\n"); - up_dump_register(up_current_regs()); + up_dump_register(tcb->xcp.regs); } else { @@ -440,7 +443,7 @@ int xtensa_swint(int irq, void *context, void *arg) } #endif - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { restore_critical_section(this_task(), this_cpu()); } diff --git a/arch/xtensa/src/common/xtensa_switchcontext.c b/arch/xtensa/src/common/xtensa_switchcontext.c index ad84e86ef0386..a98e3e1069c37 100644 --- a/arch/xtensa/src/common/xtensa_switchcontext.c +++ b/arch/xtensa/src/common/xtensa_switchcontext.c @@ -59,24 +59,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) { /* Are we in an interrupt handler? */ - if (up_current_regs()) - { - /* Yes, then we have to do things differently. - * Just copy the current_regs into the OLD rtcb. - */ - - xtensa_savestate(rtcb->xcp.regs); - - /* Then switch contexts. Any necessary address environment - * changes will be made when the interrupt returns. - */ - - xtensa_restorestate(tcb->xcp.regs); - } - - /* No, then we will need to perform the user context switch */ - - else + if (!up_current_regs()) { /* Switch context to the context of the task at the head of the * ready to run list. From 104981c71d97828e98e655d353e5d07c1d78b65b Mon Sep 17 00:00:00 2001 From: guoshichao Date: Thu, 20 Jun 2024 13:50:30 +0800 Subject: [PATCH 5/5] armv7-m/irq: fix the greenhills compiler compile error CXX: libcxxmini/libxx_new.cxx "/home/guoshichao/work_profile/vela_os/vela_qemu_1/nuttx/include/arch/armv7-m/irq.h", line 594: error #3422: use of the "register" storage class specifier is not allowed register uint32_t sp; ^ "/home/guoshichao/work_profile/vela_os/vela_qemu_1/nuttx/include/arch/armv7-m/irq.h", line 594: error #3422: use of the "register" storage class specifier is not allowed register uint32_t sp; ^ "/home/guoshichao/work_profile/vela_os/vela_qemu_1/nuttx/include/arch/armv7-m/irq.h", line 594: error #3422: use of the "register" storage class specifier is not allowed register uint32_t sp; ^ make[1]: *** [Makefile:69: libxx_delete_sized.o] Error 1 make[1]: *** Waiting for unfinished jobs.... make[1]: *** [Makefile:69: libxx_deletea_sized.o] Error 1 make[1]: *** [Makefile:69: libxx_new.o] Error 1 "/home/guoshichao/work_profile/vela_os/vela_qemu_1/nuttx/include/arch/armv7-m/irq.h", line 594: error #3422: use of the "register" storage class specifier is not allowed register uint32_t sp; ^ "/home/guoshichao/work_profile/vela_os/vela_qemu_1/nuttx/include/arch/armv7-m/irq.h", line 594: error #3422: use of the "register" storage class specifier is not allowed register uint32_t sp; ^ Signed-off-by: guoshichao --- include/nuttx/compiler.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/nuttx/compiler.h b/include/nuttx/compiler.h index fd4ce63336a7a..dc994002e41f0 100644 --- a/include/nuttx/compiler.h +++ b/include/nuttx/compiler.h @@ -82,6 +82,7 @@ #if defined(__ghs__) # define __extension__ +# define register #endif