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 <anchao@xiaomi.com>
This commit is contained in:
chao.an 2022-03-01 01:06:24 +08:00 committed by Masayuki Ishikawa
parent f30fa2fe57
commit 7b9978883c
49 changed files with 851 additions and 440 deletions

View File

@ -133,21 +133,19 @@ struct xcptcontext
void *sigdeliver; /* Actual type is sig_deliver_t */ 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. * 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_regs;
uint32_t saved_cpsr;
/* 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 /* 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]; * case of the prefetch abort, this value is the same as regs[REG_R15];

View File

@ -165,21 +165,13 @@ struct xcptcontext
void *sigdeliver; /* Actual type is sig_deliver_t */ 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. * 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_regs;
uint32_t saved_primask;
uint32_t saved_xpsr;
#ifdef CONFIG_BUILD_PROTECTED
uint32_t saved_lr;
#ifdef CONFIG_BUILD_PROTECTED
/* This is the saved address to use when returning from a user-space /* This is the saved address to use when returning from a user-space
* signal handler. * signal handler.
*/ */
@ -196,9 +188,13 @@ struct xcptcontext
struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST]; struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST];
#endif #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 #endif

View File

@ -245,16 +245,11 @@ struct xcptcontext
void *sigdeliver; /* Actual type is sig_deliver_t */ void *sigdeliver; /* Actual type is sig_deliver_t */
/* These are saved copies of LR and CPSR used during signal processing. /* 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_regs;
uint32_t saved_cpsr;
#ifdef CONFIG_BUILD_KERNEL #ifdef CONFIG_BUILD_KERNEL
/* This is the saved address to use when returning from a user-space /* This is the saved address to use when returning from a user-space
@ -265,9 +260,13 @@ struct xcptcontext
#endif #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 /* 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]; * case of the pre-fetch abort, this value is the same as regs[REG_R15];

View File

@ -120,25 +120,13 @@ struct xcptcontext
FAR void *sigdeliver; /* Actual type is sig_deliver_t */ 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. * 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_regs;
#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;
#ifdef CONFIG_BUILD_PROTECTED
/* This is the saved address to use when returning from a user-space /* This is the saved address to use when returning from a user-space
* signal handler. * signal handler.
*/ */
@ -157,9 +145,13 @@ struct xcptcontext
#endif #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 #endif

View File

@ -245,16 +245,11 @@ struct xcptcontext
void *sigdeliver; /* Actual type is sig_deliver_t */ void *sigdeliver; /* Actual type is sig_deliver_t */
/* These are saved copies of LR and CPSR used during signal processing. /* 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_regs;
uint32_t saved_cpsr;
#ifdef CONFIG_BUILD_KERNEL #ifdef CONFIG_BUILD_KERNEL
/* This is the saved address to use when returning from a user-space /* This is the saved address to use when returning from a user-space
@ -264,9 +259,13 @@ struct xcptcontext
uint32_t sigreturn; uint32_t sigreturn;
#endif #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 /* 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]; * case of the pre-fetch abort, this value is the same as regs[REG_R15];

View File

@ -125,25 +125,13 @@ struct xcptcontext
FAR void *sigdeliver; /* Actual type is sig_deliver_t */ 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. * 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_regs;
#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;
#ifdef CONFIG_BUILD_PROTECTED
/* This is the saved address to use when returning from a user-space /* This is the saved address to use when returning from a user-space
* signal handler. * signal handler.
*/ */
@ -162,9 +150,13 @@ struct xcptcontext
#endif #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 #endif

View File

@ -80,7 +80,7 @@
/* SYS call 2: /* 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) #define SYS_switch_context (2)

View File

@ -55,6 +55,10 @@ void up_initial_state(struct tcb_s *tcb)
struct xcptcontext *xcp = &tcb->xcp; struct xcptcontext *xcp = &tcb->xcp;
uint32_t cpsr; uint32_t cpsr;
/* Initialize the initial exception register context structure */
memset(xcp, 0, sizeof(struct xcptcontext));
/* Initialize the idle thread stack */ /* Initialize the idle thread stack */
if (tcb->pid == 0) if (tcb->pid == 0)
@ -72,20 +76,28 @@ void up_initial_state(struct tcb_s *tcb)
arm_stack_color(tcb->stack_alloc_ptr, 0); arm_stack_color(tcb->stack_alloc_ptr, 0);
#endif /* CONFIG_STACK_COLORATION */ #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 */ /* Save the initial stack pointer */
xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + xcp->regs[REG_SP] = (uint32_t)xcp->regs;
tcb->adj_stack_size;
/* Save the task entry point */ /* 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 /* If this task is running PIC, then set the PIC base register to the
* address of the allocated D-Space region. * address of the allocated D-Space region.

View File

@ -122,8 +122,25 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/ */
tcb->xcp.sigdeliver = 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 /* Then set up to vector to the trampoline with interrupts
* disabled * 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_PC] = (uint32_t)arm_sigdeliver;
CURRENT_REGS[REG_CPSR] = PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT; 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. * the signals have been delivered.
*/ */
tcb->xcp.sigdeliver = 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 /* Then set up to vector to the trampoline with interrupts
* disabled * disabled
*/ */
tcb->xcp.regs[REG_PC] = (uint32_t)arm_sigdeliver; 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_CPSR] = PSR_MODE_SYS | PSR_I_BIT | PSR_F_BIT;
} }
} }
} }

View File

@ -53,8 +53,8 @@
void arm_sigdeliver(void) void arm_sigdeliver(void)
{ {
struct tcb_s *rtcb = this_task(); struct tcb_s *rtcb = this_task();
uint32_t regs[XCPTCONTEXT_REGS]; uint32_t *regs = rtcb->xcp.saved_regs;
board_autoled_on(LED_SIGNAL); board_autoled_on(LED_SIGNAL);
@ -62,10 +62,6 @@ void arm_sigdeliver(void)
rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head);
DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL);
/* Save the return state on the stack. */
arm_copyfullstate(regs, rtcb->xcp.regs);
#ifndef CONFIG_SUPPRESS_INTERRUPTS #ifndef CONFIG_SUPPRESS_INTERRUPTS
/* Then make sure that interrupts are enabled. Signal handlers must always /* Then make sure that interrupts are enabled. Signal handlers must always
* run with interrupts enabled. * run with interrupts enabled.
@ -96,8 +92,6 @@ void arm_sigdeliver(void)
* could be modified by a hostile program. * 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 */ rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */
/* Then restore the correct state for this thread of execution. */ /* Then restore the correct state for this thread of execution. */

View File

@ -85,7 +85,8 @@ uint32_t *arm_syscall(uint32_t *regs)
/* R0=SYS_switch_context: This a switch context command: /* 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: * 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: case SYS_switch_context:
{ {
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); 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]; regs = (uint32_t *)regs[REG_R2];
} }
break; break;

View File

@ -116,7 +116,24 @@ arm_vectorirq:
#else #else
/* Call arm_decodeirq() on the user stack */ /* 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 #endif
/* Restore the CPSR, SYS mode registers and return */ /* Restore the CPSR, SYS mode registers and return */

View File

@ -172,8 +172,25 @@ exception_common:
bl arm_doirq /* R0=IRQ, R1=register save area on stack */ bl arm_doirq /* R0=IRQ, R1=register save area on stack */
pop {r1} /* Recover R1=main stack pointer */ pop {r1} /* Recover R1=main stack pointer */
#else #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 */ 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 */ bl arm_doirq /* R0=IRQ, R1=register save area on stack */
mrs r1, msp /* Recover R1=main stack pointer */ mrs r1, msp /* Recover R1=main stack pointer */
#endif #endif

View File

@ -56,6 +56,10 @@ void up_initial_state(struct tcb_s *tcb)
{ {
struct xcptcontext *xcp = &tcb->xcp; struct xcptcontext *xcp = &tcb->xcp;
/* Initialize the initial exception register context structure */
memset(xcp, 0, sizeof(struct xcptcontext));
/* Initialize the idle thread stack */ /* Initialize the idle thread stack */
if (tcb->pid == 0) if (tcb->pid == 0)
@ -73,16 +77,24 @@ void up_initial_state(struct tcb_s *tcb)
arm_stack_color(tcb->stack_alloc_ptr, 0); arm_stack_color(tcb->stack_alloc_ptr, 0);
#endif /* CONFIG_STACK_COLORATION */ #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 */ /* Save the initial stack pointer */
xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + xcp->regs[REG_SP] = (uint32_t)xcp->regs;
tcb->adj_stack_size;
/* Save the task entry point (stripping off the thumb bit) */ /* Save the task entry point (stripping off the thumb bit) */

View File

@ -124,12 +124,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/ */
tcb->xcp.sigdeliver = (FAR void *)sigdeliver; tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK]; /* And make sure that the saved context in the TCB is the same
tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR]; * as the interrupt return context.
#ifdef CONFIG_BUILD_PROTECTED */
tcb->xcp.saved_lr = CURRENT_REGS[REG_LR];
#endif 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 /* Then set up to vector to the trampoline with interrupts
* disabled. The kernel-space trampoline must run in * disabled. The kernel-space trampoline must run in
* privileged thread mode. * 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_LR] = EXC_RETURN_PRIVTHR;
CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
#endif #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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; /* Save the current register context location */
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR];
#ifdef CONFIG_BUILD_PROTECTED tcb->xcp.saved_regs = tcb->xcp.regs;
tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR];
#endif /* 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 /* Then set up to vector to the trampoline with interrupts
* disabled. We must already be in privileged thread mode to be * disabled. We must already be in privileged thread mode to be
* here. * 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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; /* Save the current register context location */
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR];
#ifdef CONFIG_BUILD_PROTECTED tcb->xcp.saved_regs = tcb->xcp.regs;
tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR];
#endif /* 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 /* Then set up vector to the trampoline with interrupts
* disabled. We must already be in privileged thread mode * 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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK]; /* And make sure that the saved context in the TCB is the
tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR]; * same as the interrupt return context.
#ifdef CONFIG_BUILD_PROTECTED */
tcb->xcp.saved_lr = CURRENT_REGS[REG_LR];
#endif 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 /* Then set up vector to the trampoline with interrupts
* disabled. The kernel-space trampoline must run in * 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 #ifdef CONFIG_BUILD_PROTECTED
CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR;
#endif #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 /* 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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK]; /* Save the current register context location */
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR];
#ifdef CONFIG_BUILD_PROTECTED tcb->xcp.saved_regs = tcb->xcp.regs;
tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR];
#endif /* 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, /* Increment the IRQ lock count so that when the task is restarted,
* it will hold the IRQ spinlock. * it will hold the IRQ spinlock.
*/ */

View File

@ -53,13 +53,8 @@
void arm_sigdeliver(void) 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(); struct tcb_s *rtcb = this_task();
uint32_t regs[XCPTCONTEXT_REGS + 4]; uint32_t *regs = rtcb->xcp.saved_regs;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* In the SMP case, we must terminate the critical section while the signal /* 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); rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head);
DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL);
/* Save the return state on the stack. */
arm_copyfullstate(regs, rtcb->xcp.regs);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* In the SMP case, up_schedule_sigaction(0) will have incremented /* In the SMP case, up_schedule_sigaction(0) will have incremented
* 'irqcount' in order to force us into a critical section. Save the * '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. * 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 */ rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */
/* Then restore the correct state for this thread of /* Then restore the correct state for this thread of

View File

@ -197,7 +197,8 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg)
/* R0=SYS_switch_context: This a switch context command: /* 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: * 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: case SYS_switch_context:
{ {
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); 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]; CURRENT_REGS = (uint32_t *)regs[REG_R2];
} }
break; break;

View File

@ -24,6 +24,8 @@
#include <nuttx/config.h> #include <nuttx/config.h>
#include <arch/irq.h>
#include "arm.h" #include "arm.h"
#include "cp15.h" #include "cp15.h"
#include "sctlr.h" #include "sctlr.h"
@ -98,6 +100,7 @@ __cpu1_start:
/* Set up the stack pointer and the CPU index */ /* Set up the stack pointer and the CPU index */
ldr sp, .Lcpu1_stackpointer ldr sp, .Lcpu1_stackpointer
sub sp, sp, #XCPTCONTEXT_SIZE
mov r5, #1 mov r5, #1
/* Then branch to the common startup logic (PC-relative) */ /* Then branch to the common startup logic (PC-relative) */
@ -121,6 +124,7 @@ __cpu2_start:
/* Set up the stack pointer and the CPU index */ /* Set up the stack pointer and the CPU index */
ldr sp, .Lcpu2_stackpointer ldr sp, .Lcpu2_stackpointer
sub sp, sp, #XCPTCONTEXT_SIZE
mov r5, #2 mov r5, #2
/* Then branch to the common startup logic (PC-relative) */ /* Then branch to the common startup logic (PC-relative) */
@ -144,6 +148,7 @@ __cpu3_start:
/* Set up the stack pointer and the CPU index */ /* Set up the stack pointer and the CPU index */
ldr sp, .Lcpu3_stackpointer ldr sp, .Lcpu3_stackpointer
sub sp, sp, #XCPTCONTEXT_SIZE
mov r5, #3 mov r5, #3
/* Then branch to the common startup logic (PC-relative) */ /* Then branch to the common startup logic (PC-relative) */

View File

@ -55,6 +55,10 @@ void up_initial_state(struct tcb_s *tcb)
struct xcptcontext *xcp = &tcb->xcp; struct xcptcontext *xcp = &tcb->xcp;
uint32_t cpsr; uint32_t cpsr;
/* Initialize the initial exception register context structure */
memset(xcp, 0, sizeof(struct xcptcontext));
/* Initialize the idle thread stack */ /* Initialize the idle thread stack */
if (tcb->pid == 0) if (tcb->pid == 0)
@ -72,16 +76,24 @@ void up_initial_state(struct tcb_s *tcb)
arm_stack_color(tcb->stack_alloc_ptr, 0); arm_stack_color(tcb->stack_alloc_ptr, 0);
#endif /* CONFIG_STACK_COLORATION */ #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 */ /* Save the initial stack pointer */
xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + xcp->regs[REG_SP] = (uint32_t)xcp->regs;
tcb->adj_stack_size;
/* Save the task entry point */ /* Save the task entry point */

View File

@ -127,8 +127,25 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/ */
tcb->xcp.sigdeliver = 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 /* Then set up to vector to the trampoline with interrupts
* disabled * disabled
@ -140,12 +157,6 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#ifdef CONFIG_ARM_THUMB #ifdef CONFIG_ARM_THUMB
CURRENT_REGS[REG_CPSR] |= PSR_T_BIT; CURRENT_REGS[REG_CPSR] |= PSR_T_BIT;
#endif #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.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 /* Then set up to vector to the trampoline with interrupts
* disabled * disabled
@ -249,8 +274,23 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/ */
tcb->xcp.sigdeliver = 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 /* Then set up to vector to the trampoline with interrupts
* disabled * disabled
@ -273,9 +313,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
* has been delivered. * has been delivered.
*/ */
tcb->xcp.sigdeliver = (FAR void *)sigdeliver; tcb->xcp.sigdeliver = (FAR void *)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 vector to the trampoline with interrupts /* Then set up vector to the trampoline with interrupts
* disabled. The kernel-space trampoline must run in * 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 #ifdef CONFIG_ARM_THUMB
CURRENT_REGS[REG_CPSR] |= PSR_T_BIT; CURRENT_REGS[REG_CPSR] |= PSR_T_BIT;
#endif #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 /* 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.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, /* Increment the IRQ lock count so that when the task is restarted,
* it will hold the IRQ spinlock. * it will hold the IRQ spinlock.

View File

@ -53,8 +53,8 @@
void arm_sigdeliver(void) void arm_sigdeliver(void)
{ {
struct tcb_s *rtcb = this_task(); struct tcb_s *rtcb = this_task();
uint32_t regs[XCPTCONTEXT_REGS]; uint32_t *regs = rtcb->xcp.saved_regs;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* In the SMP case, we must terminate the critical section while the signal /* 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); rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head);
DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL);
/* Save the return state on the stack. */
arm_copyfullstate(regs, rtcb->xcp.regs);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* In the SMP case, up_schedule_sigaction(0) will have incremented /* In the SMP case, up_schedule_sigaction(0) will have incremented
* 'irqcount' in order to force us into a critical section. Save the * '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. * 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 */ rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */
/* Then restore the correct state for this thread of execution. */ /* Then restore the correct state for this thread of execution. */

View File

@ -270,7 +270,8 @@ uint32_t *arm_syscall(uint32_t *regs)
/* R0=SYS_switch_context: This a switch context command: /* 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: * 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: case SYS_switch_context:
{ {
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
#if defined(CONFIG_ARCH_FPU) arm_savefpu(regs);
arm_copyarmstate((uint32_t *)regs[REG_R1], regs);
arm_restorefpu((uint32_t *)regs[REG_R2]); arm_restorefpu((uint32_t *)regs[REG_R2]);
#else *(uint32_t **)regs[REG_R1] = regs;
memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE);
#endif
regs = (uint32_t *)regs[REG_R2]; regs = (uint32_t *)regs[REG_R2];
} }
break; break;

View File

@ -178,6 +178,19 @@ arm_vectorirq:
/* Call arm_decodeirq() on the user stack */ /* Call arm_decodeirq() on the user stack */
mov r4, sp /* Save the SP in a preserved register */ 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 */ bic sp, sp, #7 /* Force 8-byte alignment */
bl arm_decodeirq /* Call the handler */ bl arm_decodeirq /* Call the handler */
mov sp, r4 /* Restore the possibly unaligned stack pointer */ mov sp, r4 /* Restore the possibly unaligned stack pointer */
@ -283,6 +296,19 @@ arm_vectorsvc:
/* Call arm_syscall() on the user stack */ /* Call arm_syscall() on the user stack */
mov r4, sp /* Save the SP in a preserved register */ 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 */ bic sp, sp, #7 /* Force 8-byte alignment */
bl arm_syscall /* Call the handler */ bl arm_syscall /* Call the handler */
mov sp, r4 /* Restore the possibly unaligned stack pointer */ mov sp, r4 /* Restore the possibly unaligned stack pointer */

View File

@ -57,6 +57,10 @@ void up_initial_state(struct tcb_s *tcb)
{ {
struct xcptcontext *xcp = &tcb->xcp; struct xcptcontext *xcp = &tcb->xcp;
/* Initialize the initial exception register context structure */
memset(xcp, 0, sizeof(struct xcptcontext));
/* Initialize the idle thread stack */ /* Initialize the idle thread stack */
if (tcb->pid == 0) if (tcb->pid == 0)
@ -74,16 +78,24 @@ void up_initial_state(struct tcb_s *tcb)
arm_stack_color(tcb->stack_alloc_ptr, 0); arm_stack_color(tcb->stack_alloc_ptr, 0);
#endif /* CONFIG_STACK_COLORATION */ #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 */ /* Save the initial stack pointer */
xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + xcp->regs[REG_SP] = (uint32_t)xcp->regs;
tcb->adj_stack_size;
#ifdef CONFIG_ARMV7M_STACKCHECK #ifdef CONFIG_ARMV7M_STACKCHECK
/* Set the stack limit value */ /* Set the stack limit value */

View File

@ -125,16 +125,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/ */
tcb->xcp.sigdeliver = (FAR void *)sigdeliver; tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
#ifdef CONFIG_ARMV7M_USEBASEPRI /* And make sure that the saved context in the TCB is the same
tcb->xcp.saved_basepri = CURRENT_REGS[REG_BASEPRI]; * as the interrupt return context.
#else */
tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK];
#endif arm_savestate(tcb->xcp.saved_regs);
tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR];
#ifdef CONFIG_BUILD_PROTECTED /* Duplicate the register context. These will be
tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; * restored by the signal trampoline after the signal has been
#endif * 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 /* Then set up to vector to the trampoline with interrupts
* disabled. The kernel-space trampoline must run in * disabled. The kernel-space trampoline must run in
* privileged thread mode. * 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_LR] = EXC_RETURN_PRIVTHR;
CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
#endif #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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
#ifdef CONFIG_ARMV7M_USEBASEPRI /* Save the current register context location */
tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI];
#else tcb->xcp.saved_regs = tcb->xcp.regs;
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK];
#endif /* Duplicate the register context. These will be
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; * restored by the signal trampoline after the signal has been
#ifdef CONFIG_BUILD_PROTECTED * delivered.
tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; */
#endif
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 /* Then set up to vector to the trampoline with interrupts
* disabled. We must already be in privileged thread mode to be * disabled. We must already be in privileged thread mode to be
* here. * 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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
#ifdef CONFIG_ARMV7M_USEBASEPRI /* Save the current register context location */
tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI];
#else tcb->xcp.saved_regs = tcb->xcp.regs;
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK];
#endif /* Duplicate the register context. These will be
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; * restored by the signal trampoline after the signal has
#ifdef CONFIG_BUILD_PROTECTED * been delivered.
tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; */
#endif
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 /* Then set up vector to the trampoline with interrupts
* disabled. We must already be in privileged thread mode * 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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
#ifdef CONFIG_ARMV7M_USEBASEPRI /* And make sure that the saved context in the TCB is the
tcb->xcp.saved_basepri = CURRENT_REGS[REG_BASEPRI]; * same as the interrupt return context.
#else */
tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK];
#endif arm_savestate(tcb->xcp.saved_regs);
tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR];
#ifdef CONFIG_BUILD_PROTECTED /* Duplicate the register context. These will be
tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; * restored by the signal trampoline after the signal has
#endif * 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 /* Then set up vector to the trampoline with interrupts
* disabled. The kernel-space trampoline must run in * 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 #ifdef CONFIG_BUILD_PROTECTED
CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR;
#endif #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 /* 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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
#ifdef CONFIG_ARMV7M_USEBASEPRI /* Save the current register context location */
tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI];
#else tcb->xcp.saved_regs = tcb->xcp.regs;
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK];
#endif /* Duplicate the register context. These will be
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; * restored by the signal trampoline after the signal has been
#ifdef CONFIG_BUILD_PROTECTED * delivered.
tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; */
#endif
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, /* Increment the IRQ lock count so that when the task is restarted,
* it will hold the IRQ spinlock. * it will hold the IRQ spinlock.
*/ */

View File

@ -53,8 +53,8 @@
void arm_sigdeliver(void) void arm_sigdeliver(void)
{ {
struct tcb_s *rtcb = this_task(); struct tcb_s *rtcb = this_task();
uint32_t regs[XCPTCONTEXT_REGS]; uint32_t *regs = rtcb->xcp.saved_regs;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* In the SMP case, we must terminate the critical section while the signal /* 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); rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head);
DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL);
/* Save the return state on the stack. */
arm_copyfullstate(regs, rtcb->xcp.regs);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* In the SMP case, up_schedule_sigaction(0) will have incremented /* In the SMP case, up_schedule_sigaction(0) will have incremented
* 'irqcount' in order to force us into a critical section. Save the * '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. * 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 */ rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */
/* Then restore the correct state for this thread of /* Then restore the correct state for this thread of

View File

@ -175,10 +175,10 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg)
case SYS_save_context: case SYS_save_context:
{ {
DEBUGASSERT(regs[REG_R1] != 0); DEBUGASSERT(regs[REG_R1] != 0);
memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE);
#if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV7M_LAZYFPU) #if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV7M_LAZYFPU)
arm_savefpu((uint32_t *)regs[REG_R1]); arm_savefpu(regs);
#endif #endif
memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE);
} }
break; 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: /* 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: * 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: case SYS_switch_context:
{ {
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); 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) #if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV7M_LAZYFPU)
arm_savefpu((uint32_t *)regs[REG_R1]); arm_savefpu(regs);
#endif #endif
*(uint32_t **)regs[REG_R1] = regs;
CURRENT_REGS = (uint32_t *)regs[REG_R2]; CURRENT_REGS = (uint32_t *)regs[REG_R2];
} }
break; break;

View File

@ -200,7 +200,21 @@ exception_common:
setintstack r2, r3 /* SP = IRQ stack top */ setintstack r2, r3 /* SP = IRQ stack top */
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
#else #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 /* Otherwise, we will re-use the interrupted thread's stack. That may
* mean using either MSP or PSP stack for interrupt level processing (in * mean using either MSP or PSP stack for interrupt level processing (in
* kernel mode). * kernel mode).
@ -209,9 +223,13 @@ exception_common:
bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */ bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */
mov sp, r2 /* Instantiate the aligned stack */ 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 #endif
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
mov r1, r4 /* Recover R1=main stack pointer */ mov r1, r4 /* Recover R1=main stack pointer */
/* On return from arm_doirq, R0 will hold a pointer to register context /* On return from arm_doirq, R0 will hold a pointer to register context

View File

@ -194,7 +194,21 @@ exception_common:
setintstack r2, r3 /* SP = IRQ stack top */ setintstack r2, r3 /* SP = IRQ stack top */
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
#else #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 /* Otherwise, we will re-use the interrupted thread's stack. That may
* mean using either MSP or PSP stack for interrupt level processing (in * mean using either MSP or PSP stack for interrupt level processing (in
* kernel mode). * kernel mode).
@ -203,9 +217,13 @@ exception_common:
bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */ bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */
mov sp, r2 /* Instantiate the aligned stack */ 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 #endif
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
mov r1, r4 /* Recover R1=main stack pointer */ mov r1, r4 /* Recover R1=main stack pointer */
/* On return from arm_doirq, R0 will hold a pointer to register context /* On return from arm_doirq, R0 will hold a pointer to register context

View File

@ -55,6 +55,10 @@ void up_initial_state(struct tcb_s *tcb)
struct xcptcontext *xcp = &tcb->xcp; struct xcptcontext *xcp = &tcb->xcp;
uint32_t cpsr; uint32_t cpsr;
/* Initialize the initial exception register context structure */
memset(xcp, 0, sizeof(struct xcptcontext));
/* Initialize the idle thread stack */ /* Initialize the idle thread stack */
if (tcb->pid == 0) if (tcb->pid == 0)
@ -72,16 +76,24 @@ void up_initial_state(struct tcb_s *tcb)
arm_stack_color(tcb->stack_alloc_ptr, 0); arm_stack_color(tcb->stack_alloc_ptr, 0);
#endif /* CONFIG_STACK_COLORATION */ #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 */ /* Save the initial stack pointer */
xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + xcp->regs[REG_SP] = (uint32_t)xcp->regs;
tcb->adj_stack_size;
/* Save the task entry point */ /* Save the task entry point */

View File

@ -122,8 +122,25 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/ */
tcb->xcp.sigdeliver = 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 /* Then set up to vector to the trampoline with interrupts
* disabled * disabled
@ -134,14 +151,8 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
PSR_F_BIT); PSR_F_BIT);
#ifdef CONFIG_ENDIAN_BIG #ifdef CONFIG_ENDIAN_BIG
CURRENT_REGS[REG_CPSR] |= PSR_E_BIT; CURRENT_REGS[REG_CPSR] |= PSR_E_BIT;
#endif #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. * have been delivered.
*/ */
tcb->xcp.sigdeliver = 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 /* Then set up to vector to the trampoline with interrupts
* disabled * disabled
@ -170,7 +195,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
PSR_F_BIT); PSR_F_BIT);
#ifdef CONFIG_ENDIAN_BIG #ifdef CONFIG_ENDIAN_BIG
tcb->xcp.regs[REG_CPSR] |= PSR_E_BIT; tcb->xcp.regs[REG_CPSR] |= PSR_E_BIT;
#endif #endif
} }
} }

View File

@ -54,7 +54,7 @@
void arm_sigdeliver(void) void arm_sigdeliver(void)
{ {
struct tcb_s *rtcb = this_task(); struct tcb_s *rtcb = this_task();
uint32_t regs[XCPTCONTEXT_REGS]; uint32_t *regs = rtcb->xcp.saved_regs;
board_autoled_on(LED_SIGNAL); board_autoled_on(LED_SIGNAL);
@ -62,10 +62,6 @@ void arm_sigdeliver(void)
rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head); rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head);
DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL);
/* Save the return state on the stack. */
arm_copyfullstate(regs, rtcb->xcp.regs);
#ifndef CONFIG_SUPPRESS_INTERRUPTS #ifndef CONFIG_SUPPRESS_INTERRUPTS
/* Then make sure that interrupts are enabled. Signal handlers must always /* Then make sure that interrupts are enabled. Signal handlers must always
* run with interrupts enabled. * run with interrupts enabled.
@ -96,8 +92,6 @@ void arm_sigdeliver(void)
* could be modified by a hostile program. * 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 */ rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */
/* Then restore the correct state for this thread of execution. */ /* Then restore the correct state for this thread of execution. */

View File

@ -267,7 +267,8 @@ uint32_t *arm_syscall(uint32_t *regs)
/* R0=SYS_switch_context: This a switch context command: /* 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: * 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: case SYS_switch_context:
{ {
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0);
#if defined(CONFIG_ARCH_FPU) arm_savefpu(regs);
arm_copyarmstate((uint32_t *)regs[REG_R1], regs);
arm_restorefpu((uint32_t *)regs[REG_R2]); arm_restorefpu((uint32_t *)regs[REG_R2]);
#else *(uint32_t **)regs[REG_R1] = regs;
memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE);
#endif
regs = (uint32_t *)regs[REG_R2]; regs = (uint32_t *)regs[REG_R2];
} }
break; break;

View File

@ -132,6 +132,19 @@ arm_vectorirq:
/* Call arm_decodeirq() on the user stack */ /* Call arm_decodeirq() on the user stack */
mov r4, sp /* Save the SP in a preserved register */ 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 */ bic sp, sp, #7 /* Force 8-byte alignment */
bl arm_decodeirq /* Call the handler */ bl arm_decodeirq /* Call the handler */
mov sp, r4 /* Restore the possibly unaligned stack pointer */ mov sp, r4 /* Restore the possibly unaligned stack pointer */
@ -237,6 +250,19 @@ arm_vectorsvc:
/* Call arm_syscall() on the user stack */ /* Call arm_syscall() on the user stack */
mov r4, sp /* Save the SP in a preserved register */ 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 */ bic sp, sp, #7 /* Force 8-byte alignment */
bl arm_syscall /* Call the handler */ bl arm_syscall /* Call the handler */
mov sp, r4 /* Restore the possibly unaligned stack pointer */ mov sp, r4 /* Restore the possibly unaligned stack pointer */

View File

@ -216,7 +216,21 @@ exception_common:
setintstack r2, r3 /* SP = IRQ stack top */ setintstack r2, r3 /* SP = IRQ stack top */
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
#else #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 /* Otherwise, we will re-use the interrupted thread's stack. That may
* mean using either MSP or PSP stack for interrupt level processing (in * mean using either MSP or PSP stack for interrupt level processing (in
* kernel mode). * kernel mode).
@ -225,9 +239,13 @@ exception_common:
bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */ bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */
mov sp, r2 /* Instantiate the aligned stack */ 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 #endif
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
mov r1, r4 /* Recover R1=main stack pointer */ mov r1, r4 /* Recover R1=main stack pointer */
/* On return from arm_doirq, R0 will hold a pointer to register context /* On return from arm_doirq, R0 will hold a pointer to register context

View File

@ -57,6 +57,10 @@ void up_initial_state(struct tcb_s *tcb)
{ {
struct xcptcontext *xcp = &tcb->xcp; struct xcptcontext *xcp = &tcb->xcp;
/* Initialize the initial exception register context structure */
memset(xcp, 0, sizeof(struct xcptcontext));
/* Initialize the idle thread stack */ /* Initialize the idle thread stack */
if (tcb->pid == 0) if (tcb->pid == 0)
@ -74,16 +78,24 @@ void up_initial_state(struct tcb_s *tcb)
arm_stack_color(tcb->stack_alloc_ptr, 0); arm_stack_color(tcb->stack_alloc_ptr, 0);
#endif /* CONFIG_STACK_COLORATION */ #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 */ /* Save the initial stack pointer */
xcp->regs[REG_SP] = (uint32_t)tcb->stack_base_ptr + xcp->regs[REG_SP] = (uint32_t)xcp->regs;
tcb->adj_stack_size;
#ifdef CONFIG_ARMV8M_STACKCHECK #ifdef CONFIG_ARMV8M_STACKCHECK
/* Set the stack limit value */ /* Set the stack limit value */

View File

@ -211,7 +211,21 @@ exception_common:
setintstack r2, r3 /* SP = IRQ stack top */ setintstack r2, r3 /* SP = IRQ stack top */
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
#else #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 /* Otherwise, we will re-use the interrupted thread's stack. That may
* mean using either MSP or PSP stack for interrupt level processing (in * mean using either MSP or PSP stack for interrupt level processing (in
* kernel mode). * kernel mode).
@ -220,9 +234,13 @@ exception_common:
bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */ bic r2, r4, #7 /* Get the stack pointer with 8-byte alignment */
mov sp, r2 /* Instantiate the aligned stack */ 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 #endif
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
mov r1, r4 /* Recover R1=main stack pointer */ mov r1, r4 /* Recover R1=main stack pointer */
/* On return from arm_doirq, R0 will hold a pointer to register context /* On return from arm_doirq, R0 will hold a pointer to register context

View File

@ -125,16 +125,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/ */
tcb->xcp.sigdeliver = (FAR void *)sigdeliver; tcb->xcp.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
#ifdef CONFIG_ARMV8M_USEBASEPRI /* And make sure that the saved context in the TCB is the same
tcb->xcp.saved_basepri = CURRENT_REGS[REG_BASEPRI]; * as the interrupt return context.
#else */
tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK];
#endif arm_savestate(tcb->xcp.saved_regs);
tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR];
#ifdef CONFIG_BUILD_PROTECTED /* Duplicate the register context. These will be
tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; * restored by the signal trampoline after the signal has been
#endif * 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 /* Then set up to vector to the trampoline with interrupts
* disabled. The kernel-space trampoline must run in * disabled. The kernel-space trampoline must run in
* privileged thread mode. * 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_LR] = EXC_RETURN_PRIVTHR;
CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
#endif #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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
#ifdef CONFIG_ARMV8M_USEBASEPRI /* Save the current register context location */
tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI];
#else tcb->xcp.saved_regs = tcb->xcp.regs;
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK];
#endif /* Duplicate the register context. These will be
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; * restored by the signal trampoline after the signal has been
#ifdef CONFIG_BUILD_PROTECTED * delivered.
tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; */
#endif
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 /* Then set up to vector to the trampoline with interrupts
* disabled. We must already be in privileged thread mode to be * disabled. We must already be in privileged thread mode to be
* here. * 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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
#ifdef CONFIG_ARMV8M_USEBASEPRI /* Save the current register context location */
tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI];
#else tcb->xcp.saved_regs = tcb->xcp.regs;
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK];
#endif /* Duplicate the register context. These will be
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; * restored by the signal trampoline after the signal has
#ifdef CONFIG_BUILD_PROTECTED * been delivered.
tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; */
#endif
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 /* Then set up vector to the trampoline with interrupts
* disabled. We must already be in privileged thread mode * 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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = CURRENT_REGS[REG_PC];
#ifdef CONFIG_ARMV8M_USEBASEPRI /* And make sure that the saved context in the TCB is the
tcb->xcp.saved_basepri = CURRENT_REGS[REG_BASEPRI]; * same as the interrupt return context.
#else */
tcb->xcp.saved_primask = CURRENT_REGS[REG_PRIMASK];
#endif arm_savestate(tcb->xcp.saved_regs);
tcb->xcp.saved_xpsr = CURRENT_REGS[REG_XPSR];
#ifdef CONFIG_BUILD_PROTECTED /* Duplicate the register context. These will be
tcb->xcp.saved_lr = CURRENT_REGS[REG_LR]; * restored by the signal trampoline after the signal has
#endif * 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 /* Then set up vector to the trampoline with interrupts
* disabled. The kernel-space trampoline must run in * 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 #ifdef CONFIG_BUILD_PROTECTED
CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR;
#endif #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 /* 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.sigdeliver = (FAR void *)sigdeliver;
tcb->xcp.saved_pc = tcb->xcp.regs[REG_PC];
#ifdef CONFIG_ARMV8M_USEBASEPRI /* Save the current register context location */
tcb->xcp.saved_basepri = tcb->xcp.regs[REG_BASEPRI];
#else tcb->xcp.saved_regs = tcb->xcp.regs;
tcb->xcp.saved_primask = tcb->xcp.regs[REG_PRIMASK];
#endif /* Duplicate the register context. These will be
tcb->xcp.saved_xpsr = tcb->xcp.regs[REG_XPSR]; * restored by the signal trampoline after the signal has been
#ifdef CONFIG_BUILD_PROTECTED * delivered.
tcb->xcp.saved_lr = tcb->xcp.regs[REG_LR]; */
#endif
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, /* Increment the IRQ lock count so that when the task is restarted,
* it will hold the IRQ spinlock. * it will hold the IRQ spinlock.
*/ */

View File

@ -53,8 +53,8 @@
void arm_sigdeliver(void) void arm_sigdeliver(void)
{ {
struct tcb_s *rtcb = this_task(); struct tcb_s *rtcb = this_task();
uint32_t regs[XCPTCONTEXT_REGS]; uint32_t *regs = rtcb->xcp.saved_regs;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* In the SMP case, we must terminate the critical section while the signal /* 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); rtcb, rtcb->xcp.sigdeliver, rtcb->sigpendactionq.head);
DEBUGASSERT(rtcb->xcp.sigdeliver != NULL); DEBUGASSERT(rtcb->xcp.sigdeliver != NULL);
/* Save the return state on the stack. */
arm_copyfullstate(regs, rtcb->xcp.regs);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* In the SMP case, up_schedule_sigaction(0) will have incremented /* In the SMP case, up_schedule_sigaction(0) will have incremented
* 'irqcount' in order to force us into a critical section. Save the * '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. * 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 */ rtcb->xcp.sigdeliver = NULL; /* Allows next handler to be scheduled */
/* Then restore the correct state for this thread of /* Then restore the correct state for this thread of

View File

@ -174,10 +174,10 @@ int arm_svcall(int irq, FAR void *context, FAR void *arg)
case SYS_save_context: case SYS_save_context:
{ {
DEBUGASSERT(regs[REG_R1] != 0); DEBUGASSERT(regs[REG_R1] != 0);
memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE);
#if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV8M_LAZYFPU) #if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV8M_LAZYFPU)
arm_savefpu((uint32_t *)regs[REG_R1]); arm_savefpu(regs);
#endif #endif
memcpy((uint32_t *)regs[REG_R1], regs, XCPTCONTEXT_SIZE);
} }
break; 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: /* 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: * 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: case SYS_switch_context:
{ {
DEBUGASSERT(regs[REG_R1] != 0 && regs[REG_R2] != 0); 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) #if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV8M_LAZYFPU)
arm_savefpu((uint32_t *)regs[REG_R1]); arm_savefpu(regs);
#endif #endif
*(uint32_t **)regs[REG_R1] = regs;
CURRENT_REGS = (uint32_t *)regs[REG_R2]; CURRENT_REGS = (uint32_t *)regs[REG_R2];
} }
break; break;

View File

@ -150,7 +150,21 @@ arm_vectorirq:
bl arm_doirq /* Call the handler */ bl arm_doirq /* Call the handler */
ldr sp, [sp] /* Restore the user stack pointer */ ldr sp, [sp] /* Restore the user stack pointer */
#else #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 #endif
/* Restore the CPSR, SYS mode registers and return */ /* Restore the CPSR, SYS mode registers and return */

View File

@ -148,7 +148,7 @@ void up_block_task(struct tcb_s *tcb, tstate_t task_state)
* ready to run list. * 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 /* arm_switchcontext forces a context switch to the task at the
* head of the ready-to-run list. It does not 'return' in the * head of the ready-to-run list. It does not 'return' in the

View File

@ -105,10 +105,11 @@
* applies if "lazy" floating point register save/restore is used * applies if "lazy" floating point register save/restore is used
*/ */
# if defined(CONFIG_ARCH_FPU) && defined(CONFIG_ARMV7M_LAZYFPU) # if defined(CONFIG_ARCH_FPU) && (defined(CONFIG_ARMV7M_LAZYFPU) || \
# define arm_savestate(regs) arm_copyarmstate(regs, (uint32_t*)CURRENT_REGS) defined(CONFIG_ARMV8M_LAZYFPU))
# define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS, arm_savefpu(regs))
# else # else
# define arm_savestate(regs) arm_copyfullstate(regs, (uint32_t*)CURRENT_REGS) # define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS)
# endif # endif
# define arm_restorestate(regs) (CURRENT_REGS = regs) # define arm_restorestate(regs) (CURRENT_REGS = regs)
@ -123,9 +124,9 @@
*/ */
# if defined(CONFIG_ARCH_FPU) # 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 # else
# define arm_savestate(regs) arm_copyfullstate(regs, (uint32_t*)CURRENT_REGS) # define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS)
# endif # endif
# define arm_restorestate(regs) (CURRENT_REGS = regs) # define arm_restorestate(regs) (CURRENT_REGS = regs)
@ -142,11 +143,11 @@
*/ */
# if defined(CONFIG_ARCH_FPU) # 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 # else
# define arm_savestate(regs) arm_copyfullstate(regs, (uint32_t*)CURRENT_REGS) # define arm_savestate(regs) (regs = (FAR uint32_t *)CURRENT_REGS)
# endif # endif
# define arm_restorestate(regs) arm_copyfullstate((uint32_t*)CURRENT_REGS, regs) # define arm_restorestate(regs) (CURRENT_REGS = regs)
#endif #endif
@ -333,7 +334,7 @@ void arm_copyarmstate(uint32_t *dest, uint32_t *src);
uint32_t *arm_decodeirq(uint32_t *regs); uint32_t *arm_decodeirq(uint32_t *regs);
int arm_saveusercontext(uint32_t *saveregs); int arm_saveusercontext(uint32_t *saveregs);
void arm_fullcontextrestore(uint32_t *restoreregs) noreturn_function; 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 **********************************************************/ /* Signal handling **********************************************************/

View File

@ -115,7 +115,7 @@ void up_release_pending(void)
* ready to run list. * 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 /* arm_switchcontext forces a context switch to the task at the
* head of the ready-to-run list. It does not 'return' in the * head of the ready-to-run list. It does not 'return' in the

View File

@ -170,7 +170,7 @@ void up_reprioritize_rtr(struct tcb_s *tcb, uint8_t priority)
* ready to run list. * 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 /* arm_switchcontext forces a context switch to the task at the
* head of the ready-to-run list. It does not 'return' in the * head of the ready-to-run list. It does not 'return' in the

View File

@ -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); sys_call2(SYS_switch_context, (uintptr_t)saveregs, (uintptr_t)restoreregs);
} }

View File

@ -132,7 +132,7 @@ void up_unblock_task(struct tcb_s *tcb)
* ready to run list. * 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 /* arm_switchcontext forces a context switch to the task at the
* head of the ready-to-run list. It does not 'return' in the * head of the ready-to-run list. It does not 'return' in the

View File

@ -36,6 +36,7 @@
#include <arch/irq.h> #include <arch/irq.h>
#include "arm_vfork.h" #include "arm_vfork.h"
#include "arm_internal.h"
#include "sched/sched.h" #include "sched/sched.h"
/**************************************************************************** /****************************************************************************
@ -136,8 +137,9 @@ pid_t up_vfork(const struct vfork_s *context)
* effort is overkill. * effort is overkill.
*/ */
newtop = (uint32_t)child->cmn.stack_base_ptr + newtop = STACK_ALIGN_DOWN((uint32_t)child->cmn.stack_base_ptr +
child->cmn.adj_stack_size; child->cmn.adj_stack_size -
XCPTCONTEXT_SIZE);
newsp = newtop - stackutil; newsp = newtop - stackutil;
memcpy((void *)newsp, (const void *)context->sp, stackutil); memcpy((void *)newsp, (const void *)context->sp, stackutil);

View File

@ -100,13 +100,24 @@ exception_common:
mrs r0, ipsr /* R0=exception number */ mrs r0, ipsr /* R0=exception number */
/* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt /* Reserve xcpcontext to ensure that signal processing can have
* stack pointer. The way that this is done here prohibits nested interrupts! * a separate xcpcontext to handle signal context
* Otherwise, we will use the stack that was current when the interrupt was taken. * (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 */ msr msp, r1 /* We are using the main stack pointer */
bl arm_doirq /* R0=IRQ, R1=register save area on stack */ 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 */ mrs r1, msp /* Recover R1=main stack pointer */
/* On return from arm_doirq, R0 will hold a pointer to register context /* 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 */ mrs r0, ipsr /* R0=exception number */
/* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will use a special interrupt /* Reserve xcpcontext to ensure that signal processing can have
* stack pointer. The way that this is done here prohibits nested interrupts! * a separate xcpcontext to handle signal context
* Otherwise, we will use the stack that was current when the interrupt was taken. * (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 */ msr msp, r1 /* We are using the main stack pointer */
bl arm_doirq /* R0=IRQ, R1=register save area on stack */ 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 */ mrs r1, msp /* Recover R1=main stack pointer */
/* On return from arm_doirq, R0 will hold a pointer to register context /* On return from arm_doirq, R0 will hold a pointer to register context