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.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 37f749c44f24d..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; } @@ -244,11 +236,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); } /**************************************************************************** diff --git a/arch/xtensa/src/common/xtensa_irqdispatch.c b/arch/xtensa/src/common/xtensa_irqdispatch.c index 99856c1ed8bd4..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 @@ -82,19 +92,18 @@ 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. */ - 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 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. */ 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