diff --git a/arch/arm/include/arm/irq.h b/arch/arm/include/arm/irq.h index 376288220e..62cbed6a0a 100644 --- a/arch/arm/include/arm/irq.h +++ b/arch/arm/include/arm/irq.h @@ -133,21 +133,19 @@ struct xcptcontext void *sigdeliver; /* Actual type is sig_deliver_t */ - /* These are saved copies of LR and CPSR used during + /* These are saved copies of the context used during * signal processing. - * - * REVISIT: Because there is only one copy of these save areas, - * only a single signal handler can be active. This precludes - * queuing of signal actions. As a result, signals received while - * another signal handler is executing will be ignored! */ - uint32_t saved_pc; - uint32_t saved_cpsr; + uint32_t *saved_regs; - /* Register save area */ + /* Register save area with XCPTCONTEXT_SIZE, only valid when: + * 1.The task isn't running or + * 2.The task is interrupted + * otherwise task is running, and regs contain the stale value. + */ - uint32_t regs[XCPTCONTEXT_REGS]; + uint32_t *regs; /* Extra fault address register saved for common paging logic. In the * case of the prefetch abort, this value is the same as regs[REG_R15]; diff --git a/arch/arm/include/armv6-m/irq.h b/arch/arm/include/armv6-m/irq.h index 104828b26c..b5e59b64e8 100644 --- a/arch/arm/include/armv6-m/irq.h +++ b/arch/arm/include/armv6-m/irq.h @@ -165,21 +165,13 @@ struct xcptcontext void *sigdeliver; /* Actual type is sig_deliver_t */ - /* These are saved copies of LR, PRIMASK, and xPSR used during + /* These are saved copies of the context used during * signal processing. - * - * REVISIT: Because there is only one copy of these save areas, - * only a single signal handler can be active. This precludes - * queuing of signal actions. As a result, signals received while - * another signal handler is executing will be ignored! */ - uint32_t saved_pc; - uint32_t saved_primask; - uint32_t saved_xpsr; -#ifdef CONFIG_BUILD_PROTECTED - uint32_t saved_lr; + uint32_t *saved_regs; +#ifdef CONFIG_BUILD_PROTECTED /* This is the saved address to use when returning from a user-space * signal handler. */ @@ -196,9 +188,13 @@ struct xcptcontext struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST]; #endif - /* Register save area */ + /* Register save area with XCPTCONTEXT_SIZE, only valid when: + * 1.The task isn't running or + * 2.The task is interrupted + * otherwise task is running, and regs contain the stale value. + */ - uint32_t regs[XCPTCONTEXT_REGS]; + uint32_t *regs; }; #endif diff --git a/arch/arm/include/armv7-a/irq.h b/arch/arm/include/armv7-a/irq.h index 7bbc7870cd..f299416276 100644 --- a/arch/arm/include/armv7-a/irq.h +++ b/arch/arm/include/armv7-a/irq.h @@ -245,16 +245,11 @@ struct xcptcontext void *sigdeliver; /* Actual type is sig_deliver_t */ - /* These are saved copies of LR and CPSR used during signal processing. - * - * REVISIT: Because there is only one copy of these save areas, - * only a single signal handler can be active. This precludes - * queuing of signal actions. As a result, signals received while - * another signal handler is executing will be ignored! + /* These are saved copies of the context used during + * signal processing. */ - uint32_t saved_pc; - uint32_t saved_cpsr; + uint32_t *saved_regs; #ifdef CONFIG_BUILD_KERNEL /* This is the saved address to use when returning from a user-space @@ -265,9 +260,13 @@ struct xcptcontext #endif - /* Register save area */ + /* Register save area with XCPTCONTEXT_SIZE, only valid when: + * 1.The task isn't running or + * 2.The task is interrupted + * otherwise task is running, and regs contain the stale value. + */ - uint32_t regs[XCPTCONTEXT_REGS]; + uint32_t *regs; /* Extra fault address register saved for common paging logic. In the * case of the pre-fetch abort, this value is the same as regs[REG_R15]; diff --git a/arch/arm/include/armv7-m/irq.h b/arch/arm/include/armv7-m/irq.h index 96fd94c1f0..e965fc7ab1 100644 --- a/arch/arm/include/armv7-m/irq.h +++ b/arch/arm/include/armv7-m/irq.h @@ -120,25 +120,13 @@ struct xcptcontext FAR void *sigdeliver; /* Actual type is sig_deliver_t */ - /* These are saved copies of LR, PRIMASK, and xPSR used during + /* These are saved copies of the context used during * signal processing. - * - * REVISIT: Because there is only one copy of these save areas, - * only a single signal handler can be active. This precludes - * queuing of signal actions. As a result, signals received while - * another signal handler is executing will be ignored! */ - uint32_t saved_pc; -#ifdef CONFIG_ARMV7M_USEBASEPRI - uint32_t saved_basepri; -#else - uint32_t saved_primask; -#endif - uint32_t saved_xpsr; -#ifdef CONFIG_BUILD_PROTECTED - uint32_t saved_lr; + uint32_t *saved_regs; +#ifdef CONFIG_BUILD_PROTECTED /* This is the saved address to use when returning from a user-space * signal handler. */ @@ -157,9 +145,13 @@ struct xcptcontext #endif - /* Register save area */ + /* Register save area with XCPTCONTEXT_SIZE, only valid when: + * 1.The task isn't running or + * 2.The task is interrupted + * otherwise task is running, and regs contain the stale value. + */ - uint32_t regs[XCPTCONTEXT_REGS]; + uint32_t *regs; }; #endif diff --git a/arch/arm/include/armv7-r/irq.h b/arch/arm/include/armv7-r/irq.h index 5acced1f55..b020504037 100644 --- a/arch/arm/include/armv7-r/irq.h +++ b/arch/arm/include/armv7-r/irq.h @@ -245,16 +245,11 @@ struct xcptcontext void *sigdeliver; /* Actual type is sig_deliver_t */ - /* These are saved copies of LR and CPSR used during signal processing. - * - * REVISIT: Because there is only one copy of these save areas, - * only a single signal handler can be active. This precludes - * queuing of signal actions. As a result, signals received while - * another signal handler is executing will be ignored! + /* These are saved copies of the context used during + * signal processing. */ - uint32_t saved_pc; - uint32_t saved_cpsr; + uint32_t *saved_regs; #ifdef CONFIG_BUILD_KERNEL /* This is the saved address to use when returning from a user-space @@ -264,9 +259,13 @@ struct xcptcontext uint32_t sigreturn; #endif - /* Register save area */ + /* Register save area with XCPTCONTEXT_SIZE, only valid when: + * 1.The task isn't running or + * 2.The task is interrupted + * otherwise task is running, and regs contain the stale value. + */ - uint32_t regs[XCPTCONTEXT_REGS]; + uint32_t *regs; /* Extra fault address register saved for common paging logic. In the * case of the pre-fetch abort, this value is the same as regs[REG_R15]; diff --git a/arch/arm/include/armv8-m/irq.h b/arch/arm/include/armv8-m/irq.h index a89de9078c..5395484d9d 100644 --- a/arch/arm/include/armv8-m/irq.h +++ b/arch/arm/include/armv8-m/irq.h @@ -125,25 +125,13 @@ struct xcptcontext FAR void *sigdeliver; /* Actual type is sig_deliver_t */ - /* These are saved copies of LR, PRIMASK, and xPSR used during + /* These are saved copies of the context used during * signal processing. - * - * REVISIT: Because there is only one copy of these save areas, - * only a single signal handler can be active. This precludes - * queuing of signal actions. As a result, signals received while - * another signal handler is executing will be ignored! */ - uint32_t saved_pc; -#ifdef CONFIG_ARMV8M_USEBASEPRI - uint32_t saved_basepri; -#else - uint32_t saved_primask; -#endif - uint32_t saved_xpsr; -#ifdef CONFIG_BUILD_PROTECTED - uint32_t saved_lr; + uint32_t *saved_regs; +#ifdef CONFIG_BUILD_PROTECTED /* This is the saved address to use when returning from a user-space * signal handler. */ @@ -162,9 +150,13 @@ struct xcptcontext #endif - /* Register save area */ + /* Register save area with XCPTCONTEXT_SIZE, only valid when: + * 1.The task isn't running or + * 2.The task is interrupted + * otherwise task is running, and regs contain the stale value. + */ - uint32_t regs[XCPTCONTEXT_REGS]; + uint32_t *regs; }; #endif diff --git a/arch/arm/include/syscall.h b/arch/arm/include/syscall.h index b998da7e04..1b1289a0a9 100644 --- a/arch/arm/include/syscall.h +++ b/arch/arm/include/syscall.h @@ -80,7 +80,7 @@ /* SYS call 2: * - * void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); + * void arm_switchcontext(uint32_t **saveregs, uint32_t *restoreregs); */ #define SYS_switch_context (2) diff --git a/arch/arm/src/arm/arm_initialstate.c b/arch/arm/src/arm/arm_initialstate.c index 4bd69fc551..df5a2c0333 100644 --- a/arch/arm/src/arm/arm_initialstate.c +++ b/arch/arm/src/arm/arm_initialstate.c @@ -55,6 +55,10 @@ void up_initial_state(struct tcb_s *tcb) struct xcptcontext *xcp = &tcb->xcp; uint32_t cpsr; + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + /* Initialize the idle thread stack */ if (tcb->pid == 0) @@ -72,20 +76,28 @@ void up_initial_state(struct tcb_s *tcb) arm_stack_color(tcb->stack_alloc_ptr, 0); #endif /* CONFIG_STACK_COLORATION */ + + return; } - /* Initialize the initial exception register context structure */ + /* Initialize the context registers to stack top */ - memset(xcp, 0, sizeof(struct xcptcontext)); + xcp->regs = (FAR void *)STACK_ALIGN_DOWN( + (uint32_t)tcb->stack_base_ptr + + tcb->adj_stack_size - + XCPTCONTEXT_SIZE); + + /* Initialize the xcp registers */ + + memset(xcp->regs, 0, XCPTCONTEXT_SIZE); /* Save the initial stack pointer */ - xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + - tcb->adj_stack_size; + xcp->regs[REG_SP] = (uint32_t)xcp->regs; /* Save the task entry point */ - xcp->regs[REG_PC] = (uint32_t)tcb->start; + xcp->regs[REG_PC] = (uint32_t)tcb->start; /* If this task is running PIC, then set the PIC base register to the * address of the allocated D-Space region. diff --git a/arch/arm/src/arm/arm_schedulesigaction.c b/arch/arm/src/arm/arm_schedulesigaction.c index 1427ba039b..9e37043162 100644 --- a/arch/arm/src/arm/arm_schedulesigaction.c +++ b/arch/arm/src/arm/arm_schedulesigaction.c @@ -122,8 +122,25 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; - tcb->xcp.saved_cpsr = CURRENT_REGS[REG_CPSR]; + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; /* Then set up to vector to the trampoline with interrupts * disabled @@ -131,12 +148,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) CURRENT_REGS[REG_PC] = (uint32_t)arm_sigdeliver; CURRENT_REGS[REG_CPSR] = PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT; - - /* And make sure that the saved context in the TCB - * is the same as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } } @@ -153,16 +164,30 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * the signals have been delivered. */ - tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; - tcb->xcp.saved_cpsr = tcb->xcp.regs[REG_CPSR]; + tcb->xcp.sigdeliver = sigdeliver; + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; /* 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; + tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; + tcb->xcp.regs[REG_CPSR] = PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT; } } } diff --git a/arch/arm/src/arm/arm_sigdeliver.c b/arch/arm/src/arm/arm_sigdeliver.c index 153e4cb733..21a0b98baa 100644 --- a/arch/arm/src/arm/arm_sigdeliver.c +++ b/arch/arm/src/arm/arm_sigdeliver.c @@ -53,8 +53,8 @@ void arm_sigdeliver(void) { - struct tcb_s *rtcb = this_task(); - uint32_t regs[XCPTCONTEXT_REGS]; + struct tcb_s *rtcb = this_task(); + uint32_t *regs = rtcb->xcp.saved_regs; board_autoled_on(LED_SIGNAL); @@ -62,10 +62,6 @@ void arm_sigdeliver(void) rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); - /* Save the return state on the stack. */ - - arm_copyfullstate(regs, rtcb->xcp.regs); - #ifndef CONFIG_SUPPRESS_INTERRUPTS /* Then make sure that interrupts are enabled. Signal handlers must always * run with interrupts enabled. @@ -96,8 +92,6 @@ void arm_sigdeliver(void) * could be modified by a hostile program. */ - regs[REG_PC] = rtcb->xcp.saved_pc; - regs[REG_CPSR] = rtcb->xcp.saved_cpsr; rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */ /* Then restore the correct state for this thread of execution. */ diff --git a/arch/arm/src/arm/arm_syscall.c b/arch/arm/src/arm/arm_syscall.c index e4b9c9857a..06687dfd49 100644 --- a/arch/arm/src/arm/arm_syscall.c +++ b/arch/arm/src/arm/arm_syscall.c @@ -85,7 +85,8 @@ uint32_t *arm_syscall(uint32_t *regs) /* R0=SYS_switch_context: This a switch context command: * - * void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); + * void arm_switchcontext(uint32_t **saveregs, + * uint32_t *restoreregs); * * At this point, the following values are saved in context: * @@ -102,7 +103,7 @@ uint32_t *arm_syscall(uint32_t *regs) case SYS_switch_context: { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); - memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); + *(uint32_t **)regs[REG_R1] = regs; regs = (uint32_t *)regs[REG_R2]; } break; diff --git a/arch/arm/src/arm/arm_vectors.S b/arch/arm/src/arm/arm_vectors.S index 838412e04d..e6f4d047ef 100644 --- a/arch/arm/src/arm/arm_vectors.S +++ b/arch/arm/src/arm/arm_vectors.S @@ -116,7 +116,24 @@ arm_vectorirq: #else /* Call arm_decodeirq() on the user stack */ - bl arm_decodeirq /* Call the handler */ + mov r4, sp /* Save the SP in a preserved register */ + + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + * also the sp should be restore from r4 after arm_doirq() + */ + + sub sp, sp, #XCPTCONTEXT_SIZE /* Reserve signal context */ + + bic sp, sp, #7 /* Force 8-byte alignment */ + bl arm_decodeirq /* Call the handler */ + mov sp, r4 /* Restore the possibly unaligned stack pointer */ #endif /* Restore the CPSR, SYS mode registers and return */ diff --git a/arch/arm/src/armv6-m/arm_exception.S b/arch/arm/src/armv6-m/arm_exception.S index b71a912bbb..c438bf595e 100644 --- a/arch/arm/src/armv6-m/arm_exception.S +++ b/arch/arm/src/armv6-m/arm_exception.S @@ -172,8 +172,25 @@ exception_common: bl arm_doirq /* R0=IRQ, R1=register save area on stack */ pop {r1} /* Recover R1=main stack pointer */ #else + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ---------------------- + * | Signal XCP context | + * ---------------------- <- SP + * also the sp should be restore after arm_doirq() + */ + + sub r1, r1, #XCPTCONTEXT_SIZE /* Reserve signal context */ + msr msp, r1 /* We are using the main stack pointer */ + + add r1, r1, #XCPTCONTEXT_SIZE /* Restore signal context */ + bl arm_doirq /* R0=IRQ, R1=register save area on stack */ + mrs r1, msp /* Recover R1=main stack pointer */ #endif diff --git a/arch/arm/src/armv6-m/arm_initialstate.c b/arch/arm/src/armv6-m/arm_initialstate.c index 9f9683990e..b1d28df81c 100644 --- a/arch/arm/src/armv6-m/arm_initialstate.c +++ b/arch/arm/src/armv6-m/arm_initialstate.c @@ -56,6 +56,10 @@ void up_initial_state(struct tcb_s *tcb) { struct xcptcontext *xcp = &tcb->xcp; + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + /* Initialize the idle thread stack */ if (tcb->pid == 0) @@ -73,16 +77,24 @@ void up_initial_state(struct tcb_s *tcb) arm_stack_color(tcb->stack_alloc_ptr, 0); #endif /* CONFIG_STACK_COLORATION */ + + return; } - /* Initialize the initial exception register context structure */ + /* Initialize the context registers to stack top */ - memset(xcp, 0, sizeof(struct xcptcontext)); + xcp->regs = (FAR void *)STACK_ALIGN_DOWN( + (uint32_t)tcb->stack_base_ptr + + tcb->adj_stack_size - + XCPTCONTEXT_SIZE); + + /* Initialize the xcp registers */ + + memset(xcp->regs, 0, XCPTCONTEXT_SIZE); /* Save the initial stack pointer */ - xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + - tcb->adj_stack_size; + xcp->regs[REG_SP] = (uint32_t)xcp->regs; /* Save the task entry point (stripping off the thumb bit) */ diff --git a/arch/arm/src/armv6-m/arm_schedulesigaction.c b/arch/arm/src/armv6-m/arm_schedulesigaction.c index 41d7614dc6..23e4290628 100644 --- a/arch/arm/src/armv6-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv6-m/arm_schedulesigaction.c @@ -124,12 +124,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; - tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK]; - tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; -#endif + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; + /* Then set up to vector to the trampoline with interrupts * disabled. The kernel-space trampoline must run in * privileged thread mode. @@ -142,11 +156,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; #endif - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } } @@ -163,12 +172,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; - tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; - tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; -#endif + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; + /* Then set up to vector to the trampoline with interrupts * disabled. We must already be in privileged thread mode to be * here. @@ -255,12 +275,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; - tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; - tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; -#endif + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; /* Then set up vector to the trampoline with interrupts * disabled. We must already be in privileged thread mode @@ -285,12 +316,25 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; - tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK]; - tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; -#endif + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; /* Then set up vector to the trampoline with interrupts * disabled. The kernel-space trampoline must run in @@ -303,12 +347,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_BUILD_PROTECTED CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; #endif - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } /* Increment the IRQ lock count so that when the task is @@ -347,12 +385,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; - tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; - tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; -#endif + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; + /* Increment the IRQ lock count so that when the task is restarted, * it will hold the IRQ spinlock. */ diff --git a/arch/arm/src/armv6-m/arm_sigdeliver.c b/arch/arm/src/armv6-m/arm_sigdeliver.c index fd683e0e7e..164318865b 100644 --- a/arch/arm/src/armv6-m/arm_sigdeliver.c +++ b/arch/arm/src/armv6-m/arm_sigdeliver.c @@ -53,13 +53,8 @@ void arm_sigdeliver(void) { - /* NOTE the "magic" guard space added to regs. This is a little kludge - * because arm_fullcontextrestore (called below) will do a stack-to-stack - * copy an may overwrite the regs[] array contents. Sorry. - */ - struct tcb_s *rtcb = this_task(); - uint32_t regs[XCPTCONTEXT_REGS + 4]; + uint32_t *regs = rtcb->xcp.saved_regs; #ifdef CONFIG_SMP /* In the SMP case, we must terminate the critical section while the signal @@ -76,10 +71,6 @@ void arm_sigdeliver(void) rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); - /* Save the return state on the stack. */ - - arm_copyfullstate(regs, rtcb->xcp.regs); - #ifdef CONFIG_SMP /* In the SMP case, up_schedule_sigaction(0) will have incremented * 'irqcount' in order to force us into a critical section. Save the @@ -148,12 +139,6 @@ void arm_sigdeliver(void) * could be modified by a hostile program. */ - regs[REG_PC] = rtcb->xcp.saved_pc; - regs[REG_PRIMASK] = rtcb->xcp.saved_primask; - regs[REG_XPSR] = rtcb->xcp.saved_xpsr; -#ifdef CONFIG_BUILD_PROTECTED - regs[REG_LR] = rtcb->xcp.saved_lr; -#endif rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */ /* Then restore the correct state for this thread of diff --git a/arch/arm/src/armv6-m/arm_svcall.c b/arch/arm/src/armv6-m/arm_svcall.c index 701541bcaf..1ccf869bc9 100644 --- a/arch/arm/src/armv6-m/arm_svcall.c +++ b/arch/arm/src/armv6-m/arm_svcall.c @@ -197,7 +197,8 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg) /* R0=SYS_switch_context: This a switch context command: * - * void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); + * void arm_switchcontext(uint32_t **saveregs, + * uint32_t *restoreregs); * * At this point, the following values are saved in context: * @@ -214,7 +215,7 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg) case SYS_switch_context: { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); - memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); + *(uint32_t **)regs[REG_R1] = regs; CURRENT_REGS = (uint32_t *)regs[REG_R2]; } break; diff --git a/arch/arm/src/armv7-a/arm_cpuhead.S b/arch/arm/src/armv7-a/arm_cpuhead.S index 373fd12a1f..70f29a0886 100644 --- a/arch/arm/src/armv7-a/arm_cpuhead.S +++ b/arch/arm/src/armv7-a/arm_cpuhead.S @@ -24,6 +24,8 @@ #include +#include + #include "arm.h" #include "cp15.h" #include "sctlr.h" @@ -98,6 +100,7 @@ __cpu1_start: /* Set up the stack pointer and the CPU index */ ldr sp, .Lcpu1_stackpointer + sub sp, sp, #XCPTCONTEXT_SIZE mov r5, #1 /* Then branch to the common startup logic (PC-relative) */ @@ -121,6 +124,7 @@ __cpu2_start: /* Set up the stack pointer and the CPU index */ ldr sp, .Lcpu2_stackpointer + sub sp, sp, #XCPTCONTEXT_SIZE mov r5, #2 /* Then branch to the common startup logic (PC-relative) */ @@ -144,6 +148,7 @@ __cpu3_start: /* Set up the stack pointer and the CPU index */ ldr sp, .Lcpu3_stackpointer + sub sp, sp, #XCPTCONTEXT_SIZE mov r5, #3 /* Then branch to the common startup logic (PC-relative) */ diff --git a/arch/arm/src/armv7-a/arm_initialstate.c b/arch/arm/src/armv7-a/arm_initialstate.c index cbc086d764..91a7eaefee 100644 --- a/arch/arm/src/armv7-a/arm_initialstate.c +++ b/arch/arm/src/armv7-a/arm_initialstate.c @@ -55,6 +55,10 @@ void up_initial_state(struct tcb_s *tcb) struct xcptcontext *xcp = &tcb->xcp; uint32_t cpsr; + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + /* Initialize the idle thread stack */ if (tcb->pid == 0) @@ -72,16 +76,24 @@ void up_initial_state(struct tcb_s *tcb) arm_stack_color(tcb->stack_alloc_ptr, 0); #endif /* CONFIG_STACK_COLORATION */ + + return; } - /* Initialize the initial exception register context structure */ + /* Initialize the context registers to stack top */ - memset(xcp, 0, sizeof(struct xcptcontext)); + xcp->regs = (FAR void *)STACK_ALIGN_DOWN( + (uint32_t)tcb->stack_base_ptr + + tcb->adj_stack_size - + XCPTCONTEXT_SIZE); + + /* Initialize the xcp registers */ + + memset(xcp->regs, 0, XCPTCONTEXT_SIZE); /* Save the initial stack pointer */ - xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + - tcb->adj_stack_size; + xcp->regs[REG_SP] = (uint32_t)xcp->regs; /* Save the task entry point */ diff --git a/arch/arm/src/armv7-a/arm_schedulesigaction.c b/arch/arm/src/armv7-a/arm_schedulesigaction.c index a41368044f..aaf03c03f8 100644 --- a/arch/arm/src/armv7-a/arm_schedulesigaction.c +++ b/arch/arm/src/armv7-a/arm_schedulesigaction.c @@ -127,8 +127,25 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; - tcb->xcp.saved_cpsr = CURRENT_REGS[REG_CPSR]; + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; /* Then set up to vector to the trampoline with interrupts * disabled @@ -140,12 +157,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_ARM_THUMB CURRENT_REGS[REG_CPSR] |= PSR_T_BIT; #endif - - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } } @@ -162,8 +173,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; - tcb->xcp.saved_cpsr = tcb->xcp.regs[REG_CPSR]; + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; /* Then set up to vector to the trampoline with interrupts * disabled @@ -249,8 +274,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; - tcb->xcp.saved_cpsr = tcb->xcp.regs[REG_CPSR]; + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; /* Then set up to vector to the trampoline with interrupts * disabled @@ -273,9 +313,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * has been delivered. */ - tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; - tcb->xcp.saved_cpsr = CURRENT_REGS[REG_CPSR]; + tcb->xcp.sigdeliver = (FAR void *)sigdeliver; + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; /* Then set up vector to the trampoline with interrupts * disabled. The kernel-space trampoline must run in @@ -288,12 +345,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_ARM_THUMB CURRENT_REGS[REG_CPSR] |= PSR_T_BIT; #endif - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } /* Increment the IRQ lock count so that when the task is @@ -332,8 +383,22 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; - tcb->xcp.saved_cpsr = tcb->xcp.regs[REG_CPSR]; + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; /* Increment the IRQ lock count so that when the task is restarted, * it will hold the IRQ spinlock. diff --git a/arch/arm/src/armv7-a/arm_sigdeliver.c b/arch/arm/src/armv7-a/arm_sigdeliver.c index aeea069ae6..856f216c0c 100644 --- a/arch/arm/src/armv7-a/arm_sigdeliver.c +++ b/arch/arm/src/armv7-a/arm_sigdeliver.c @@ -53,8 +53,8 @@ void arm_sigdeliver(void) { - struct tcb_s *rtcb = this_task(); - uint32_t regs[XCPTCONTEXT_REGS]; + struct tcb_s *rtcb = this_task(); + uint32_t *regs = rtcb->xcp.saved_regs; #ifdef CONFIG_SMP /* In the SMP case, we must terminate the critical section while the signal @@ -71,10 +71,6 @@ void arm_sigdeliver(void) rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); - /* Save the return state on the stack. */ - - arm_copyfullstate(regs, rtcb->xcp.regs); - #ifdef CONFIG_SMP /* In the SMP case, up_schedule_sigaction(0) will have incremented * 'irqcount' in order to force us into a critical section. Save the @@ -143,8 +139,6 @@ void arm_sigdeliver(void) * could be modified by a hostile program. */ - regs[REG_PC] = rtcb->xcp.saved_pc; - regs[REG_CPSR] = rtcb->xcp.saved_cpsr; rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */ /* Then restore the correct state for this thread of execution. */ diff --git a/arch/arm/src/armv7-a/arm_syscall.c b/arch/arm/src/armv7-a/arm_syscall.c index c571b73ac9..0ac7c8c636 100644 --- a/arch/arm/src/armv7-a/arm_syscall.c +++ b/arch/arm/src/armv7-a/arm_syscall.c @@ -270,7 +270,8 @@ uint32_t *arm_syscall(uint32_t *regs) /* R0=SYS_switch_context: This a switch context command: * - * void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); + * void arm_switchcontext(uint32_t **saveregs, + * uint32_t *restoreregs); * * At this point, the following values are saved in context: * @@ -287,12 +288,9 @@ uint32_t *arm_syscall(uint32_t *regs) case SYS_switch_context: { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); -#if defined(CONFIG_ARCH_FPU) - arm_copyarmstate((uint32_t *)regs[REG_R1], regs); + arm_savefpu(regs); arm_restorefpu((uint32_t *)regs[REG_R2]); -#else - memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); -#endif + *(uint32_t **)regs[REG_R1] = regs; regs = (uint32_t *)regs[REG_R2]; } break; diff --git a/arch/arm/src/armv7-a/arm_vectors.S b/arch/arm/src/armv7-a/arm_vectors.S index fc97937ec7..a4a6bbc425 100644 --- a/arch/arm/src/armv7-a/arm_vectors.S +++ b/arch/arm/src/armv7-a/arm_vectors.S @@ -178,6 +178,19 @@ arm_vectorirq: /* Call arm_decodeirq() on the user stack */ mov r4, sp /* Save the SP in a preserved register */ + + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + */ + + sub sp, sp, #XCPTCONTEXT_SIZE /* Reserve signal context */ + bic sp, sp, #7 /* Force 8-byte alignment */ bl arm_decodeirq /* Call the handler */ mov sp, r4 /* Restore the possibly unaligned stack pointer */ @@ -283,6 +296,19 @@ arm_vectorsvc: /* Call arm_syscall() on the user stack */ mov r4, sp /* Save the SP in a preserved register */ + + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + */ + + sub sp, sp, #XCPTCONTEXT_SIZE /* Reserve signal context */ + bic sp, sp, #7 /* Force 8-byte alignment */ bl arm_syscall /* Call the handler */ mov sp, r4 /* Restore the possibly unaligned stack pointer */ diff --git a/arch/arm/src/armv7-m/arm_initialstate.c b/arch/arm/src/armv7-m/arm_initialstate.c index 7380ce0e86..02188f43a4 100644 --- a/arch/arm/src/armv7-m/arm_initialstate.c +++ b/arch/arm/src/armv7-m/arm_initialstate.c @@ -57,6 +57,10 @@ void up_initial_state(struct tcb_s *tcb) { struct xcptcontext *xcp = &tcb->xcp; + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + /* Initialize the idle thread stack */ if (tcb->pid == 0) @@ -74,16 +78,24 @@ void up_initial_state(struct tcb_s *tcb) arm_stack_color(tcb->stack_alloc_ptr, 0); #endif /* CONFIG_STACK_COLORATION */ + + return; } - /* Initialize the initial exception register context structure */ + /* Initialize the context registers to stack top */ - memset(xcp, 0, sizeof(struct xcptcontext)); + xcp->regs = (FAR void *)STACK_ALIGN_DOWN( + (uint32_t)tcb->stack_base_ptr + + tcb->adj_stack_size - + XCPTCONTEXT_SIZE); + + /* Initialize the xcp registers */ + + memset(xcp->regs, 0, XCPTCONTEXT_SIZE); /* Save the initial stack pointer */ - xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + - tcb->adj_stack_size; + xcp->regs[REG_SP] = (uint32_t)xcp->regs; #ifdef CONFIG_ARMV7M_STACKCHECK /* Set the stack limit value */ diff --git a/arch/arm/src/armv7-m/arm_schedulesigaction.c b/arch/arm/src/armv7-m/arm_schedulesigaction.c index fc27a7b7f7..9bcf40e1b3 100644 --- a/arch/arm/src/armv7-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv7-m/arm_schedulesigaction.c @@ -125,16 +125,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; -#ifdef CONFIG_ARMV7M_USEBASEPRI - tcb->xcp.saved_basepri = CURRENT_REGS[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; -#endif + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; + /* Then set up to vector to the trampoline with interrupts * disabled. The kernel-space trampoline must run in * privileged thread mode. @@ -151,11 +161,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; #endif - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } } @@ -172,16 +177,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; -#ifdef CONFIG_ARMV7M_USEBASEPRI - tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; -#endif + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; + /* Then set up to vector to the trampoline with interrupts * disabled. We must already be in privileged thread mode to be * here. @@ -272,16 +284,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; -#ifdef CONFIG_ARMV7M_USEBASEPRI - tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; -#endif + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; /* Then set up vector to the trampoline with interrupts * disabled. We must already be in privileged thread mode @@ -310,16 +329,25 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; -#ifdef CONFIG_ARMV7M_USEBASEPRI - tcb->xcp.saved_basepri = CURRENT_REGS[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; -#endif + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; /* Then set up vector to the trampoline with interrupts * disabled. The kernel-space trampoline must run in @@ -336,12 +364,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_BUILD_PROTECTED CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; #endif - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } /* Increment the IRQ lock count so that when the task is @@ -380,16 +402,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; -#ifdef CONFIG_ARMV7M_USEBASEPRI - tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; -#endif + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; + /* Increment the IRQ lock count so that when the task is restarted, * it will hold the IRQ spinlock. */ diff --git a/arch/arm/src/armv7-m/arm_sigdeliver.c b/arch/arm/src/armv7-m/arm_sigdeliver.c index d98e68c81e..94098e0367 100644 --- a/arch/arm/src/armv7-m/arm_sigdeliver.c +++ b/arch/arm/src/armv7-m/arm_sigdeliver.c @@ -53,8 +53,8 @@ void arm_sigdeliver(void) { - struct tcb_s *rtcb = this_task(); - uint32_t regs[XCPTCONTEXT_REGS]; + struct tcb_s *rtcb = this_task(); + uint32_t *regs = rtcb->xcp.saved_regs; #ifdef CONFIG_SMP /* In the SMP case, we must terminate the critical section while the signal @@ -71,10 +71,6 @@ void arm_sigdeliver(void) rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); - /* Save the return state on the stack. */ - - arm_copyfullstate(regs, rtcb->xcp.regs); - #ifdef CONFIG_SMP /* In the SMP case, up_schedule_sigaction(0) will have incremented * 'irqcount' in order to force us into a critical section. Save the @@ -147,16 +143,6 @@ void arm_sigdeliver(void) * could be modified by a hostile program. */ - regs[REG_PC] = rtcb->xcp.saved_pc; -#ifdef CONFIG_ARMV7M_USEBASEPRI - regs[REG_BASEPRI] = rtcb->xcp.saved_basepri; -#else - regs[REG_PRIMASK] = rtcb->xcp.saved_primask; -#endif - regs[REG_XPSR] = rtcb->xcp.saved_xpsr; -#ifdef CONFIG_BUILD_PROTECTED - regs[REG_LR] = rtcb->xcp.saved_lr; -#endif rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */ /* Then restore the correct state for this thread of diff --git a/arch/arm/src/armv7-m/arm_svcall.c b/arch/arm/src/armv7-m/arm_svcall.c index 7eceeaa0af..71f526f010 100644 --- a/arch/arm/src/armv7-m/arm_svcall.c +++ b/arch/arm/src/armv7-m/arm_svcall.c @@ -175,10 +175,10 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg) case SYS_save_context: { DEBUGASSERT(regs[REG_R1] != 0); - memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); #if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV7M_LAZYFPU) - arm_savefpu((uint32_t *)regs[REG_R1]); + arm_savefpu(regs); #endif + memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); } break; @@ -208,7 +208,8 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg) /* R0=SYS_switch_context: This a switch context command: * - * void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); + * void arm_switchcontext(uint32_t **saveregs, + * uint32_t *restoreregs); * * At this point, the following values are saved in context: * @@ -225,10 +226,10 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg) case SYS_switch_context: { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); - memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); #if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV7M_LAZYFPU) - arm_savefpu((uint32_t *)regs[REG_R1]); + arm_savefpu(regs); #endif + *(uint32_t **)regs[REG_R1] = regs; CURRENT_REGS = (uint32_t *)regs[REG_R2]; } break; diff --git a/arch/arm/src/armv7-m/gnu/arm_exception.S b/arch/arm/src/armv7-m/gnu/arm_exception.S index db23b854bb..8836f40308 100644 --- a/arch/arm/src/armv7-m/gnu/arm_exception.S +++ b/arch/arm/src/armv7-m/gnu/arm_exception.S @@ -200,7 +200,21 @@ exception_common: setintstack r2, r3 /* SP = IRQ stack top */ + bl arm_doirq /* R0=IRQ, R1=register save (msp) */ #else + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + * also the sp should be restore after arm_doirq() + */ + + sub r4, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */ + /* Otherwise, we will re-use the interrupted thread's stack. That may * mean using either MSP or PSP stack for interrupt level processing (in * kernel mode). @@ -209,9 +223,13 @@ exception_common: bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */ mov sp, r2 /* Instantiate the aligned stack */ + bl arm_doirq /* R0=IRQ, R1=register save (msp) */ + + /* If the interrupt stack is disabled, restore the signal context */ + + add r4, r4, #XCPTCONTEXT_SIZE /* Restore signal context */ #endif - bl arm_doirq /* R0=IRQ, R1=register save (msp) */ mov r1, r4 /* Recover R1=main stack pointer */ /* On return from arm_doirq, R0 will hold a pointer to register context diff --git a/arch/arm/src/armv7-m/gnu/arm_lazyexception.S b/arch/arm/src/armv7-m/gnu/arm_lazyexception.S index 968c77a451..9cf57816ca 100644 --- a/arch/arm/src/armv7-m/gnu/arm_lazyexception.S +++ b/arch/arm/src/armv7-m/gnu/arm_lazyexception.S @@ -194,7 +194,21 @@ exception_common: setintstack r2, r3 /* SP = IRQ stack top */ + bl arm_doirq /* R0=IRQ, R1=register save (msp) */ #else + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + * also the sp should be restore after arm_doirq() + */ + + sub r4, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */ + /* Otherwise, we will re-use the interrupted thread's stack. That may * mean using either MSP or PSP stack for interrupt level processing (in * kernel mode). @@ -203,9 +217,13 @@ exception_common: bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */ mov sp, r2 /* Instantiate the aligned stack */ + bl arm_doirq /* R0=IRQ, R1=register save (msp) */ + + /* If the interrupt stack is disabled, restore the signal context */ + + add r4, r4, #XCPTCONTEXT_SIZE /* Restore signal context */ #endif - bl arm_doirq /* R0=IRQ, R1=register save (msp) */ mov r1, r4 /* Recover R1=main stack pointer */ /* On return from arm_doirq, R0 will hold a pointer to register context diff --git a/arch/arm/src/armv7-r/arm_initialstate.c b/arch/arm/src/armv7-r/arm_initialstate.c index 60c8070bd0..a4834c4892 100644 --- a/arch/arm/src/armv7-r/arm_initialstate.c +++ b/arch/arm/src/armv7-r/arm_initialstate.c @@ -55,6 +55,10 @@ void up_initial_state(struct tcb_s *tcb) struct xcptcontext *xcp = &tcb->xcp; uint32_t cpsr; + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + /* Initialize the idle thread stack */ if (tcb->pid == 0) @@ -72,16 +76,24 @@ void up_initial_state(struct tcb_s *tcb) arm_stack_color(tcb->stack_alloc_ptr, 0); #endif /* CONFIG_STACK_COLORATION */ + + return; } - /* Initialize the initial exception register context structure */ + /* Initialize the context registers to stack top */ - memset(xcp, 0, sizeof(struct xcptcontext)); + xcp->regs = (FAR void *)STACK_ALIGN_DOWN( + (uint32_t)tcb->stack_base_ptr + + tcb->adj_stack_size - + XCPTCONTEXT_SIZE); + + /* Initialize the xcp registers */ + + memset(xcp->regs, 0, XCPTCONTEXT_SIZE); /* Save the initial stack pointer */ - xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + - tcb->adj_stack_size; + xcp->regs[REG_SP] = (uint32_t)xcp->regs; /* Save the task entry point */ diff --git a/arch/arm/src/armv7-r/arm_schedulesigaction.c b/arch/arm/src/armv7-r/arm_schedulesigaction.c index b668e0ddd9..284ca3d057 100644 --- a/arch/arm/src/armv7-r/arm_schedulesigaction.c +++ b/arch/arm/src/armv7-r/arm_schedulesigaction.c @@ -122,8 +122,25 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; - tcb->xcp.saved_cpsr = CURRENT_REGS[REG_CPSR]; + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; /* Then set up to vector to the trampoline with interrupts * disabled @@ -134,14 +151,8 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) PSR_F_BIT); #ifdef CONFIG_ENDIAN_BIG - CURRENT_REGS[REG_CPSR] |= PSR_E_BIT; + CURRENT_REGS[REG_CPSR] |= PSR_E_BIT; #endif - - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } } @@ -157,9 +168,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) * have been delivered. */ - tcb->xcp.sigdeliver = sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; - tcb->xcp.saved_cpsr = tcb->xcp.regs[REG_CPSR]; + tcb->xcp.sigdeliver = sigdeliver; + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; /* Then set up to vector to the trampoline with interrupts * disabled @@ -170,7 +195,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) PSR_F_BIT); #ifdef CONFIG_ENDIAN_BIG - tcb->xcp.regs[REG_CPSR] |= PSR_E_BIT; + tcb->xcp.regs[REG_CPSR] |= PSR_E_BIT; #endif } } diff --git a/arch/arm/src/armv7-r/arm_sigdeliver.c b/arch/arm/src/armv7-r/arm_sigdeliver.c index 5ebf367ae7..6699aaa777 100644 --- a/arch/arm/src/armv7-r/arm_sigdeliver.c +++ b/arch/arm/src/armv7-r/arm_sigdeliver.c @@ -54,7 +54,7 @@ void arm_sigdeliver(void) { struct tcb_s *rtcb = this_task(); - uint32_t regs[XCPTCONTEXT_REGS]; + uint32_t *regs = rtcb->xcp.saved_regs; board_autoled_on(LED_SIGNAL); @@ -62,10 +62,6 @@ void arm_sigdeliver(void) rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); - /* Save the return state on the stack. */ - - arm_copyfullstate(regs, rtcb->xcp.regs); - #ifndef CONFIG_SUPPRESS_INTERRUPTS /* Then make sure that interrupts are enabled. Signal handlers must always * run with interrupts enabled. @@ -96,8 +92,6 @@ void arm_sigdeliver(void) * could be modified by a hostile program. */ - regs[REG_PC] = rtcb->xcp.saved_pc; - regs[REG_CPSR] = rtcb->xcp.saved_cpsr; rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */ /* Then restore the correct state for this thread of execution. */ diff --git a/arch/arm/src/armv7-r/arm_syscall.c b/arch/arm/src/armv7-r/arm_syscall.c index 0311803abb..4a52d0191b 100644 --- a/arch/arm/src/armv7-r/arm_syscall.c +++ b/arch/arm/src/armv7-r/arm_syscall.c @@ -267,7 +267,8 @@ uint32_t *arm_syscall(uint32_t *regs) /* R0=SYS_switch_context: This a switch context command: * - * void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); + * void arm_switchcontext(uint32_t **saveregs, + * uint32_t *restoreregs); * * At this point, the following values are saved in context: * @@ -284,12 +285,9 @@ uint32_t *arm_syscall(uint32_t *regs) case SYS_switch_context: { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); -#if defined(CONFIG_ARCH_FPU) - arm_copyarmstate((uint32_t *)regs[REG_R1], regs); + arm_savefpu(regs); arm_restorefpu((uint32_t *)regs[REG_R2]); -#else - memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); -#endif + *(uint32_t **)regs[REG_R1] = regs; regs = (uint32_t *)regs[REG_R2]; } break; diff --git a/arch/arm/src/armv7-r/arm_vectors.S b/arch/arm/src/armv7-r/arm_vectors.S index 319209a27e..68e47faa13 100644 --- a/arch/arm/src/armv7-r/arm_vectors.S +++ b/arch/arm/src/armv7-r/arm_vectors.S @@ -132,6 +132,19 @@ arm_vectorirq: /* Call arm_decodeirq() on the user stack */ mov r4, sp /* Save the SP in a preserved register */ + + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + */ + + sub sp, sp, #XCPTCONTEXT_SIZE /* Reserve signal context */ + bic sp, sp, #7 /* Force 8-byte alignment */ bl arm_decodeirq /* Call the handler */ mov sp, r4 /* Restore the possibly unaligned stack pointer */ @@ -237,6 +250,19 @@ arm_vectorsvc: /* Call arm_syscall() on the user stack */ mov r4, sp /* Save the SP in a preserved register */ + + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + */ + + sub sp, sp, #XCPTCONTEXT_SIZE /* Reserve signal context */ + bic sp, sp, #7 /* Force 8-byte alignment */ bl arm_syscall /* Call the handler */ mov sp, r4 /* Restore the possibly unaligned stack pointer */ diff --git a/arch/arm/src/armv8-m/arm_exception.S b/arch/arm/src/armv8-m/arm_exception.S index 6a3a958cc7..aa81280220 100644 --- a/arch/arm/src/armv8-m/arm_exception.S +++ b/arch/arm/src/armv8-m/arm_exception.S @@ -216,7 +216,21 @@ exception_common: setintstack r2, r3 /* SP = IRQ stack top */ + bl arm_doirq /* R0=IRQ, R1=register save (msp) */ #else + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + * also the sp should be restore after arm_doirq() + */ + + sub r4, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */ + /* Otherwise, we will re-use the interrupted thread's stack. That may * mean using either MSP or PSP stack for interrupt level processing (in * kernel mode). @@ -225,9 +239,13 @@ exception_common: bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */ mov sp, r2 /* Instantiate the aligned stack */ + bl arm_doirq /* R0=IRQ, R1=register save (msp) */ + + /* If the interrupt stack is disabled, restore the signal context */ + + add r4, r4, #XCPTCONTEXT_SIZE /* Restore signal context */ #endif - bl arm_doirq /* R0=IRQ, R1=register save (msp) */ mov r1, r4 /* Recover R1=main stack pointer */ /* On return from arm_doirq, R0 will hold a pointer to register context diff --git a/arch/arm/src/armv8-m/arm_initialstate.c b/arch/arm/src/armv8-m/arm_initialstate.c index 81a6959d52..b6a32474ee 100644 --- a/arch/arm/src/armv8-m/arm_initialstate.c +++ b/arch/arm/src/armv8-m/arm_initialstate.c @@ -57,6 +57,10 @@ void up_initial_state(struct tcb_s *tcb) { struct xcptcontext *xcp = &tcb->xcp; + /* Initialize the initial exception register context structure */ + + memset(xcp, 0, sizeof(struct xcptcontext)); + /* Initialize the idle thread stack */ if (tcb->pid == 0) @@ -74,16 +78,24 @@ void up_initial_state(struct tcb_s *tcb) arm_stack_color(tcb->stack_alloc_ptr, 0); #endif /* CONFIG_STACK_COLORATION */ + + return; } - /* Initialize the initial exception register context structure */ + /* Initialize the context registers to stack top */ - memset(xcp, 0, sizeof(struct xcptcontext)); + xcp->regs = (FAR void *)STACK_ALIGN_DOWN( + (uint32_t)tcb->stack_base_ptr + + tcb->adj_stack_size - + XCPTCONTEXT_SIZE); + + /* Initialize the xcp registers */ + + memset(xcp->regs, 0, XCPTCONTEXT_SIZE); /* Save the initial stack pointer */ - xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + - tcb->adj_stack_size; + xcp->regs[REG_SP] = (uint32_t)xcp->regs; #ifdef CONFIG_ARMV8M_STACKCHECK /* Set the stack limit value */ diff --git a/arch/arm/src/armv8-m/arm_lazyexception.S b/arch/arm/src/armv8-m/arm_lazyexception.S index fd6ed95483..d70e2bd8af 100644 --- a/arch/arm/src/armv8-m/arm_lazyexception.S +++ b/arch/arm/src/armv8-m/arm_lazyexception.S @@ -211,7 +211,21 @@ exception_common: setintstack r2, r3 /* SP = IRQ stack top */ + bl arm_doirq /* R0=IRQ, R1=register save (msp) */ #else + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + * also the sp should be restore after arm_doirq() + */ + + sub r4, r4, #XCPTCONTEXT_SIZE /* Reserve signal context */ + /* Otherwise, we will re-use the interrupted thread's stack. That may * mean using either MSP or PSP stack for interrupt level processing (in * kernel mode). @@ -220,9 +234,13 @@ exception_common: bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */ mov sp, r2 /* Instantiate the aligned stack */ + bl arm_doirq /* R0=IRQ, R1=register save (msp) */ + + /* If the interrupt stack is disabled, restore the signal context */ + + add r4, r4, #XCPTCONTEXT_SIZE /* Restore signal context */ #endif - bl arm_doirq /* R0=IRQ, R1=register save (msp) */ mov r1, r4 /* Recover R1=main stack pointer */ /* On return from arm_doirq, R0 will hold a pointer to register context diff --git a/arch/arm/src/armv8-m/arm_schedulesigaction.c b/arch/arm/src/armv8-m/arm_schedulesigaction.c index 8926dda840..228efadd64 100644 --- a/arch/arm/src/armv8-m/arm_schedulesigaction.c +++ b/arch/arm/src/armv8-m/arm_schedulesigaction.c @@ -125,16 +125,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; -#ifdef CONFIG_ARMV8M_USEBASEPRI - tcb->xcp.saved_basepri = CURRENT_REGS[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; -#endif + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; + /* Then set up to vector to the trampoline with interrupts * disabled. The kernel-space trampoline must run in * privileged thread mode. @@ -151,11 +161,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; #endif - /* And make sure that the saved context in the TCB is the same - * as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } } @@ -172,16 +177,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; -#ifdef CONFIG_ARMV8M_USEBASEPRI - tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; -#endif + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; + /* Then set up to vector to the trampoline with interrupts * disabled. We must already be in privileged thread mode to be * here. @@ -272,16 +284,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; -#ifdef CONFIG_ARMV8M_USEBASEPRI - tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; -#endif + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; /* Then set up vector to the trampoline with interrupts * disabled. We must already be in privileged thread mode @@ -310,16 +329,25 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = CURRENT_REGS[REG_PC]; -#ifdef CONFIG_ARMV8M_USEBASEPRI - tcb->xcp.saved_basepri = CURRENT_REGS[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; -#endif + + /* 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. + */ + + CURRENT_REGS = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)CURRENT_REGS - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy((FAR uint32_t *)CURRENT_REGS, tcb->xcp.saved_regs, + XCPTCONTEXT_SIZE); + + CURRENT_REGS[REG_SP] = (uint32_t)CURRENT_REGS; /* Then set up vector to the trampoline with interrupts * disabled. The kernel-space trampoline must run in @@ -336,12 +364,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) #ifdef CONFIG_BUILD_PROTECTED CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; #endif - - /* And make sure that the saved context in the TCB is the - * same as the interrupt return context. - */ - - arm_savestate(tcb->xcp.regs); } /* Increment the IRQ lock count so that when the task is @@ -384,16 +406,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver) */ tcb->xcp.sigdeliver = (FAR void *)sigdeliver; - tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC]; -#ifdef CONFIG_ARMV8M_USEBASEPRI - tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI]; -#else - tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; -#endif - tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; -#ifdef CONFIG_BUILD_PROTECTED - tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; -#endif + + /* 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 = + (FAR void *)STACK_ALIGN_DOWN((uint32_t)tcb->xcp.regs - + (uint32_t)XCPTCONTEXT_SIZE); + memcpy(tcb->xcp.regs, tcb->xcp.saved_regs, XCPTCONTEXT_SIZE); + + tcb->xcp.regs[REG_SP] = (uint32_t)tcb->xcp.regs; + /* Increment the IRQ lock count so that when the task is restarted, * it will hold the IRQ spinlock. */ diff --git a/arch/arm/src/armv8-m/arm_sigdeliver.c b/arch/arm/src/armv8-m/arm_sigdeliver.c index 183d00eceb..717a7009f6 100644 --- a/arch/arm/src/armv8-m/arm_sigdeliver.c +++ b/arch/arm/src/armv8-m/arm_sigdeliver.c @@ -53,8 +53,8 @@ void arm_sigdeliver(void) { - struct tcb_s *rtcb = this_task(); - uint32_t regs[XCPTCONTEXT_REGS]; + struct tcb_s *rtcb = this_task(); + uint32_t *regs = rtcb->xcp.saved_regs; #ifdef CONFIG_SMP /* In the SMP case, we must terminate the critical section while the signal @@ -71,10 +71,6 @@ void arm_sigdeliver(void) rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); - /* Save the return state on the stack. */ - - arm_copyfullstate(regs, rtcb->xcp.regs); - #ifdef CONFIG_SMP /* In the SMP case, up_schedule_sigaction(0) will have incremented * 'irqcount' in order to force us into a critical section. Save the @@ -147,16 +143,6 @@ void arm_sigdeliver(void) * could be modified by a hostile program. */ - regs[REG_PC] = rtcb->xcp.saved_pc; -#ifdef CONFIG_ARMV8M_USEBASEPRI - regs[REG_BASEPRI] = rtcb->xcp.saved_basepri; -#else - regs[REG_PRIMASK] = rtcb->xcp.saved_primask; -#endif - regs[REG_XPSR] = rtcb->xcp.saved_xpsr; -#ifdef CONFIG_BUILD_PROTECTED - regs[REG_LR] = rtcb->xcp.saved_lr; -#endif rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */ /* Then restore the correct state for this thread of diff --git a/arch/arm/src/armv8-m/arm_svcall.c b/arch/arm/src/armv8-m/arm_svcall.c index ae1e80ceab..351b1adcb7 100644 --- a/arch/arm/src/armv8-m/arm_svcall.c +++ b/arch/arm/src/armv8-m/arm_svcall.c @@ -174,10 +174,10 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg) case SYS_save_context: { DEBUGASSERT(regs[REG_R1] != 0); - memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); #if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV8M_LAZYFPU) - arm_savefpu((uint32_t *)regs[REG_R1]); + arm_savefpu(regs); #endif + memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); } break; @@ -207,7 +207,8 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg) /* R0=SYS_switch_context: This a switch context command: * - * void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); + * void arm_switchcontext(uint32_t **saveregs, + * uint32_t *restoreregs); * * At this point, the following values are saved in context: * @@ -224,10 +225,10 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg) case SYS_switch_context: { DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); - memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE); #if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV8M_LAZYFPU) - arm_savefpu((uint32_t *)regs[REG_R1]); + arm_savefpu(regs); #endif + *(uint32_t **)regs[REG_R1] = regs; CURRENT_REGS = (uint32_t *)regs[REG_R2]; } break; diff --git a/arch/arm/src/c5471/c5471_vectors.S b/arch/arm/src/c5471/c5471_vectors.S index d633f77009..1965545a07 100644 --- a/arch/arm/src/c5471/c5471_vectors.S +++ b/arch/arm/src/c5471/c5471_vectors.S @@ -150,7 +150,21 @@ arm_vectorirq: bl arm_doirq /* Call the handler */ ldr sp, [sp] /* Restore the user stack pointer */ #else - bl arm_doirq /* Call the handler */ + /* If the interrupt stack is disabled, reserve xcpcontext to ensure + * that signal processing can have a separate xcpcontext to handle + * signal context (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ------------------- + * | Signal XCP context | + * ---------------------- <- SP + */ + + sub sp, sp, #XCPTCONTEXT_SIZE /* Reserve signal context */ + + bl arm_doirq /* Call the handler */ + + add sp, sp, #XCPTCONTEXT_SIZE /* Restore signal context */ #endif /* Restore the CPSR, SYS mode registers and return */ diff --git a/arch/arm/src/common/arm_blocktask.c b/arch/arm/src/common/arm_blocktask.c index 6187b8565e..46986634c0 100644 --- a/arch/arm/src/common/arm_blocktask.c +++ b/arch/arm/src/common/arm_blocktask.c @@ -148,7 +148,7 @@ void up_block_task(struct tcb_s *tcb, tstate_t task_state) * ready to run list. */ - arm_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + arm_switchcontext(&rtcb->xcp.regs, nexttcb->xcp.regs); /* arm_switchcontext forces a context switch to the task at the * head of the ready-to-run list. It does not 'return' in the diff --git a/arch/arm/src/common/arm_internal.h b/arch/arm/src/common/arm_internal.h index cbd2ba6de2..7e28918caa 100644 --- a/arch/arm/src/common/arm_internal.h +++ b/arch/arm/src/common/arm_internal.h @@ -105,10 +105,11 @@ * applies if "lazy" floating point register save/restore is used */ -# if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV7M_LAZYFPU) -# define arm_savestate(regs) arm_copyarmstate(regs, (uint32_t*)CURRENT_REGS) +# if defined(CONFIG_ARCH_FPU) && (defined(CONFIG_ARMV7M_LAZYFPU) || \ + defined(CONFIG_ARMV8M_LAZYFPU)) +# define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS, arm_savefpu(regs)) # else -# define arm_savestate(regs) arm_copyfullstate(regs, (uint32_t*)CURRENT_REGS) +# define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS) # endif # define arm_restorestate(regs) (CURRENT_REGS = regs) @@ -123,9 +124,9 @@ */ # if defined(CONFIG_ARCH_FPU) -# define arm_savestate(regs) arm_copyarmstate(regs, (uint32_t*)CURRENT_REGS) +# define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS, arm_savefpu(regs)) # else -# define arm_savestate(regs) arm_copyfullstate(regs, (uint32_t*)CURRENT_REGS) +# define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS) # endif # define arm_restorestate(regs) (CURRENT_REGS = regs) @@ -142,11 +143,11 @@ */ # if defined(CONFIG_ARCH_FPU) -# define arm_savestate(regs) arm_copyarmstate(regs, (uint32_t*)CURRENT_REGS) +# define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS, arm_savefpu(regs)) # else -# define arm_savestate(regs) arm_copyfullstate(regs, (uint32_t*)CURRENT_REGS) +# define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS) # endif -# define arm_restorestate(regs) arm_copyfullstate((uint32_t*)CURRENT_REGS, regs) +# define arm_restorestate(regs) (CURRENT_REGS = regs) #endif @@ -333,7 +334,7 @@ void arm_copyarmstate(uint32_t *dest, uint32_t *src); uint32_t *arm_decodeirq(uint32_t *regs); int arm_saveusercontext(uint32_t *saveregs); void arm_fullcontextrestore(uint32_t *restoreregs) noreturn_function; -void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs); +void arm_switchcontext(uint32_t **saveregs, uint32_t *restoreregs); /* Signal handling **********************************************************/ diff --git a/arch/arm/src/common/arm_releasepending.c b/arch/arm/src/common/arm_releasepending.c index c4b3646bc2..6a50f3f999 100644 --- a/arch/arm/src/common/arm_releasepending.c +++ b/arch/arm/src/common/arm_releasepending.c @@ -115,7 +115,7 @@ void up_release_pending(void) * ready to run list. */ - arm_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + arm_switchcontext(&rtcb->xcp.regs, nexttcb->xcp.regs); /* arm_switchcontext forces a context switch to the task at the * head of the ready-to-run list. It does not 'return' in the diff --git a/arch/arm/src/common/arm_reprioritizertr.c b/arch/arm/src/common/arm_reprioritizertr.c index 054f03b4f6..3f223b72cc 100644 --- a/arch/arm/src/common/arm_reprioritizertr.c +++ b/arch/arm/src/common/arm_reprioritizertr.c @@ -170,7 +170,7 @@ void up_reprioritize_rtr(struct tcb_s *tcb, uint8_t priority) * ready to run list. */ - arm_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + arm_switchcontext(&rtcb->xcp.regs, nexttcb->xcp.regs); /* arm_switchcontext forces a context switch to the task at the * head of the ready-to-run list. It does not 'return' in the diff --git a/arch/arm/src/common/arm_switchcontext.c b/arch/arm/src/common/arm_switchcontext.c index 3a1c5684da..1cf965f7dd 100644 --- a/arch/arm/src/common/arm_switchcontext.c +++ b/arch/arm/src/common/arm_switchcontext.c @@ -41,7 +41,7 @@ * ****************************************************************************/ -void arm_switchcontext(uint32_t *saveregs, uint32_t *restoreregs) +void arm_switchcontext(uint32_t **saveregs, uint32_t *restoreregs) { sys_call2(SYS_switch_context, (uintptr_t)saveregs, (uintptr_t)restoreregs); } diff --git a/arch/arm/src/common/arm_unblocktask.c b/arch/arm/src/common/arm_unblocktask.c index 86d96e0949..47357f253a 100644 --- a/arch/arm/src/common/arm_unblocktask.c +++ b/arch/arm/src/common/arm_unblocktask.c @@ -132,7 +132,7 @@ void up_unblock_task(struct tcb_s *tcb) * ready to run list. */ - arm_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); + arm_switchcontext(&rtcb->xcp.regs, nexttcb->xcp.regs); /* arm_switchcontext forces a context switch to the task at the * head of the ready-to-run list. It does not 'return' in the diff --git a/arch/arm/src/common/arm_vfork.c b/arch/arm/src/common/arm_vfork.c index 10b38b10b7..f265aaf51b 100644 --- a/arch/arm/src/common/arm_vfork.c +++ b/arch/arm/src/common/arm_vfork.c @@ -36,6 +36,7 @@ #include #include "arm_vfork.h" +#include "arm_internal.h" #include "sched/sched.h" /**************************************************************************** @@ -136,8 +137,9 @@ pid_t up_vfork(const struct vfork_s *context) * effort is overkill. */ - newtop = (uint32_t)child->cmn.stack_base_ptr + - child->cmn.adj_stack_size; + newtop = STACK_ALIGN_DOWN((uint32_t)child->cmn.stack_base_ptr + + child->cmn.adj_stack_size - + XCPTCONTEXT_SIZE); newsp = newtop - stackutil; memcpy((void *)newsp, (const void *)context->sp, stackutil); diff --git a/arch/arm/src/phy62xx/phy62xx_exception.S b/arch/arm/src/phy62xx/phy62xx_exception.S index 468277f2dd..ea1b198312 100644 --- a/arch/arm/src/phy62xx/phy62xx_exception.S +++ b/arch/arm/src/phy62xx/phy62xx_exception.S @@ -100,13 +100,24 @@ exception_common: mrs r0, ipsr /* R0=exception number */ - /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt - * stack pointer. The way that this is done here prohibits nested interrupts! - * Otherwise, we will use the stack that was current when the interrupt was taken. + /* Reserve xcpcontext to ensure that signal processing can have + * a separate xcpcontext to handle signal context + * (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ---------------------- + * | Signal XCP context | + * ---------------------- <- SP + * also the sp should be restore after arm_doirq() */ + sub r1, r1, #XCPTCONTEXT_SIZE /* Reserve signal context */ + msr msp, r1 /* We are using the main stack pointer */ bl arm_doirq /* R0=IRQ, R1=register save area on stack */ + + add r1, r1, #XCPTCONTEXT_SIZE /* Restore signal context */ + mrs r1, msp /* Recover R1=main stack pointer */ /* On return from arm_doirq, R0 will hold a pointer to register context @@ -252,13 +263,24 @@ exception_common_inline: mrs r0, ipsr /* R0=exception number */ - /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt - * stack pointer. The way that this is done here prohibits nested interrupts! - * Otherwise, we will use the stack that was current when the interrupt was taken. + /* Reserve xcpcontext to ensure that signal processing can have + * a separate xcpcontext to handle signal context + * (reference: arm_schedulesigaction.c): + * ---------------------- + * | IRQ XCP context | + * ---------------------- + * | Signal XCP context | + * ---------------------- <- SP + * also the sp should be restore after arm_doirq() */ + sub r1, r1, #XCPTCONTEXT_SIZE /* Reserve signal context */ + msr msp, r1 /* We are using the main stack pointer */ bl arm_doirq /* R0=IRQ, R1=register save area on stack */ + + add r1, r1, #XCPTCONTEXT_SIZE /* Restore signal context */ + mrs r1, msp /* Recover R1=main stack pointer */ /* On return from arm_doirq, R0 will hold a pointer to register context