From 7b9978883c46569068ba5dac5755f998fbd237b2 Mon Sep 17 00:00:00 2001 From: "chao.an" Date: Tue, 1 Mar 2022 01:06:24 +0800 Subject: [PATCH] arch/arm: optimize context switch speed The current context save implementation saves registers of each task to xcp context, which is unnecessary because most of the arm registers are already saved in the task stack, this commit replace the xcp context with stack context to improve context switching performance and reduce the tcb space occupation of tcb instance. Signed-off-by: chao.an --- arch/arm/include/arm/irq.h | 18 +-- arch/arm/include/armv6-m/irq.h | 22 ++- arch/arm/include/armv7-a/irq.h | 19 ++- arch/arm/include/armv7-m/irq.h | 26 ++-- arch/arm/include/armv7-r/irq.h | 19 ++- arch/arm/include/armv8-m/irq.h | 26 ++-- arch/arm/include/syscall.h | 2 +- arch/arm/src/arm/arm_initialstate.c | 22 ++- arch/arm/src/arm/arm_schedulesigaction.c | 51 +++++-- arch/arm/src/arm/arm_sigdeliver.c | 10 +- arch/arm/src/arm/arm_syscall.c | 5 +- arch/arm/src/arm/arm_vectors.S | 19 ++- arch/arm/src/armv6-m/arm_exception.S | 17 +++ arch/arm/src/armv6-m/arm_initialstate.c | 20 ++- arch/arm/src/armv6-m/arm_schedulesigaction.c | 131 +++++++++++----- arch/arm/src/armv6-m/arm_sigdeliver.c | 17 +-- arch/arm/src/armv6-m/arm_svcall.c | 5 +- arch/arm/src/armv7-a/arm_cpuhead.S | 5 + arch/arm/src/armv7-a/arm_initialstate.c | 20 ++- arch/arm/src/armv7-a/arm_schedulesigaction.c | 111 +++++++++++--- arch/arm/src/armv7-a/arm_sigdeliver.c | 10 +- arch/arm/src/armv7-a/arm_syscall.c | 10 +- arch/arm/src/armv7-a/arm_vectors.S | 26 ++++ arch/arm/src/armv7-m/arm_initialstate.c | 20 ++- arch/arm/src/armv7-m/arm_schedulesigaction.c | 151 +++++++++++-------- arch/arm/src/armv7-m/arm_sigdeliver.c | 18 +-- arch/arm/src/armv7-m/arm_svcall.c | 11 +- arch/arm/src/armv7-m/gnu/arm_exception.S | 20 ++- arch/arm/src/armv7-m/gnu/arm_lazyexception.S | 20 ++- arch/arm/src/armv7-r/arm_initialstate.c | 20 ++- arch/arm/src/armv7-r/arm_schedulesigaction.c | 51 +++++-- arch/arm/src/armv7-r/arm_sigdeliver.c | 8 +- arch/arm/src/armv7-r/arm_syscall.c | 10 +- arch/arm/src/armv7-r/arm_vectors.S | 26 ++++ arch/arm/src/armv8-m/arm_exception.S | 20 ++- arch/arm/src/armv8-m/arm_initialstate.c | 20 ++- arch/arm/src/armv8-m/arm_lazyexception.S | 20 ++- arch/arm/src/armv8-m/arm_schedulesigaction.c | 151 +++++++++++-------- arch/arm/src/armv8-m/arm_sigdeliver.c | 18 +-- arch/arm/src/armv8-m/arm_svcall.c | 11 +- arch/arm/src/c5471/c5471_vectors.S | 16 +- arch/arm/src/common/arm_blocktask.c | 2 +- arch/arm/src/common/arm_internal.h | 19 +-- arch/arm/src/common/arm_releasepending.c | 2 +- arch/arm/src/common/arm_reprioritizertr.c | 2 +- arch/arm/src/common/arm_switchcontext.c | 2 +- arch/arm/src/common/arm_unblocktask.c | 2 +- arch/arm/src/common/arm_vfork.c | 6 +- arch/arm/src/phy62xx/phy62xx_exception.S | 34 ++++- 49 files changed, 851 insertions(+), 440 deletions(-) diff --git a/arch/arm/include/arm/irq.h b/arch/arm/include/arm/irq.h index 376288220e0..62cbed6a0a1 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 104828b26ca..b5e59b64e89 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 7bbc7870cde..f2994162765 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 96fd94c1f04..e965fc7ab1d 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 5acced1f555..b0205040370 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 a89de9078ca..5395484d9d2 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 b998da7e045..1b1289a0a9d 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 4bd69fc551f..df5a2c0333e 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 1427ba039b2..9e37043162b 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 153e4cb733f..21a0b98baac 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 e4b9c9857ae..06687dfd495 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 838412e04da..e6f4d047ef4 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 b71a912bbb6..c438bf595ee 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 9f9683990e9..b1d28df81c3 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 41d7614dc6e..23e4290628d 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 fd683e0e7ed..164318865b2 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 701541bcafb..1ccf869bc96 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 373fd12a1f3..70f29a08865 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 cbc086d764b..91a7eaefeea 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 a41368044fa..aaf03c03f88 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 aeea069ae67..856f216c0ce 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 c571b73ac92..0ac7c8c636f 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 fc97937ec77..a4a6bbc4256 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 7380ce0e86d..02188f43a4d 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 fc27a7b7f76..9bcf40e1b33 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 d98e68c81ed..94098e03674 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 7eceeaa0af8..71f526f010a 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 db23b854bb0..8836f40308c 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 968c77a451b..9cf57816ca1 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 60c8070bd00..a4834c4892e 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 b668e0ddd95..284ca3d0578 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 5ebf367ae74..6699aaa777c 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 0311803abb6..4a52d0191bb 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 319209a27e4..68e47faa13f 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 6a3a958cc7f..aa812802205 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 81a6959d521..b6a32474eed 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 fd6ed954831..d70e2bd8af7 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 8926dda8402..228efadd648 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 183d00eceba..717a7009f6d 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 ae1e80ceab2..351b1adcb7c 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 d633f77009e..1965545a073 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 6187b8565e4..46986634c00 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 cbd2ba6de25..7e28918caaf 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 c4b3646bc2b..6a50f3f9993 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 054f03b4f65..3f223b72cc1 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 3a1c5684da8..1cf965f7dd5 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 86d96e09492..47357f253aa 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 10b38b10b75..f265aaf51bf 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 468277f2dd8..ea1b1983122 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