From 515fcc70f46c23f3cab494fa226d29d7ebd3b080 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Fri, 5 Jul 2024 19:39:58 +0800 Subject: [PATCH 1/4] arm: 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 size nuttx text data bss dec hex filename 225920 409 30925 257254 3ece6 nuttx after text data bss dec hex filename 225604 409 30925 256938 3ebaa nuttx szie change -316 Signed-off-by: hujun5 --- arch/arm/src/arm/arm_doirq.c | 10 +- arch/arm/src/arm/arm_schedulesigaction.c | 67 +--- arch/arm/src/arm/arm_syscall.c | 22 +- arch/arm/src/armv6-m/arm_doirq.c | 11 +- arch/arm/src/armv6-m/arm_schedulesigaction.c | 308 +++------------- arch/arm/src/armv6-m/arm_svcall.c | 26 +- arch/arm/src/armv7-a/arm_cpupause.c | 12 +- arch/arm/src/armv7-a/arm_cpustart.c | 12 +- arch/arm/src/armv7-a/arm_doirq.c | 23 +- arch/arm/src/armv7-a/arm_schedulesigaction.c | 280 ++------------- arch/arm/src/armv7-a/arm_syscall.c | 25 +- arch/arm/src/armv7-m/arm_doirq.c | 11 +- arch/arm/src/armv7-m/arm_schedulesigaction.c | 328 +++--------------- arch/arm/src/armv7-m/arm_svcall.c | 27 +- arch/arm/src/armv7-r/arm_cpupause.c | 12 +- arch/arm/src/armv7-r/arm_cpustart.c | 6 +- arch/arm/src/armv7-r/arm_doirq.c | 23 +- arch/arm/src/armv7-r/arm_schedulesigaction.c | 288 ++------------- arch/arm/src/armv7-r/arm_syscall.c | 16 +- arch/arm/src/armv8-m/arm_doirq.c | 11 +- arch/arm/src/armv8-m/arm_schedulesigaction.c | 321 +++-------------- arch/arm/src/armv8-m/arm_svcall.c | 25 +- arch/arm/src/armv8-r/arm_doirq.c | 19 +- arch/arm/src/armv8-r/arm_schedulesigaction.c | 302 ++-------------- arch/arm/src/armv8-r/arm_syscall.c | 15 +- arch/arm/src/common/arm_internal.h | 5 - arch/arm/src/common/arm_switchcontext.c | 12 - arch/arm/src/cxd56xx/cxd56_cpupause.c | 12 +- arch/arm/src/dm320/dm320_decodeirq.c | 7 +- arch/arm/src/imx1/imx_decodeirq.c | 6 +- arch/arm/src/lc823450/lc823450_cpupause.c | 12 +- arch/arm/src/lpc214x/lpc214x_decodeirq.c | 4 + arch/arm/src/lpc2378/lpc23xx_decodeirq.c | 4 + arch/arm/src/lpc31xx/lpc31_decodeirq.c | 8 +- arch/arm/src/moxart/moxart_irq.c | 2 + arch/arm/src/rp2040/rp2040_cpupause.c | 12 +- arch/arm/src/sam34/sam4cm_cpupause.c | 12 +- arch/arm/src/str71x/str71x_decodeirq.c | 4 + arch/arm/src/tlsr82/tc32/tc32_doirq.c | 13 +- .../src/tlsr82/tc32/tc32_schedulesigaction.c | 64 +--- 40 files changed, 404 insertions(+), 1973 deletions(-) diff --git a/arch/arm/src/arm/arm_doirq.c b/arch/arm/src/arm/arm_doirq.c index 9340eafb0277b..6cc7da46bdef2 100644 --- a/arch/arm/src/arm/arm_doirq.c +++ b/arch/arm/src/arm/arm_doirq.c @@ -58,6 +58,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) { + struct tcb_s *tcb = this_task(); + board_autoled_on(LED_INIRQ); #ifdef CONFIG_SUPPRESS_INTERRUPTS PANIC(); @@ -71,6 +73,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) */ up_set_current_regs(regs); + tcb->xcp.regs = regs; /* Acknowledge the interrupt */ @@ -79,6 +82,7 @@ uint32_t *arm_doirq(int irq, uint32_t *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 an @@ -87,7 +91,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) * returning from the interrupt. */ - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously @@ -104,9 +108,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) * crashes. */ - g_running_tasks[this_cpu()] = this_task(); + g_running_tasks[this_cpu()] = tcb; - regs = up_current_regs(); + regs = tcb->xcp.regs; } /* Set current_regs to NULL to indicate that we are no longer in an diff --git a/arch/arm/src/arm/arm_schedulesigaction.c b/arch/arm/src/arm/arm_schedulesigaction.c index d141a33a00aa7..a0a4017bf4235 100644 --- a/arch/arm/src/arm/arm_schedulesigaction.c +++ b/arch/arm/src/arm/arm_schedulesigaction.c @@ -89,70 +89,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * being delivered to the currently executing task. */ - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); + sinfo("rtcb=%p current_regs=%p\n", this_task(), + this_task()->xcp.regs); - if (tcb == this_task()) + if (tcb == this_task() && !up_interrupt_context()) { - /* CASE 1: We are not in an interrupt handler and - * a task is signalling itself for some reason. - */ - - if (!up_current_regs()) - { - /* In this case just deliver the signal now. */ - - 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 signalling itself, but - * a context switch to another task has occurred so that - * current_regs does not refer to the thread of this_task()! - */ - - else - { - /* Save the return lr and cpsr and one scratch register - * These will be restored by the signal trampoline after - * the signals have been delivered. - */ - - /* And make sure that the saved context in the TCB - * is the same as the interrupt return context. - */ - - arm_savestate(tcb->xcp.saved_regs); + /* In this case just deliver the signal now. */ - /* 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_SP] = (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)arm_sigdeliver; - up_current_regs()[REG_CPSR] = PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT; -#ifdef CONFIG_ARM_THUMB - up_current_regs()[REG_CPSR] |= PSR_T_BIT; -#endif - } + sigdeliver(tcb); + tcb->xcp.sigdeliver = NULL; } /* Otherwise, we are (1) signaling a task is not running diff --git a/arch/arm/src/arm/arm_syscall.c b/arch/arm/src/arm/arm_syscall.c index 867d33536c9ba..be95d916ffe3b 100644 --- a/arch/arm/src/arm/arm_syscall.c +++ b/arch/arm/src/arm/arm_syscall.c @@ -54,7 +54,7 @@ uint32_t *arm_syscall(uint32_t *regs) { - struct tcb_s *tcb; + struct tcb_s *tcb = this_task(); uint32_t cmd; int cpu; @@ -66,6 +66,7 @@ uint32_t *arm_syscall(uint32_t *regs) * current_regs is also used to manage interrupt level context switches. */ + tcb->xcp.regs = regs; up_set_current_regs(regs); /* The SYSCALL command is in R0 on entry. Parameters follow in R1..R7 */ @@ -94,7 +95,7 @@ uint32_t *arm_syscall(uint32_t *regs) * set will determine the restored context. */ - up_set_current_regs((uint32_t *)regs[REG_R1]); + tcb->xcp.regs = (uint32_t *)regs[REG_R1]; DEBUGASSERT(up_current_regs()); } break; @@ -133,15 +134,9 @@ uint32_t *arm_syscall(uint32_t *regs) break; } -#ifdef CONFIG_ARCH_ADDRENV - /* Check for a context switch. If a context switch occurred, then - * current_regs will have a different value than it did on entry. If an - * interrupt level context switch has occurred, then establish the correct - * address environment before returning from the interrupt. - */ - - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { +#ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, * MMU flushed) and set up the address environment for the new @@ -149,13 +144,8 @@ uint32_t *arm_syscall(uint32_t *regs) */ addrenv_switch(NULL); - } #endif - /* Restore the cpu lock */ - - if (regs != up_current_regs()) - { /* Record the new "running" task. g_running_tasks[] is only used by * assertion logic for reporting crashes. */ @@ -181,5 +171,5 @@ uint32_t *arm_syscall(uint32_t *regs) * SYS_context_switch system call. */ - return regs; + return tcb->xcp.regs; } diff --git a/arch/arm/src/armv6-m/arm_doirq.c b/arch/arm/src/armv6-m/arm_doirq.c index b5a7af4e226d7..566d9390a00e3 100644 --- a/arch/arm/src/armv6-m/arm_doirq.c +++ b/arch/arm/src/armv6-m/arm_doirq.c @@ -42,6 +42,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) { + struct tcb_s *tcb = this_task(); + board_autoled_on(LED_INIRQ); #ifdef CONFIG_SUPPRESS_INTERRUPTS PANIC(); @@ -49,6 +51,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE) { + tcb->xcp.regs = regs; up_set_current_regs(regs); } @@ -68,17 +71,17 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE) { - /* Restore the cpu lock */ + tcb = this_task(); - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* 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(); - regs = up_current_regs(); + g_running_tasks[this_cpu()] = tcb; + regs = tcb->xcp.regs; } /* Update the current_regs to NULL. */ diff --git a/arch/arm/src/armv6-m/arm_schedulesigaction.c b/arch/arm/src/armv6-m/arm_schedulesigaction.c index 3272dd4dc7502..4e5da4c5efd95 100644 --- a/arch/arm/src/armv6-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv6-m/arm_schedulesigaction.c @@ -78,7 +78,6 @@ * ****************************************************************************/ -#ifndef CONFIG_SMP void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) { sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); @@ -94,158 +93,20 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * to the currently executing task. */ - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); + sinfo("rtcb=%p current_regs=%p\n", this_task(), + this_task()->xcp.regs); - 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. + /* In this case just deliver the signal now. + * REVISIT: Signal handle will run in a critical section! */ - if (!up_current_regs()) - { - /* In this case just deliver the signal now. - * REVISIT: Signal handle 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. - */ - - else - { - /* Save the return PC, CPSR and PRIMASK - * registers (and perhaps also the LR). These will be - * restored by the signal trampoline after the signal has been - * delivered. - */ - - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() + - XCPTCONTEXT_REGS); - - /* Then set up to vector to the trampoline with interrupts - * disabled. The kernel-space trampoline must run in - * privileged thread mode. - */ - - up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver; - up_current_regs()[REG_PRIMASK] = 1; - up_current_regs()[REG_XPSR] = ARMV6M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - up_current_regs()[REG_LR] = EXC_RETURN_THREAD; - up_current_regs()[REG_EXC_RETURN] = EXC_RETURN_THREAD; - up_current_regs()[REG_CONTROL] = getcontrol() & - ~CONTROL_NPRIV; -#endif - } + 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 return PC, CPSR and PRIMASK - * registers (and perhaps also the LR). These will be restored - * by the signal trampoline after the signal has been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; - - /* Then set up to vector to the trampoline with interrupts - * disabled. We must already be in privileged thread mode to be - * here. - */ - - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; - tcb->xcp.regs[REG_PRIMASK] = 1; - tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; - tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; -#endif - } - } -} -#endif /* !CONFIG_SMP */ - -#ifdef CONFIG_SMP -void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) -{ - int cpu; - int me; - - 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()) - { - /* 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: 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 @@ -254,122 +115,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * 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. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; - - /* Then set up vector to the trampoline with interrupts - * disabled. We must already be in privileged thread mode - * to be here. - */ - - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; - tcb->xcp.regs[REG_PRIMASK] = 1; - tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; - tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; -#endif - } - else - { - /* tcb is running on the same CPU */ - - /* Save the return PC, CPSR and either the BASEPRI or - * PRIMASK registers (and perhaps also the LR). These - * will be restored by the signal trampoline after the - * signal has been delivered. - */ - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() - + XCPTCONTEXT_REGS); - - /* Then set up vector to the trampoline with interrupts - * disabled. The kernel-space trampoline must run in - * privileged thread mode. - */ - - up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver; - up_current_regs()[REG_PRIMASK] = 1; - up_current_regs()[REG_XPSR] = ARMV6M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - up_current_regs()[REG_LR] = EXC_RETURN_THREAD; - up_current_regs()[REG_CONTROL] = getcontrol() & - ~CONTROL_NPRIV; -#endif - } + /* If we signaling a task running on the other CPU, we have + * to PAUSE the other CPU. + */ - /* 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 - */ +#ifdef CONFIG_SMP + int cpu = tcb->cpu; + int me = this_cpu(); - /* RESUME the other CPU if it was PAUSED */ + if (cpu != me) + { + /* Pause the CPU */ - if (cpu != me) - { - up_cpu_resume(cpu); - } + up_cpu_pause(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. - */ +#endif - else - { /* Save the return PC, CPSR and either the BASEPRI or PRIMASK * registers (and perhaps also the LR). These will be restored * by the signal trampoline after the signal has been delivered. @@ -377,34 +138,43 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) /* Save the current register context location */ - tcb->xcp.saved_regs = tcb->xcp.regs; + 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); + 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs + + XCPTCONTEXT_SIZE; /* Then set up to vector to the trampoline with interrupts * disabled. We must already be in privileged thread mode to be * here. */ - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; - tcb->xcp.regs[REG_PRIMASK] = 1; - tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T; + tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; + tcb->xcp.regs[REG_PRIMASK] = 1; + tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; - tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; + tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; + tcb->xcp.regs[REG_EXC_RETURN] = EXC_RETURN_THREAD; + tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; +#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/arm/src/armv6-m/arm_svcall.c b/arch/arm/src/armv6-m/arm_svcall.c index 408a40c2495fd..62f57e302a47d 100644 --- a/arch/arm/src/armv6-m/arm_svcall.c +++ b/arch/arm/src/armv6-m/arm_svcall.c @@ -117,6 +117,7 @@ static void dispatch_syscall(void) int arm_svcall(int irq, void *context, void *arg) { + struct tcb_s *tcb = this_task(); uint32_t *regs = (uint32_t *)context; uint32_t cmd; @@ -167,7 +168,7 @@ int arm_svcall(int irq, void *context, void *arg) case SYS_restore_context: { DEBUGASSERT(regs[REG_R1] != 0); - up_set_current_regs((uint32_t *)regs[REG_R1]); + tcb->xcp.regs = (uint32_t *)regs[REG_R1]; } break; @@ -192,7 +193,7 @@ int arm_svcall(int irq, void *context, void *arg) { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); *(uint32_t **)regs[REG_R1] = regs; - up_set_current_regs((uint32_t *)regs[REG_R2]); + tcb->xcp.regs = (uint32_t *)regs[REG_R2]; } break; @@ -450,23 +451,20 @@ int arm_svcall(int irq, void *context, void *arg) # ifndef CONFIG_DEBUG_SVCALL if (cmd > SYS_switch_context) # else - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) # endif { + regs = (uint32_t *)tcb->xcp.regs; + svcinfo("SVCall Return:\n"); svcinfo(" R0: %08x %08x %08x %08x %08x %08x %08x %08x\n", - up_current_regs()[REG_R0], up_current_regs()[REG_R1], - up_current_regs()[REG_R2], up_current_regs()[REG_R3], - up_current_regs()[REG_R4], up_current_regs()[REG_R5], - up_current_regs()[REG_R6], up_current_regs()[REG_R7]); + regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3], + regs[REG_R4], regs[REG_R5], regs[REG_R6], regs[REG_R7]); svcinfo(" R8: %08x %08x %08x %08x %08x %08x %08x %08x\n", - up_current_regs()[REG_R8], up_current_regs()[REG_R9], - up_current_regs()[REG_R10], up_current_regs()[REG_R11], - up_current_regs()[REG_R12], up_current_regs()[REG_R13], - up_current_regs()[REG_R14], up_current_regs()[REG_R15]); - svcinfo(" PSR: %08x PRIMASK: %08x EXC_RETURN: %08x\n", - up_current_regs()[REG_XPSR], up_current_regs()[REG_PRIMASK], - up_current_regs()[REG_EXC_RETURN]); + regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11], + regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]); + svcinfo(" PSR: %08x EXC_RETURN: %08x CONTROL: %08x\n", + regs[REG_XPSR], regs[REG_EXC_RETURN], regs[REG_CONTROL]); } # ifdef CONFIG_DEBUG_SVCALL else diff --git a/arch/arm/src/armv7-a/arm_cpupause.c b/arch/arm/src/armv7-a/arm_cpupause.c index 7077d905a31ac..b36c6de7aa2b9 100644 --- a/arch/arm/src/armv7-a/arm_cpupause.c +++ b/arch/arm/src/armv7-a/arm_cpupause.c @@ -117,11 +117,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. - */ - - arm_savestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } @@ -207,11 +203,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. - */ - - arm_restorestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } diff --git a/arch/arm/src/armv7-a/arm_cpustart.c b/arch/arm/src/armv7-a/arm_cpustart.c index 6e04f872db146..e358d54b01f8a 100644 --- a/arch/arm/src/armv7-a/arm_cpustart.c +++ b/arch/arm/src/armv7-a/arm_cpustart.c @@ -79,18 +79,8 @@ int arm_start_handler(int irq, void *context, void *arg) nxsched_resume_scheduler(tcb); - /* Dump registers so that we can see what is going to happen on return */ + UNUSED(tcb); -#if 0 - up_dump_register(tcb->xcp.regs); -#endif - - /* Then switch contexts. This instantiates the exception context of the - * tcb at the head of the assigned task list. In this case, this should - * be the CPUs NULL task. - */ - - arm_restorestate(tcb->xcp.regs); return OK; } diff --git a/arch/arm/src/armv7-a/arm_doirq.c b/arch/arm/src/armv7-a/arm_doirq.c index cb68f8b55a453..460bb9a6c478a 100644 --- a/arch/arm/src/armv7-a/arm_doirq.c +++ b/arch/arm/src/armv7-a/arm_doirq.c @@ -53,6 +53,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) { + struct tcb_s *tcb = this_task(); + board_autoled_on(LED_INIRQ); #ifdef CONFIG_SUPPRESS_INTERRUPTS PANIC(); @@ -61,6 +63,18 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) DEBUGASSERT(up_current_regs() == NULL); + /* if irq == GIC_SMP_CPUSTART + * We are initiating the multi-core jumping state to up_idle, + * and we will use this_task(). Therefore, it cannot be overridden. + */ + +#ifdef CONFIG_SMP + if (irq != GIC_SMP_CPUSTART) +#endif + { + tcb->xcp.regs = regs; + } + /* Current regs non-zero indicates that we are processing an interrupt; * current_regs is also used to manage interrupt level context switches. */ @@ -70,10 +84,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) /* Deliver the IRQ */ irq_dispatch(irq, regs); + tcb = this_task(); - /* Restore the cpu lock */ - - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously @@ -90,8 +103,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) * crashes. */ - g_running_tasks[this_cpu()] = this_task(); - 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/arm/src/armv7-a/arm_schedulesigaction.c b/arch/arm/src/armv7-a/arm_schedulesigaction.c index b49534c4c6cc1..187af9b18ba63 100644 --- a/arch/arm/src/armv7-a/arm_schedulesigaction.c +++ b/arch/arm/src/armv7-a/arm_schedulesigaction.c @@ -77,7 +77,6 @@ * ****************************************************************************/ -#ifndef CONFIG_SMP void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) { sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); @@ -92,157 +91,20 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * to task that is currently executing on this CPU. */ - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); + sinfo("rtcb=%p current_regs=%p\n", this_task(), + this_task()->xcp.regs); - 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. + /* In this case just deliver the signal now. + * REVISIT: Signal handler will run in a critical section! */ - 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()! - */ - - else - { - /* Save the return lr and cpsr and one scratch register - * These will be restored by the signal trampoline after - * the signals have been delivered. - */ - - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_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_SP] = (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)arm_sigdeliver; - up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - up_current_regs()[REG_CPSR] |= PSR_T_BIT; -#endif - } + 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 other non-running task. - */ - else { - /* Save the return lr and cpsr and one scratch register. These - * will be restored by the signal trampoline after the signals - * have been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (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)arm_sigdeliver; - tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; -#endif - } - } -} -#endif /* !CONFIG_SMP */ - -#ifdef CONFIG_SMP -void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) -{ - int cpu; - int me; - - 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()) - { - /* 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: 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 @@ -251,118 +113,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * 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. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (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)arm_sigdeliver; - tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; -#endif - } - else - { - /* tcb is running on the same CPU */ - - /* Save the return PC, CPSR and either the BASEPRI or - * PRIMASK registers (and perhaps also the LR). These will - * be restored by the signal trampoline after the signal - * has been delivered. - */ - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() - + XCPTCONTEXT_REGS); - - /* Then set up vector to the trampoline with interrupts - * disabled. The kernel-space trampoline must run in - * privileged thread mode. - */ - - up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver; - up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - up_current_regs()[REG_CPSR] |= PSR_T_BIT; -#endif - } + /* If we signaling a task running on the other CPU, we have + * to PAUSE the other CPU. + */ - /* 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 - */ +#ifdef CONFIG_SMP + int cpu = tcb->cpu; + int me = this_cpu(); - /* RESUME the other CPU if it was PAUSED */ + if (cpu != me) + { + /* Pause the CPU */ - if (cpu != me) - { - up_cpu_resume(cpu); - } + up_cpu_pause(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. - */ +#endif - else - { /* Save the return lr and cpsr and one scratch register. These * will be restored by the signal trampoline after the signals * have been delivered. @@ -394,7 +160,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_ARM_THUMB tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; #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/arm/src/armv7-a/arm_syscall.c b/arch/arm/src/armv7-a/arm_syscall.c index feca24da09f30..9a8df57bdd8dd 100644 --- a/arch/arm/src/armv7-a/arm_syscall.c +++ b/arch/arm/src/armv7-a/arm_syscall.c @@ -160,7 +160,7 @@ static void dispatch_syscall(void) uint32_t *arm_syscall(uint32_t *regs) { - struct tcb_s *tcb; + struct tcb_s *tcb = this_task(); uint32_t cmd; int cpu; #ifdef CONFIG_BUILD_KERNEL @@ -171,6 +171,8 @@ uint32_t *arm_syscall(uint32_t *regs) DEBUGASSERT(up_current_regs() == NULL); + tcb->xcp.regs = regs; + /* Current regs non-zero indicates that we are processing an interrupt; * current_regs is also used to manage interrupt level context switches. */ @@ -272,7 +274,7 @@ uint32_t *arm_syscall(uint32_t *regs) * set will determine the restored context. */ - up_set_current_regs((uint32_t *)regs[REG_R1]); + tcb->xcp.regs = (uint32_t *)regs[REG_R1]; DEBUGASSERT(up_current_regs()); } break; @@ -298,7 +300,7 @@ uint32_t *arm_syscall(uint32_t *regs) { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); *(uint32_t **)regs[REG_R1] = regs; - up_set_current_regs((uint32_t *)regs[REG_R2]); + tcb->xcp.regs = (uint32_t *)regs[REG_R2]; } break; @@ -565,15 +567,9 @@ uint32_t *arm_syscall(uint32_t *regs) break; } -#ifdef CONFIG_ARCH_ADDRENV - /* Check for a context switch. If a context switch occurred, then - * current_regs will have a different value than it did on entry. If an - * interrupt level context switch has occurred, then establish the correct - * address environment before returning from the interrupt. - */ - - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { +#ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, * MMU flushed) and set up the address environment for the new @@ -581,13 +577,8 @@ uint32_t *arm_syscall(uint32_t *regs) */ addrenv_switch(NULL); - } #endif - /* Restore the cpu lock */ - - if (regs != up_current_regs()) - { /* Record the new "running" task. g_running_tasks[] is only used by * assertion logic for reporting crashes. */ @@ -599,7 +590,7 @@ uint32_t *arm_syscall(uint32_t *regs) /* Restore the cpu lock */ restore_critical_section(tcb, cpu); - regs = up_current_regs(); + regs = tcb->xcp.regs; } /* Report what happened */ diff --git a/arch/arm/src/armv7-m/arm_doirq.c b/arch/arm/src/armv7-m/arm_doirq.c index 66af948ef3436..c1370659c9e74 100644 --- a/arch/arm/src/armv7-m/arm_doirq.c +++ b/arch/arm/src/armv7-m/arm_doirq.c @@ -42,6 +42,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) { + struct tcb_s *tcb = this_task(); + board_autoled_on(LED_INIRQ); #ifdef CONFIG_SUPPRESS_INTERRUPTS PANIC(); @@ -49,6 +51,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE) { + tcb->xcp.regs = regs; up_set_current_regs(regs); } @@ -68,17 +71,17 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE) { - /* Restore the cpu lock */ + tcb = this_task(); - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* 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(); - regs = up_current_regs(); + g_running_tasks[this_cpu()] = tcb; + regs = tcb->xcp.regs; } /* Update the current_regs to NULL. */ diff --git a/arch/arm/src/armv7-m/arm_schedulesigaction.c b/arch/arm/src/armv7-m/arm_schedulesigaction.c index 1aea1dd908ea7..531e295bbd84d 100644 --- a/arch/arm/src/armv7-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv7-m/arm_schedulesigaction.c @@ -79,7 +79,6 @@ * ****************************************************************************/ -#ifndef CONFIG_SMP void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) { sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); @@ -95,167 +94,20 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * to the currently executing task. */ - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); + sinfo("rtcb=%p current_regs=%p\n", this_task(), + this_task()->xcp.regs); - 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. + /* In this case just deliver the signal now. + * REVISIT: Signal handle will run in a critical section! */ - if (!up_current_regs()) - { - /* In this case just deliver the signal now. - * REVISIT: Signal handle 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. - */ - - else - { - /* Save the return PC, CPSR and either the BASEPRI or PRIMASK - * registers (and perhaps also the LR). These will be - * restored by the signal trampoline after the signal has been - * delivered. - */ - - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() + - XCPTCONTEXT_REGS); - - /* Then set up to vector to the trampoline with interrupts - * disabled. The kernel-space trampoline must run in - * privileged thread mode. - */ - - up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver; -#ifdef CONFIG_ARMV7M_USEBASEPRI - up_current_regs()[REG_BASEPRI] = - NVIC_SYSH_DISABLE_PRIORITY; -#else - up_current_regs()[REG_PRIMASK] = 1; -#endif - up_current_regs()[REG_XPSR] = ARMV7M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - up_current_regs()[REG_LR] = EXC_RETURN_THREAD; - up_current_regs()[REG_EXC_RETURN] = EXC_RETURN_THREAD; - up_current_regs()[REG_CONTROL] = getcontrol() & - ~CONTROL_NPRIV; -#endif - } + 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 return PC, CPSR and either the BASEPRI or PRIMASK - * registers (and perhaps also the LR). These will be restored - * by the signal trampoline after the signal has been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; - - /* Then set up to vector to the trampoline with interrupts - * disabled. We must already be in privileged thread mode to be - * here. - */ - - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; -#ifdef CONFIG_ARMV7M_USEBASEPRI - tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY; -#else - tcb->xcp.regs[REG_PRIMASK] = 1; -#endif - tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; - tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; -#endif - } - } -} -#endif /* !CONFIG_SMP */ - -#ifdef CONFIG_SMP -void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) -{ - int cpu; - int me; - - 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()) - { - /* 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: 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 @@ -264,131 +116,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * 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. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; - - /* Then set up vector to the trampoline with interrupts - * disabled. We must already be in privileged thread mode - * to be here. - */ - - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; -#ifdef CONFIG_ARMV7M_USEBASEPRI - tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY; -#else - tcb->xcp.regs[REG_PRIMASK] = 1; -#endif - tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; - tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; -#endif - } - else - { - /* tcb is running on the same CPU */ - - /* Save the return PC, CPSR and either the BASEPRI or - * PRIMASK registers (and perhaps also the LR). These - * will be restored by the signal trampoline after the - * signal has been delivered. - */ - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() - + XCPTCONTEXT_REGS); - - /* Then set up vector to the trampoline with interrupts - * disabled. The kernel-space trampoline must run in - * privileged thread mode. - */ - - up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver; -#ifdef CONFIG_ARMV7M_USEBASEPRI - up_current_regs()[REG_BASEPRI] = - NVIC_SYSH_DISABLE_PRIORITY; -#else - up_current_regs()[REG_PRIMASK] = 1; -#endif - up_current_regs()[REG_XPSR] = ARMV7M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - up_current_regs()[REG_LR] = EXC_RETURN_THREAD; - up_current_regs()[REG_CONTROL] = getcontrol() & - ~CONTROL_NPRIV; -#endif - } + /* If we signaling a task running on the other CPU, we have + * to PAUSE the other CPU. + */ - /* 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 - */ +#ifdef CONFIG_SMP + int cpu = tcb->cpu; + int me = this_cpu(); - /* RESUME the other CPU if it was PAUSED */ + if (cpu != me) + { + /* Pause the CPU */ - if (cpu != me) - { - up_cpu_resume(cpu); - } + up_cpu_pause(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. - */ +#endif - else - { /* Save the return PC, CPSR and either the BASEPRI or PRIMASK * registers (and perhaps also the LR). These will be restored * by the signal trampoline after the signal has been delivered. @@ -396,38 +139,47 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) /* Save the current register context location */ - tcb->xcp.saved_regs = tcb->xcp.regs; + 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); + 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs + + XCPTCONTEXT_SIZE; /* Then set up to vector to the trampoline with interrupts * disabled. We must already be in privileged thread mode to be * here. */ - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; + tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; #ifdef CONFIG_ARMV7M_USEBASEPRI - tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY; + tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY; #else - tcb->xcp.regs[REG_PRIMASK] = 1; + tcb->xcp.regs[REG_PRIMASK] = 1; #endif - tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T; + tcb->xcp.regs[REG_XPSR] = ARMV7M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; - tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; + tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; + tcb->xcp.regs[REG_EXC_RETURN] = EXC_RETURN_THREAD; + tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; +#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/arm/src/armv7-m/arm_svcall.c b/arch/arm/src/armv7-m/arm_svcall.c index a025681c53238..6c6f507aeca1b 100644 --- a/arch/arm/src/armv7-m/arm_svcall.c +++ b/arch/arm/src/armv7-m/arm_svcall.c @@ -125,6 +125,7 @@ static void dispatch_syscall(void) int arm_svcall(int irq, void *context, void *arg) { + struct tcb_s *tcb = this_task(); uint32_t *regs = (uint32_t *)context; uint32_t cmd; @@ -176,7 +177,7 @@ int arm_svcall(int irq, void *context, void *arg) case SYS_restore_context: { DEBUGASSERT(regs[REG_R1] != 0); - up_set_current_regs((uint32_t *)regs[REG_R1]); + tcb->xcp.regs = (uint32_t *)regs[REG_R1]; } break; @@ -201,7 +202,7 @@ int arm_svcall(int irq, void *context, void *arg) { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); *(uint32_t **)regs[REG_R1] = regs; - up_set_current_regs((uint32_t *)regs[REG_R2]); + tcb->xcp.regs = (uint32_t *)regs[REG_R2]; } break; @@ -459,24 +460,20 @@ int arm_svcall(int irq, void *context, void *arg) # ifndef CONFIG_DEBUG_SVCALL if (cmd > SYS_switch_context) # else - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) # endif { + regs = (uint32_t *)tcb->xcp.regs; + svcinfo("SVCall Return:\n"); svcinfo(" R0: %08x %08x %08x %08x %08x %08x %08x %08x\n", - up_current_regs()[REG_R0], up_current_regs()[REG_R1], - up_current_regs()[REG_R2], up_current_regs()[REG_R3], - up_current_regs()[REG_R4], up_current_regs()[REG_R5], - up_current_regs()[REG_R6], up_current_regs()[REG_R7]); + regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3], + regs[REG_R4], regs[REG_R5], regs[REG_R6], regs[REG_R7]); svcinfo(" R8: %08x %08x %08x %08x %08x %08x %08x %08x\n", - up_current_regs()[REG_R8], up_current_regs()[REG_R9], - up_current_regs()[REG_R10], up_current_regs()[REG_R11], - up_current_regs()[REG_R12], up_current_regs()[REG_R13], - up_current_regs()[REG_R14], up_current_regs()[REG_R15]); - svcinfo(" PSR: %08x EXC_RETURN: %08x, CONTROL: %08x\n", - up_current_regs()[REG_XPSR], - up_current_regs()[REG_EXC_RETURN], - up_current_regs()[REG_CONTROL]); + regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11], + regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]); + svcinfo(" PSR: %08x EXC_RETURN: %08x CONTROL: %08x\n", + regs[REG_XPSR], regs[REG_EXC_RETURN], regs[REG_CONTROL]); } # ifdef CONFIG_DEBUG_SVCALL else diff --git a/arch/arm/src/armv7-r/arm_cpupause.c b/arch/arm/src/armv7-r/arm_cpupause.c index b51b98e539091..a466d963eba99 100644 --- a/arch/arm/src/armv7-r/arm_cpupause.c +++ b/arch/arm/src/armv7-r/arm_cpupause.c @@ -117,11 +117,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. - */ - - arm_savestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } @@ -207,11 +203,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. - */ - - arm_restorestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } diff --git a/arch/arm/src/armv7-r/arm_cpustart.c b/arch/arm/src/armv7-r/arm_cpustart.c index fe93836e5b5de..15d0ec1ac0ad3 100644 --- a/arch/arm/src/armv7-r/arm_cpustart.c +++ b/arch/arm/src/armv7-r/arm_cpustart.c @@ -79,12 +79,8 @@ int arm_start_handler(int irq, void *context, void *arg) nxsched_resume_scheduler(tcb); - /* Then switch contexts. This instantiates the exception context of the - * tcb at the head of the assigned task list. In this case, this should - * be the CPUs NULL task. - */ + UNUSED(tcb); - arm_restorestate(tcb->xcp.regs); return OK; } diff --git a/arch/arm/src/armv7-r/arm_doirq.c b/arch/arm/src/armv7-r/arm_doirq.c index 61adb183b662d..7b08a7dd56326 100644 --- a/arch/arm/src/armv7-r/arm_doirq.c +++ b/arch/arm/src/armv7-r/arm_doirq.c @@ -41,6 +41,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) { + struct tcb_s *tcb = this_task(); + board_autoled_on(LED_INIRQ); #ifdef CONFIG_SUPPRESS_INTERRUPTS @@ -50,6 +52,18 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) DEBUGASSERT(up_current_regs() == NULL); + /* if irq == GIC_SMP_CPUSTART + * We are initiating the multi-core jumping state to up_idle, + * and we will use this_task(). Therefore, it cannot be overridden. + */ + +#ifdef CONFIG_SMP + if (irq != GIC_SMP_CPUSTART) +#endif + { + tcb->xcp.regs = regs; + } + /* Current regs non-zero indicates that we are processing an interrupt; * current_regs is also used to manage interrupt level context switches. */ @@ -59,18 +73,17 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) /* Deliver the IRQ */ irq_dispatch(irq, regs); + tcb = this_task(); - /* Restore the cpu lock */ - - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* 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(); - 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/arm/src/armv7-r/arm_schedulesigaction.c b/arch/arm/src/armv7-r/arm_schedulesigaction.c index e24fc8de3bd71..b21a0c9188d59 100644 --- a/arch/arm/src/armv7-r/arm_schedulesigaction.c +++ b/arch/arm/src/armv7-r/arm_schedulesigaction.c @@ -75,7 +75,6 @@ * ****************************************************************************/ -#ifndef CONFIG_SMP void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) { sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); @@ -87,284 +86,39 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.sigdeliver = sigdeliver; /* 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. */ - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); + sinfo("rtcb=%p current_regs=%p\n", this_task(), + this_task()->xcp.regs); - if (tcb == this_task()) + if (tcb == this_task() && !up_interrupt_context()) { - /* CASE 1: We are not in an interrupt handler and a task is - * signalling itself for some reason. - */ - - if (!up_current_regs()) - { - /* In this case just deliver the signal now. */ - - 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 signalling 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 return lr and cpsr and one scratch register - * These will be restored by the signal trampoline after - * the signals have been delivered. - */ - - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_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_SP] = (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)arm_sigdeliver; - up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - up_current_regs()[REG_CPSR] |= PSR_T_BIT; -#endif - -#ifdef CONFIG_ENDIAN_BIG - up_current_regs()[REG_CPSR] |= PSR_E_BIT; -#endif - } + 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 signalling some non-running task. - */ - else { - /* Save the return lr and cpsr and one scratch register. These - * will be restored by the signal trampoline after the signals - * have been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; - - /* Then set up to vector to the trampoline with interrupts - * disabled + /* If we signaling a task running on the other CPU, we have + * to PAUSE the other CPU. */ - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; - tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; -#endif - -#ifdef CONFIG_ENDIAN_BIG - tcb->xcp.regs[REG_CPSR] |= PSR_E_BIT; -#endif - } - } -} -#else -void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) -{ - int cpu; - int me; - - 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; +#ifdef CONFIG_SMP + int cpu = tcb->cpu; + int me = this_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. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (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)arm_sigdeliver; - tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; -#endif - } - else - { - /* tcb is running on the same CPU */ - - /* Save the return PC, CPSR and either the BASEPRI or - * PRIMASK registers (and perhaps also the LR). These will - * be restored by the signal trampoline after the signal - * has been delivered. - */ - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() - + XCPTCONTEXT_REGS); - - /* Then set up vector to the trampoline with interrupts - * disabled. The kernel-space trampoline must run in - * privileged thread mode. - */ - - up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver; - up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - up_current_regs()[REG_CPSR] |= PSR_T_BIT; #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 return lr and cpsr and one scratch register. These * will be restored by the signal trampoline after the signals * have been delivered. @@ -396,7 +150,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_ARM_THUMB tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; #endif + +#ifdef CONFIG_SMP + /* RESUME the other CPU if it was PAUSED */ + + if (cpu != me) + { + up_cpu_resume(cpu); + } +#endif } } } -#endif diff --git a/arch/arm/src/armv7-r/arm_syscall.c b/arch/arm/src/armv7-r/arm_syscall.c index f1e149e74947f..66d2181618478 100644 --- a/arch/arm/src/armv7-r/arm_syscall.c +++ b/arch/arm/src/armv7-r/arm_syscall.c @@ -156,7 +156,8 @@ static void dispatch_syscall(void) uint32_t *arm_syscall(uint32_t *regs) { - struct tcb_s *tcb; + struct tcb_s *tcb = this_task(); + uint32_t cmd; int cpu; #ifdef CONFIG_BUILD_PROTECTED @@ -167,6 +168,8 @@ uint32_t *arm_syscall(uint32_t *regs) DEBUGASSERT(up_current_regs() == NULL); + tcb->xcp.regs = regs; + /* Current regs non-zero indicates that we are processing an interrupt; * current_regs is also used to manage interrupt level context switches. */ @@ -268,7 +271,7 @@ uint32_t *arm_syscall(uint32_t *regs) * set will determine the restored context. */ - up_set_current_regs((uint32_t *)regs[REG_R1]); + tcb->xcp.regs = (uint32_t *)regs[REG_R1]; DEBUGASSERT(up_current_regs()); } break; @@ -294,7 +297,7 @@ uint32_t *arm_syscall(uint32_t *regs) { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); *(uint32_t **)regs[REG_R1] = regs; - up_set_current_regs((uint32_t *)regs[REG_R2]); + tcb->xcp.regs = (uint32_t *)regs[REG_R2]; } break; @@ -561,22 +564,19 @@ uint32_t *arm_syscall(uint32_t *regs) break; } - /* Restore the cpu lock */ - - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* 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 */ restore_critical_section(tcb, cpu); - regs = up_current_regs(); + regs = tcb->xcp.regs; } /* Report what happened */ diff --git a/arch/arm/src/armv8-m/arm_doirq.c b/arch/arm/src/armv8-m/arm_doirq.c index 198261961d0af..e35cbb0eef8cc 100644 --- a/arch/arm/src/armv8-m/arm_doirq.c +++ b/arch/arm/src/armv8-m/arm_doirq.c @@ -91,6 +91,8 @@ static inline bool arm_from_thread(uint32_t excret) uint32_t *arm_doirq(int irq, uint32_t *regs) { + struct tcb_s *tcb = this_task(); + board_autoled_on(LED_INIRQ); #ifdef CONFIG_SUPPRESS_INTERRUPTS PANIC(); @@ -98,6 +100,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (arm_from_thread(regs[REG_EXC_RETURN])) { + tcb->xcp.regs = regs; up_set_current_regs(regs); } @@ -117,17 +120,17 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (arm_from_thread(regs[REG_EXC_RETURN])) { - /* Restore the cpu lock */ + tcb = this_task(); - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* 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(); - regs = up_current_regs(); + g_running_tasks[this_cpu()] = tcb; + regs = tcb->xcp.regs; } /* Update the current_regs to NULL. */ diff --git a/arch/arm/src/armv8-m/arm_schedulesigaction.c b/arch/arm/src/armv8-m/arm_schedulesigaction.c index f96309538e8d2..42b0ccfb06445 100644 --- a/arch/arm/src/armv8-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv8-m/arm_schedulesigaction.c @@ -79,7 +79,6 @@ * ****************************************************************************/ -#ifndef CONFIG_SMP void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) { sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); @@ -95,167 +94,20 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * to the currently executing task. */ - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); + sinfo("rtcb=%p current_regs=%p\n", this_task(), + this_task()->xcp.regs); - 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. + /* In this case just deliver the signal now. + * REVISIT: Signal handle will run in a critical section! */ - if (!up_current_regs()) - { - /* In this case just deliver the signal now. - * REVISIT: Signal handle 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. - */ - - else - { - /* Save the return PC, CPSR and either the BASEPRI or PRIMASK - * registers (and perhaps also the LR). These will be - * restored by the signal trampoline after the signal has been - * delivered. - */ - - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() + - XCPTCONTEXT_REGS); - - /* Then set up to vector to the trampoline with interrupts - * disabled. The kernel-space trampoline must run in - * privileged thread mode. - */ - - up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver; -#ifdef CONFIG_ARMV8M_USEBASEPRI - up_current_regs()[REG_BASEPRI] = - NVIC_SYSH_DISABLE_PRIORITY; -#else - up_current_regs()[REG_PRIMASK] = 1; -#endif - up_current_regs()[REG_XPSR] = ARMV8M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - up_current_regs()[REG_LR] = EXC_RETURN_THREAD; - up_current_regs()[REG_EXC_RETURN] = EXC_RETURN_THREAD; - up_current_regs()[REG_CONTROL] = getcontrol() & - ~CONTROL_NPRIV; -#endif - } + 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 return PC, CPSR and either the BASEPRI or PRIMASK - * registers (and perhaps also the LR). These will be restored - * by the signal trampoline after the signal has been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; - - /* Then set up to vector to the trampoline with interrupts - * disabled. We must already be in privileged thread mode to be - * here. - */ - - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; -#ifdef CONFIG_ARMV8M_USEBASEPRI - tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY; -#else - tcb->xcp.regs[REG_PRIMASK] = 1; -#endif - tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; - tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; -#endif - } - } -} -#endif /* !CONFIG_SMP */ - -#ifdef CONFIG_SMP -void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) -{ - int cpu; - int me; - - 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()) - { - /* 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: 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 @@ -264,124 +116,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * 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. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; - - /* Then set up vector to the trampoline with interrupts - * disabled. We must already be in privileged thread mode - * to be here. - */ - - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; -#ifdef CONFIG_ARMV8M_USEBASEPRI - tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY; -#else - tcb->xcp.regs[REG_PRIMASK] = 1; -#endif - tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; - tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; -#endif - } - else - { - /* tcb is running on the same CPU */ - - /* Save the return PC, CPSR and either the BASEPRI or - * PRIMASK registers (and perhaps also the LR). These - * will be restored by the signal trampoline after the - * signal has been delivered. - */ - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() - + XCPTCONTEXT_REGS); - - /* Then set up vector to the trampoline with interrupts - * disabled. The kernel-space trampoline must run in - * privileged thread mode. - */ + /* If we signaling a task running on the other CPU, we have + * to PAUSE the other CPU. + */ - up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver; -#ifdef CONFIG_ARMV8M_USEBASEPRI - up_current_regs()[REG_BASEPRI] = - NVIC_SYSH_DISABLE_PRIORITY; -#else - up_current_regs()[REG_PRIMASK] = 1; -#endif - up_current_regs()[REG_XPSR] = ARMV8M_XPSR_T; -#ifdef CONFIG_BUILD_PROTECTED - up_current_regs()[REG_LR] = EXC_RETURN_THREAD; - up_current_regs()[REG_CONTROL] = getcontrol() & - ~CONTROL_NPRIV; -#endif - } +#ifdef CONFIG_SMP + int cpu = tcb->cpu; + int me = this_cpu(); - /* RESUME the other CPU if it was PAUSED */ + if (cpu != me) + { + /* Pause the CPU */ - if (cpu != me) - { - up_cpu_resume(cpu); - } + up_cpu_pause(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. - */ +#endif - else - { /* Save the return PC, CPSR and either the BASEPRI or PRIMASK * registers (and perhaps also the LR). These will be restored * by the signal trampoline after the signal has been delivered. @@ -389,38 +139,47 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) /* Save the current register context location */ - tcb->xcp.saved_regs = tcb->xcp.regs; + 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); + 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_SP] = (uint32_t)tcb->xcp.regs + - XCPTCONTEXT_SIZE; + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs + + XCPTCONTEXT_SIZE; /* Then set up to vector to the trampoline with interrupts * disabled. We must already be in privileged thread mode to be * here. */ - tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; + tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; #ifdef CONFIG_ARMV8M_USEBASEPRI - tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY; + tcb->xcp.regs[REG_BASEPRI] = NVIC_SYSH_DISABLE_PRIORITY; #else - tcb->xcp.regs[REG_PRIMASK] = 1; + tcb->xcp.regs[REG_PRIMASK] = 1; #endif - tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; + tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; #ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; - tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; + tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD; + tcb->xcp.regs[REG_EXC_RETURN] = EXC_RETURN_THREAD; + tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; +#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/arm/src/armv8-m/arm_svcall.c b/arch/arm/src/armv8-m/arm_svcall.c index 9df396b6c4e94..aeb427322c07d 100644 --- a/arch/arm/src/armv8-m/arm_svcall.c +++ b/arch/arm/src/armv8-m/arm_svcall.c @@ -124,6 +124,7 @@ static void dispatch_syscall(void) int arm_svcall(int irq, void *context, void *arg) { + struct tcb_s *tcb = this_task(); uint32_t *regs = (uint32_t *)context; uint32_t cmd; @@ -175,7 +176,7 @@ int arm_svcall(int irq, void *context, void *arg) case SYS_restore_context: { DEBUGASSERT(regs[REG_R1] != 0); - up_set_current_regs((uint32_t *)regs[REG_R1]); + tcb->xcp.regs = (uint32_t *)regs[REG_R1]; } break; @@ -200,7 +201,7 @@ int arm_svcall(int irq, void *context, void *arg) { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); *(uint32_t **)regs[REG_R1] = regs; - up_set_current_regs((uint32_t *)regs[REG_R2]); + tcb->xcp.regs = (uint32_t *)regs[REG_R2]; } break; @@ -460,24 +461,20 @@ int arm_svcall(int irq, void *context, void *arg) # ifndef CONFIG_DEBUG_SVCALL if (cmd > SYS_switch_context) # else - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) # endif { + regs = (uint32_t *)tcb->xcp.regs; + svcinfo("SVCall Return:\n"); svcinfo(" R0: %08x %08x %08x %08x %08x %08x %08x %08x\n", - up_current_regs()[REG_R0], up_current_regs()[REG_R1], - up_current_regs()[REG_R2], up_current_regs()[REG_R3], - up_current_regs()[REG_R4], up_current_regs()[REG_R5], - up_current_regs()[REG_R6], up_current_regs()[REG_R7]); + regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3], + regs[REG_R4], regs[REG_R5], regs[REG_R6], regs[REG_R7]); svcinfo(" R8: %08x %08x %08x %08x %08x %08x %08x %08x\n", - up_current_regs()[REG_R8], up_current_regs()[REG_R9], - up_current_regs()[REG_R10], up_current_regs()[REG_R11], - up_current_regs()[REG_R12], up_current_regs()[REG_R13], - up_current_regs()[REG_R14], up_current_regs()[REG_R15]); + regs[REG_R8], regs[REG_R9], regs[REG_R10], regs[REG_R11], + regs[REG_R12], regs[REG_R13], regs[REG_R14], regs[REG_R15]); svcinfo(" PSR: %08x EXC_RETURN: %08x CONTROL: %08x\n", - up_current_regs()[REG_XPSR], - up_current_regs()[REG_EXC_RETURN], - up_current_regs()[REG_CONTROL]); + regs[REG_XPSR], regs[REG_EXC_RETURN], regs[REG_CONTROL]); } # ifdef CONFIG_DEBUG_SVCALL else diff --git a/arch/arm/src/armv8-r/arm_doirq.c b/arch/arm/src/armv8-r/arm_doirq.c index 982795fe1397f..2863292052b90 100644 --- a/arch/arm/src/armv8-r/arm_doirq.c +++ b/arch/arm/src/armv8-r/arm_doirq.c @@ -42,6 +42,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) { + struct tcb_s *tcb = this_task(); + board_autoled_on(LED_INIRQ); #ifdef CONFIG_SUPPRESS_INTERRUPTS @@ -51,6 +53,16 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) DEBUGASSERT(up_current_regs() == NULL); + /* if irq == GIC_SMP_CPUSTART + * We are initiating the multi-core jumping state to up_idle, + * and we will use this_task(). Therefore, it cannot be overridden. + */ + + if (irq != GIC_SMP_CPUSTART) + { + tcb->xcp.regs = regs; + } + /* Current regs non-zero indicates that we are processing an interrupt; * current_regs is also used to manage interrupt level context switches. */ @@ -60,10 +72,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) /* Deliver the IRQ */ irq_dispatch(irq, regs); + tcb = this_task(); - /* Restore the cpu lock */ - - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* Record the new "running" task when context switch occurred. * g_running_tasks[] is only used by assertion logic for reporting @@ -71,7 +82,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) */ g_running_tasks[this_cpu()] = this_task(); - regs = up_current_regs(); + regs = tcb->xcp.regs; } /* Set current_regs to NULL to indicate that we are no longer in an diff --git a/arch/arm/src/armv8-r/arm_schedulesigaction.c b/arch/arm/src/armv8-r/arm_schedulesigaction.c index 400dbc339d287..1ceba997f7f34 100644 --- a/arch/arm/src/armv8-r/arm_schedulesigaction.c +++ b/arch/arm/src/armv8-r/arm_schedulesigaction.c @@ -75,7 +75,6 @@ * ****************************************************************************/ -#ifndef CONFIG_SMP void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) { sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); @@ -87,291 +86,39 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.sigdeliver = sigdeliver; /* 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. */ - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); + sinfo("rtcb=%p current_regs=%p\n", this_task(), + this_task()->xcp.regs); - if (tcb == this_task()) + if (tcb == this_task() && !up_interrupt_context()) { - /* CASE 1: We are not in an interrupt handler and a task is - * signalling itself for some reason. - */ - - if (!up_current_regs()) - { - /* In this case just deliver the signal now. */ - - 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 signalling 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 return lr and cpsr and one scratch register - * These will be restored by the signal trampoline after - * the signals have been delivered. - */ - - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_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_SP] = (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)arm_sigdeliver; - up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - up_current_regs()[REG_CPSR] |= PSR_T_BIT; -#endif - -#ifdef CONFIG_ENDIAN_BIG - up_current_regs()[REG_CPSR] |= PSR_E_BIT; -#endif - } + 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 signalling some non-running task. - */ - else { - /* Save the return lr and cpsr and one scratch register. These - * will be restored by the signal trampoline after the signals - * have been delivered. + /* If we signaling a task running on the other CPU, we have + * to PAUSE the other CPU. */ - /* Save the current register context location */ - - tcb->xcp.saved_regs = tcb->xcp.regs; +#ifdef CONFIG_SMP + int cpu = tcb->cpu; + int me = this_cpu(); - /* 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_SP] = (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)arm_sigdeliver; - tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; -#endif - -#ifdef CONFIG_ENDIAN_BIG - tcb->xcp.regs[REG_CPSR] |= PSR_E_BIT; -#endif - } - } -} -#else -void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) -{ - int cpu; - int me; - - 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. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - - /* Save the current register context location */ - - 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_SP] = (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)arm_sigdeliver; - tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; -#endif - } - else - { - /* tcb is running on the same CPU */ - - /* Save the return PC, CPSR and either the BASEPRI or - * PRIMASK registers (and perhaps also the LR). These will - * be restored by the signal trampoline after the signal - * has been delivered. - */ - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() - + XCPTCONTEXT_REGS); - - /* Then set up vector to the trampoline with interrupts - * disabled. The kernel-space trampoline must run in - * privileged thread mode. - */ - - up_current_regs()[REG_PC] = (uint32_t)arm_sigdeliver; - up_current_regs()[REG_CPSR] = (PSR_MODE_SYS | PSR_I_BIT | - PSR_F_BIT); -#ifdef CONFIG_ARM_THUMB - up_current_regs()[REG_CPSR] |= PSR_T_BIT; #endif - } - - /* Increment the IRQ lock count so that when the task is - * restarted, it will hold the IRQ spinlock. - */ - - DEBUGASSERT(tcb->irqcount < INT16_MAX); - tcb->irqcount++; - - /* 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 return lr and cpsr and one scratch register. These * will be restored by the signal trampoline after the signals * have been delivered. @@ -394,13 +141,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs + XCPTCONTEXT_SIZE; - /* Increment the IRQ lock count so that when the task is restarted, - * it will hold the IRQ spinlock. - */ - - DEBUGASSERT(tcb->irqcount < INT16_MAX); - tcb->irqcount++; - /* Then set up to vector to the trampoline with interrupts * disabled */ @@ -410,7 +150,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_ARM_THUMB tcb->xcp.regs[REG_CPSR] |= PSR_T_BIT; #endif + +#ifdef CONFIG_SMP + /* RESUME the other CPU if it was PAUSED */ + + if (cpu != me) + { + up_cpu_resume(cpu); + } +#endif } } } -#endif diff --git a/arch/arm/src/armv8-r/arm_syscall.c b/arch/arm/src/armv8-r/arm_syscall.c index ffc57ee1f22a9..1f82dc20e7b02 100644 --- a/arch/arm/src/armv8-r/arm_syscall.c +++ b/arch/arm/src/armv8-r/arm_syscall.c @@ -156,7 +156,7 @@ static void dispatch_syscall(void) uint32_t *arm_syscall(uint32_t *regs) { - struct tcb_s *tcb; + struct tcb_s *tcb = this_task(); uint32_t cmd; int cpu; #ifdef CONFIG_BUILD_PROTECTED @@ -167,6 +167,8 @@ uint32_t *arm_syscall(uint32_t *regs) DEBUGASSERT(up_current_regs() == NULL); + tcb->xcp.regs = regs; + /* Current regs non-zero indicates that we are processing an interrupt; * current_regs is also used to manage interrupt level context switches. */ @@ -268,7 +270,7 @@ uint32_t *arm_syscall(uint32_t *regs) * set will determine the restored context. */ - up_set_current_regs((uint32_t *)regs[REG_R1]); + tcb->xcp.regs = (uint32_t *)regs[REG_R1]; DEBUGASSERT(up_current_regs()); } break; @@ -294,7 +296,7 @@ uint32_t *arm_syscall(uint32_t *regs) { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); *(uint32_t **)regs[REG_R1] = regs; - up_set_current_regs((uint32_t *)regs[REG_R2]); + tcb->xcp.regs = (uint32_t *)regs[REG_R2]; } break; @@ -561,22 +563,19 @@ uint32_t *arm_syscall(uint32_t *regs) break; } - /* Restore the cpu lock */ - - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* 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 */ restore_critical_section(tcb, cpu); - regs = up_current_regs(); + regs = tcb->xcp.regs; } /* Report what happened */ diff --git a/arch/arm/src/common/arm_internal.h b/arch/arm/src/common/arm_internal.h index c5c02a8927717..e7ace0d52ed84 100644 --- a/arch/arm/src/common/arm_internal.h +++ b/arch/arm/src/common/arm_internal.h @@ -96,11 +96,6 @@ #define INTSTACK_SIZE (CONFIG_ARCH_INTERRUPTSTACK & ~STACK_ALIGN_MASK) -/* Macros to handle saving and restoring interrupt state. */ - -#define arm_savestate(regs) (regs = up_current_regs()) -#define arm_restorestate(regs) up_set_current_regs(regs) - /* Toolchain dependent, linker defined section addresses */ #if defined(__ICCARM__) diff --git a/arch/arm/src/common/arm_switchcontext.c b/arch/arm/src/common/arm_switchcontext.c index 51fe498e0c1e0..f342da9ebc763 100644 --- a/arch/arm/src/common/arm_switchcontext.c +++ b/arch/arm/src/common/arm_switchcontext.c @@ -63,21 +63,9 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) if (up_current_regs()) { - /* Yes, then we have to do things differently. - * Just copy the current_regs into the OLD rtcb. - */ - - arm_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. - */ - - arm_restorestate(tcb->xcp.regs); } /* No, then we will need to perform the user context switch */ diff --git a/arch/arm/src/cxd56xx/cxd56_cpupause.c b/arch/arm/src/cxd56xx/cxd56_cpupause.c index d02a51b8a2d35..3857728f45095 100644 --- a/arch/arm/src/cxd56xx/cxd56_cpupause.c +++ b/arch/arm/src/cxd56xx/cxd56_cpupause.c @@ -199,11 +199,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. - */ - - arm_savestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } @@ -290,11 +286,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. - */ - - arm_restorestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } diff --git a/arch/arm/src/dm320/dm320_decodeirq.c b/arch/arm/src/dm320/dm320_decodeirq.c index 0fc6b0b39df07..3cdec04c059b3 100644 --- a/arch/arm/src/dm320/dm320_decodeirq.c +++ b/arch/arm/src/dm320/dm320_decodeirq.c @@ -34,6 +34,7 @@ #include "chip.h" #include "arm_internal.h" +#include "sched/sched.h" /**************************************************************************** * Public Functions @@ -41,6 +42,8 @@ uint32_t *arm_decodeirq(uint32_t *regs) { + struct tcb_s *tcb = this_task(); + #ifdef CONFIG_SUPPRESS_INTERRUPTS up_set_current_regs(regs); err("ERROR: Unexpected IRQ\n"); @@ -78,11 +81,13 @@ uint32_t *arm_decodeirq(uint32_t *regs) */ DEBUGASSERT(up_current_regs() == NULL); + tcb->xcp.regs = regs; up_set_current_regs(regs); /* Deliver the IRQ */ irq_dispatch(irq, regs); + tcb = this_task(); #ifdef CONFIG_ARCH_ADDRENV /* Check for a context switch. If a context switch occurred, then @@ -92,7 +97,7 @@ uint32_t *arm_decodeirq(uint32_t *regs) * from the interrupt. */ - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, diff --git a/arch/arm/src/imx1/imx_decodeirq.c b/arch/arm/src/imx1/imx_decodeirq.c index b164e5adbe193..43f7c8e1ed45b 100644 --- a/arch/arm/src/imx1/imx_decodeirq.c +++ b/arch/arm/src/imx1/imx_decodeirq.c @@ -57,6 +57,8 @@ uint32_t *arm_decodeirq(uint32_t *regs) { + struct tcb_s *tcb = this_task(); + #ifdef CONFIG_SUPPRESS_INTERRUPTS up_set_current_regs(regs); err("ERROR: Unexpected IRQ\n"); @@ -74,6 +76,7 @@ uint32_t *arm_decodeirq(uint32_t *regs) DEBUGASSERT(up_current_regs() == NULL); up_set_current_regs(regs); + tcb->xcp.regs = regs; /* Loop while there are pending interrupts to be processed */ @@ -99,6 +102,7 @@ uint32_t *arm_decodeirq(uint32_t *regs) /* Deliver the IRQ */ irq_dispatch(irq, regs); + tcb = this_task(); #ifdef CONFIG_ARCH_ADDRENV /* Check for a context switch. If a context switch occurred, then @@ -108,7 +112,7 @@ uint32_t *arm_decodeirq(uint32_t *regs) * from the interrupt. */ - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, diff --git a/arch/arm/src/lc823450/lc823450_cpupause.c b/arch/arm/src/lc823450/lc823450_cpupause.c index 31957f8ad2c08..c75abbae17b63 100644 --- a/arch/arm/src/lc823450/lc823450_cpupause.c +++ b/arch/arm/src/lc823450/lc823450_cpupause.c @@ -127,11 +127,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. - */ - - arm_savestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } @@ -211,11 +207,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. - */ - - arm_restorestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } diff --git a/arch/arm/src/lpc214x/lpc214x_decodeirq.c b/arch/arm/src/lpc214x/lpc214x_decodeirq.c index ecf0294b257da..08662be3b5a7a 100644 --- a/arch/arm/src/lpc214x/lpc214x_decodeirq.c +++ b/arch/arm/src/lpc214x/lpc214x_decodeirq.c @@ -33,6 +33,7 @@ #include "chip.h" #include "arm_internal.h" #include "lpc214x_vic.h" +#include "sched/sched.h" /**************************************************************************** * Private Data @@ -81,6 +82,8 @@ uint32_t *arm_decodeirq(uint32_t *regs) static uint32_t *lpc214x_decodeirq(uint32_t *regs) #endif { + struct tcb_s *tcb = this_task(); + #ifdef CONFIG_SUPPRESS_INTERRUPTS up_set_current_regs(regs); err("ERROR: Unexpected IRQ\n"); @@ -125,6 +128,7 @@ static uint32_t *lpc214x_decodeirq(uint32_t *regs) savestate = up_current_regs(); up_set_current_regs(regs); + tcb->xcp.regs = regs; /* Deliver the IRQ */ diff --git a/arch/arm/src/lpc2378/lpc23xx_decodeirq.c b/arch/arm/src/lpc2378/lpc23xx_decodeirq.c index 0affc82ebaf99..9a2d253dea86f 100644 --- a/arch/arm/src/lpc2378/lpc23xx_decodeirq.c +++ b/arch/arm/src/lpc2378/lpc23xx_decodeirq.c @@ -56,6 +56,7 @@ #include "arm_internal.h" #include "lpc2378.h" #include "lpc23xx_vic.h" +#include "sched/sched.h" /**************************************************************************** * Public Functions @@ -91,6 +92,8 @@ uint32_t *arm_decodeirq(uint32_t *regs) static uint32_t *lpc23xx_decodeirq(uint32_t *regs) #endif { + struct tcb_s *tcb = this_task(); + #ifdef CONFIG_SUPPRESS_INTERRUPTS err("ERROR: Unexpected IRQ\n"); up_set_current_regs(regs); @@ -124,6 +127,7 @@ static uint32_t *lpc23xx_decodeirq(uint32_t *regs) savestate = up_current_regs(); up_set_current_regs(regs); + tcb->xcp.regs = regs; /* Acknowledge the interrupt */ diff --git a/arch/arm/src/lpc31xx/lpc31_decodeirq.c b/arch/arm/src/lpc31xx/lpc31_decodeirq.c index 517761d9ceb9d..64e603ce3012b 100644 --- a/arch/arm/src/lpc31xx/lpc31_decodeirq.c +++ b/arch/arm/src/lpc31xx/lpc31_decodeirq.c @@ -34,7 +34,7 @@ #include "chip.h" #include "arm_internal.h" - +#include "sched/sched.h" #include "lpc31_intc.h" /**************************************************************************** @@ -43,6 +43,8 @@ uint32_t *arm_decodeirq(uint32_t *regs) { + struct tcb_s *tcb = this_task(); + #ifdef CONFIG_SUPPRESS_INTERRUPTS up_set_current_regs(regs); err("ERROR: Unexpected IRQ\n"); @@ -84,10 +86,12 @@ uint32_t *arm_decodeirq(uint32_t *regs) DEBUGASSERT(up_current_regs() == NULL); up_set_current_regs(regs); + tcb->xcp.regs = regs; /* Deliver the IRQ */ irq_dispatch(irq, regs); + tcb = this_task(); #ifdef CONFIG_ARCH_ADDRENV /* Check for a context switch. If a context switch occurred, then @@ -97,7 +101,7 @@ uint32_t *arm_decodeirq(uint32_t *regs) * from the interrupt. */ - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, diff --git a/arch/arm/src/moxart/moxart_irq.c b/arch/arm/src/moxart/moxart_irq.c index 0fcb8c4348dfe..029582c0e0143 100644 --- a/arch/arm/src/moxart/moxart_irq.c +++ b/arch/arm/src/moxart/moxart_irq.c @@ -260,6 +260,7 @@ void arm_ack_irq(int irq) uint32_t *arm_decodeirq(uint32_t *regs) { + struct tcb_s *tcb = this_task(); uint32_t num; uint32_t status; @@ -278,6 +279,7 @@ uint32_t *arm_decodeirq(uint32_t *regs) DEBUGASSERT(up_current_regs() == NULL); up_set_current_regs(regs); + tcb->xcp.regs = regs; irq_dispatch(num, regs); up_set_current_regs(NULL); diff --git a/arch/arm/src/rp2040/rp2040_cpupause.c b/arch/arm/src/rp2040/rp2040_cpupause.c index 06edbadef23da..b5a4e8f820184 100644 --- a/arch/arm/src/rp2040/rp2040_cpupause.c +++ b/arch/arm/src/rp2040/rp2040_cpupause.c @@ -167,11 +167,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. - */ - - arm_savestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } @@ -251,11 +247,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. - */ - - arm_restorestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } diff --git a/arch/arm/src/sam34/sam4cm_cpupause.c b/arch/arm/src/sam34/sam4cm_cpupause.c index 5ad0adb4106bf..4abd9068de7c1 100644 --- a/arch/arm/src/sam34/sam4cm_cpupause.c +++ b/arch/arm/src/sam34/sam4cm_cpupause.c @@ -129,11 +129,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. - */ - - arm_savestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } @@ -213,11 +209,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. - */ - - arm_restorestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } diff --git a/arch/arm/src/str71x/str71x_decodeirq.c b/arch/arm/src/str71x/str71x_decodeirq.c index 44e8fe9478432..f3098e76b890c 100644 --- a/arch/arm/src/str71x/str71x_decodeirq.c +++ b/arch/arm/src/str71x/str71x_decodeirq.c @@ -35,6 +35,7 @@ #include "chip.h" #include "arm_internal.h" +#include "sched/sched.h" /**************************************************************************** * Public Functions @@ -53,6 +54,8 @@ uint32_t *arm_decodeirq(uint32_t *regs) { + struct tcb_s *tcb = this_task(); + #ifdef CONFIG_SUPPRESS_INTERRUPTS board_autoled_on(LED_INIRQ); up_set_current_regs(regs); @@ -82,6 +85,7 @@ uint32_t *arm_decodeirq(uint32_t *regs) savestate = up_current_regs(); up_set_current_regs(regs); + tcb->xcp.regs = regs; /* Acknowledge the interrupt */ diff --git a/arch/arm/src/tlsr82/tc32/tc32_doirq.c b/arch/arm/src/tlsr82/tc32/tc32_doirq.c index 82fcd63710b92..aa301a366983b 100644 --- a/arch/arm/src/tlsr82/tc32/tc32_doirq.c +++ b/arch/arm/src/tlsr82/tc32/tc32_doirq.c @@ -36,7 +36,7 @@ #include #include "arm_internal.h" - +#include "sched/sched.h" #include "hardware/tlsr82_irq.h" /**************************************************************************** @@ -57,6 +57,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) { + struct tcb_s *tcb = this_task(); + board_autoled_on(LED_INIRQ); #ifdef CONFIG_SUPPRESS_INTERRUPTS PANIC(); @@ -78,6 +80,8 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) regs = NULL; } + tcb->xcp.regs = regs; + /* Acknowledge the interrupt */ arm_ack_irq(irq); @@ -85,6 +89,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) /* Deliver the IRQ */ irq_dispatch(irq, up_current_regs()); + tcb = this_task(); /* If a context switch occurred while processing the interrupt then * current_regs may have change value. If we return any value different @@ -94,11 +99,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) if (regs == NULL) { - /* Restore the cpu lock */ - - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { - regs = up_current_regs(); + regs = tcb->xcp.regs; } /* Update the current_regs to NULL. */ diff --git a/arch/arm/src/tlsr82/tc32/tc32_schedulesigaction.c b/arch/arm/src/tlsr82/tc32/tc32_schedulesigaction.c index 73fd33227897a..4e90afee3a804 100644 --- a/arch/arm/src/tlsr82/tc32/tc32_schedulesigaction.c +++ b/arch/arm/src/tlsr82/tc32/tc32_schedulesigaction.c @@ -89,67 +89,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * being delivered to the currently executing task. */ - sinfo("rtcb=%p current_regs=%p\n", this_task(), up_current_regs()); + sinfo("rtcb=%p current_regs=%p\n", this_task(), + this_task()->xcp.regs); - if (tcb == this_task()) + if (tcb == this_task() && !up_interrupt_context()) { - /* CASE 1: We are not in an interrupt handler and - * a task is signalling itself for some reason. - */ - - if (!up_current_regs()) - { - /* In this case just deliver the signal now. */ - - 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 signalling itself, but - * a context switch to another task has occurred so that - * current_regs does not refer to the thread of this_task()! - */ - - else - { - /* Save the return lr and cpsr and one scratch register - * These will be restored by the signal trampoline after - * the signals have been delivered. - */ - - /* And make sure that the saved context in the TCB - * is the same as the interrupt return context. - */ - - arm_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_SP] = (uint32_t)(up_current_regs() + - XCPTCONTEXT_REGS); - - /* Then set up to vector to the trampoline with interrupts - * disabled - */ + /* In this case just deliver the signal now. */ - up_current_regs()[REG_LR] = (uint32_t)arm_sigdeliver; - up_current_regs()[REG_CPSR] = PSR_MODE_SVC | PSR_I_BIT; - up_current_regs()[REG_IRQ_EN] = 0; - } + sigdeliver(tcb); + tcb->xcp.sigdeliver = NULL; } /* Otherwise, we are (1) signaling a task is not running From 21f7acfd688b3bcaf841efd90a200c7b3e048d25 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Mon, 23 Sep 2024 09:24:53 +0800 Subject: [PATCH 2/4] arm: tc32 nested interrupts are not supported Signed-off-by: hujun5 --- arch/arm/src/tlsr82/tc32/tc32_doirq.c | 28 ++++++++++----------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/arch/arm/src/tlsr82/tc32/tc32_doirq.c b/arch/arm/src/tlsr82/tc32/tc32_doirq.c index aa301a366983b..8dd0abb66a2de 100644 --- a/arch/arm/src/tlsr82/tc32/tc32_doirq.c +++ b/arch/arm/src/tlsr82/tc32/tc32_doirq.c @@ -64,21 +64,15 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) PANIC(); #else - /* Nested interrupts are not supported in this implementation. If you - * want to implement nested interrupts, you would have to (1) change the - * way that current_regs is handled and (2) the design associated with - * CONFIG_ARCH_INTERRUPTSTACK. - */ + /* Nested interrupts are not supported */ + + DEBUGASSERT(up_current_regs() == NULL); /* Current regs non-zero indicates that we are processing an interrupt; * current_regs is also used to manage interrupt level context switches. */ - if (up_current_regs() == NULL) - { - up_set_current_regs(regs); - regs = NULL; - } + up_set_current_regs(regs); tcb->xcp.regs = regs; @@ -97,17 +91,15 @@ uint32_t *arm_doirq(int irq, uint32_t *regs) * switch occurred during interrupt processing. */ - if (regs == NULL) + if (regs != tcb->xcp.regs) { - if (regs != tcb->xcp.regs) - { - regs = tcb->xcp.regs; - } + regs = tcb->xcp.regs; + } - /* Update the current_regs to NULL. */ + /* Update the current_regs to NULL. */ + + up_set_current_regs(NULL); - up_set_current_regs(NULL); - } #endif board_autoled_off(LED_INIRQ); From 292f9fd910b8d4fef0c230f3776f5a216a3dbf34 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Tue, 25 Jun 2024 21:33:35 +0800 Subject: [PATCH 3/4] irq: use up_interrupt_context to replace up_current_regs Signed-off-by: hujun5 --- arch/arm/src/common/arm_switchcontext.c | 2 +- arch/arm64/src/common/arm64_switchcontext.c | 2 +- arch/risc-v/src/common/riscv_switchcontext.c | 2 +- arch/sim/src/sim/sim_switchcontext.c | 2 +- arch/x86_64/src/common/x86_64_switchcontext.c | 2 +- boards/arm/cxd56xx/common/src/cxd56_crashdump.c | 7 +------ boards/arm/stm32/nucleo-f429zi/src/stm32_bbsram.c | 7 +------ boards/arm/stm32f7/nucleo-144/src/stm32_bbsram.c | 7 +------ boards/renesas/rx65n/rx65n-grrose/src/rx65n_sbram.c | 7 +------ boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_sbram.c | 7 +------ 10 files changed, 10 insertions(+), 35 deletions(-) diff --git a/arch/arm/src/common/arm_switchcontext.c b/arch/arm/src/common/arm_switchcontext.c index f342da9ebc763..ab266f29fb8f0 100644 --- a/arch/arm/src/common/arm_switchcontext.c +++ b/arch/arm/src/common/arm_switchcontext.c @@ -61,7 +61,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) /* Are we in an interrupt handler? */ - if (up_current_regs()) + if (up_interrupt_context()) { /* Update scheduler parameters */ diff --git a/arch/arm64/src/common/arm64_switchcontext.c b/arch/arm64/src/common/arm64_switchcontext.c index 28b6014f149cb..78b9784e702da 100644 --- a/arch/arm64/src/common/arm64_switchcontext.c +++ b/arch/arm64/src/common/arm64_switchcontext.c @@ -61,7 +61,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) /* Are we in an interrupt handler? */ - if (up_current_regs()) + if (up_interrupt_context()) { /* Yes, then we have to do things differently. * Just copy the current_regs into the OLD rtcb. diff --git a/arch/risc-v/src/common/riscv_switchcontext.c b/arch/risc-v/src/common/riscv_switchcontext.c index fe3db42d0ef9c..d7df00ef86bea 100644 --- a/arch/risc-v/src/common/riscv_switchcontext.c +++ b/arch/risc-v/src/common/riscv_switchcontext.c @@ -63,7 +63,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) /* Are we in an interrupt handler? */ - if (up_current_regs()) + if (up_interrupt_context()) { /* Yes, then we have to do things differently. * Just copy the current_regs into the OLD rtcb. diff --git a/arch/sim/src/sim/sim_switchcontext.c b/arch/sim/src/sim/sim_switchcontext.c index 106af71e3ab95..fc8d9d703dfc4 100644 --- a/arch/sim/src/sim/sim_switchcontext.c +++ b/arch/sim/src/sim/sim_switchcontext.c @@ -64,7 +64,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) /* Are we in an interrupt handler? */ - if (up_current_regs()) + if (up_interrupt_context()) { /* Yes, then we have to do things differently. * Just copy the current_regs into the OLD rtcb. diff --git a/arch/x86_64/src/common/x86_64_switchcontext.c b/arch/x86_64/src/common/x86_64_switchcontext.c index 16f1417140199..d876f20a30e5b 100644 --- a/arch/x86_64/src/common/x86_64_switchcontext.c +++ b/arch/x86_64/src/common/x86_64_switchcontext.c @@ -65,7 +65,7 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) /* Are we in an interrupt handler? */ - if (up_current_regs()) + if (up_interrupt_context()) { /* Yes, then we have to do things differently. * Just copy the g_current_regs into the OLD rtcb. diff --git a/boards/arm/cxd56xx/common/src/cxd56_crashdump.c b/boards/arm/cxd56xx/common/src/cxd56_crashdump.c index fc99e88090c98..c3c37a164c93d 100644 --- a/boards/arm/cxd56xx/common/src/cxd56_crashdump.c +++ b/boards/arm/cxd56xx/common/src/cxd56_crashdump.c @@ -155,12 +155,7 @@ void board_crashdump(uintptr_t sp, struct tcb_s *tcb, pdump->info.pid = tcb->pid; - /* If current_regs is not NULL then we are in an interrupt context - * and the user context is in current_regs else we are running in - * the users context - */ - - if (up_current_regs()) + if (up_interrupt_context()) { #if CONFIG_ARCH_INTERRUPTSTACK > 3 pdump->info.stacks.interrupt.sp = sp; diff --git a/boards/arm/stm32/nucleo-f429zi/src/stm32_bbsram.c b/boards/arm/stm32/nucleo-f429zi/src/stm32_bbsram.c index 0b2e362525fe7..9f4c643368f04 100644 --- a/boards/arm/stm32/nucleo-f429zi/src/stm32_bbsram.c +++ b/boards/arm/stm32/nucleo-f429zi/src/stm32_bbsram.c @@ -426,12 +426,7 @@ void board_crashdump(uintptr_t sp, struct tcb_s *tcb, pdump->info.pid = tcb->pid; - /* If current_regs is not NULL then we are in an interrupt context - * and the user context is in current_regs else we are running in - * the users context - */ - - if (up_current_regs()) + if (up_interrupt_context()) { pdump->info.stacks.interrupt.sp = sp; pdump->info.flags |= (REGS_PRESENT | USERSTACK_PRESENT | diff --git a/boards/arm/stm32f7/nucleo-144/src/stm32_bbsram.c b/boards/arm/stm32f7/nucleo-144/src/stm32_bbsram.c index 5ea551dd9018e..9e11adaaa69be 100644 --- a/boards/arm/stm32f7/nucleo-144/src/stm32_bbsram.c +++ b/boards/arm/stm32f7/nucleo-144/src/stm32_bbsram.c @@ -426,12 +426,7 @@ void board_crashdump(uintptr_t sp, struct tcb_s *tcb, pdump->info.pid = tcb->pid; - /* If current_regs is not NULL then we are in an interrupt context - * and the user context is in current_regs else we are running in - * the users context - */ - - if (up_current_regs()) + if (up_interrupt_context()) { pdump->info.stacks.interrupt.sp = sp; pdump->info.flags |= (REGS_PRESENT | USERSTACK_PRESENT | diff --git a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_sbram.c b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_sbram.c index 09a32bbccc64f..881c785040f5b 100644 --- a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_sbram.c +++ b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_sbram.c @@ -380,12 +380,7 @@ void board_crashdump(uintptr_t sp, struct tcb_s *tcb, pdump->info.pid = tcb->pid; - /* If current_regs is not NULL then we are in an interrupt context - * and the user context is in current_regs else we are running in - * the users context - */ - - if (up_current_regs()) + if (up_interrupt_context()) { pdump->info.stacks.interrupt.sp = sp; pdump->info.flags |= (REGS_PRESENT | USERSTACK_PRESENT | diff --git a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_sbram.c b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_sbram.c index f4f24219ed933..f5918bb850ceb 100644 --- a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_sbram.c +++ b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_sbram.c @@ -378,12 +378,7 @@ void board_crashdump(uintptr_t sp, struct tcb_s *tcb, pdump->info.pid = tcb->pid; - /* If current_regs is not NULL then we are in an interrupt context - * and the user context is in current_regs else we are running in - * the users context - */ - - if (up_current_regs()) + if (up_interrupt_context()) { pdump->info.stacks.interrupt.sp = sp; pdump->info.flags |= (REGS_PRESENT | USERSTACK_PRESENT | From 9cf0902f592e9928a7e870afb0753aa5103eb2e7 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Fri, 5 Jul 2024 20:53:49 +0800 Subject: [PATCH 4/4] arm64: g_current_regs is only used to determine if we are in irq, with other functionalities removed. Signed-off-by: hujun5 --- arch/arm64/src/common/arm64_cpupause.c | 12 +- arch/arm64/src/common/arm64_doirq.c | 10 +- arch/arm64/src/common/arm64_internal.h | 7 - .../src/common/arm64_schedulesigaction.c | 207 ++---------------- arch/arm64/src/common/arm64_switchcontext.c | 12 - 5 files changed, 31 insertions(+), 217 deletions(-) diff --git a/arch/arm64/src/common/arm64_cpupause.c b/arch/arm64/src/common/arm64_cpupause.c index 05bdf8a324c1c..870917ca152c8 100644 --- a/arch/arm64/src/common/arm64_cpupause.c +++ b/arch/arm64/src/common/arm64_cpupause.c @@ -116,11 +116,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. - */ - - arm64_savestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } @@ -210,11 +206,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. - */ - - arm64_restorestate(tcb->xcp.regs); + UNUSED(tcb); return OK; } diff --git a/arch/arm64/src/common/arm64_doirq.c b/arch/arm64/src/common/arm64_doirq.c index 5a45a40d26712..af0a5abe444c2 100644 --- a/arch/arm64/src/common/arm64_doirq.c +++ b/arch/arm64/src/common/arm64_doirq.c @@ -57,6 +57,8 @@ uint64_t *arm64_doirq(int irq, uint64_t * regs) { + struct tcb_s *tcb = this_task(); + /* Nested interrupts are not supported */ DEBUGASSERT(up_current_regs() == NULL); @@ -66,10 +68,12 @@ uint64_t *arm64_doirq(int irq, uint64_t * regs) */ up_set_current_regs(regs); + 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 an @@ -78,7 +82,7 @@ uint64_t *arm64_doirq(int irq, uint64_t * regs) * returning from the interrupt. */ - if (regs != up_current_regs()) + if (regs != tcb->xcp.regs) { /* need to do a context switch */ @@ -97,8 +101,8 @@ uint64_t *arm64_doirq(int irq, uint64_t * regs) * crashes. */ - g_running_tasks[this_cpu()] = this_task(); - 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/arm64/src/common/arm64_internal.h b/arch/arm64/src/common/arm64_internal.h index 19c8b9eb69f64..6f4ab45b2c93b 100644 --- a/arch/arm64/src/common/arm64_internal.h +++ b/arch/arm64/src/common/arm64_internal.h @@ -84,13 +84,6 @@ # define CONFIG_ARCH_INTERRUPTSTACK 0 #endif -/* If the floating point unit is present and enabled, then save the - * floating point registers as well as normal ARM registers. - */ - -#define arm64_savestate(regs) (regs = up_current_regs()) -#define arm64_restorestate(regs) up_set_current_regs(regs) - /* This is the value used to mark the stack for subsequent stack monitoring * logic. */ diff --git a/arch/arm64/src/common/arm64_schedulesigaction.c b/arch/arm64/src/common/arm64_schedulesigaction.c index 888c8106268dd..6301f0bb6f248 100644 --- a/arch/arm64/src/common/arm64_schedulesigaction.c +++ b/arch/arm64/src/common/arm64_schedulesigaction.c @@ -126,9 +126,10 @@ void arm64_init_signal_process(struct tcb_s *tcb, struct regs_context *regs) * ****************************************************************************/ -#ifndef CONFIG_SMP void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) { + sinfo("tcb=%p sigdeliver=%p\n", tcb, sigdeliver); + /* Refuse to handle nested signal actions */ if (!tcb->xcp.sigdeliver) @@ -136,204 +137,32 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) tcb->xcp.sigdeliver = sigdeliver; /* First, handle some special cases when the signal is being delivered - * to task that is currently executing on this CPU. + * 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. + /* In this case just deliver the signal now. + * REVISIT: Signal handler will run in a critical section! */ - 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()! - */ - - else - { - /* Save the return lr and cpsr and one scratch register - * These will be restored by the signal trampoline after - * the signals have been delivered. - */ - - /* create signal process context */ - - tcb->xcp.saved_reg = up_current_regs(); -#ifdef CONFIG_ARCH_FPU - tcb->xcp.saved_fpu_regs = tcb->xcp.fpu_regs; -#endif - arm64_init_signal_process(tcb, - (struct regs_context *)up_current_regs()); - - /* trigger switch to signal process */ - - up_set_current_regs(tcb->xcp.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 other non-running task. - */ - else { - /* Save the return lr and cpsr and one scratch register. These - * will be restored by the signal trampoline after the signals - * have been delivered. - */ - -#ifdef CONFIG_ARCH_FPU - tcb->xcp.saved_fpu_regs = tcb->xcp.fpu_regs; -#endif - /* create signal process context */ - - tcb->xcp.saved_reg = tcb->xcp.regs; - arm64_init_signal_process(tcb, NULL); - } - } -} -#endif /* !CONFIG_SMP */ - #ifdef CONFIG_SMP -void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) -{ - int cpu; - int me; - - 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. - */ + int cpu = tcb->cpu; + int me = this_cpu(); - 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. These will be - * restored by the signal trampoline after the signal has - * been delivered. - */ - -#ifdef CONFIG_ARCH_FPU - tcb->xcp.saved_fpu_regs = tcb->xcp.fpu_regs; -#endif - /* create signal process context */ - - tcb->xcp.saved_reg = tcb->xcp.regs; - arm64_init_signal_process(tcb, NULL); - } - else - { - /* tcb is running on the same CPU */ - - /* Save the return PC, CPSR and either the BASEPRI or - * PRIMASK registers (and perhaps also the LR). These will - * be restored by the signal trampoline after the signal - * has been delivered. - */ - - /* create signal process context */ - - tcb->xcp.saved_reg = up_current_regs(); -#ifdef CONFIG_ARCH_FPU - tcb->xcp.saved_fpu_regs = tcb->xcp.fpu_regs; #endif - arm64_init_signal_process(tcb, - (struct regs_context *)up_current_regs()); - - /* trigger switch to signal process */ - - up_set_current_regs(tcb->xcp.regs); - } - - /* 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 return lr and cpsr and one scratch register. These * will be restored by the signal trampoline after the signals * have been delivered. @@ -347,7 +176,15 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) /* create signal process context */ arm64_init_signal_process(tcb, NULL); + +#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/arm64/src/common/arm64_switchcontext.c b/arch/arm64/src/common/arm64_switchcontext.c index 78b9784e702da..b5ab2234d19c3 100644 --- a/arch/arm64/src/common/arm64_switchcontext.c +++ b/arch/arm64/src/common/arm64_switchcontext.c @@ -63,21 +63,9 @@ void up_switch_context(struct tcb_s *tcb, struct tcb_s *rtcb) if (up_interrupt_context()) { - /* Yes, then we have to do things differently. - * Just copy the current_regs into the OLD rtcb. - */ - - arm64_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. - */ - - arm64_restorestate(tcb->xcp.regs); } /* No, then we will need to perform the user context switch */