arch/armv8-m: Supports interrupt nesting

1、The process stack supports interrupt nesting, Execute in MSP;
2、The interrupt stack supports interrupt nesting;
   The thread mode use PSP, and the handle mode use MSP;
3、Adjust arm_doirq、exception_common implementation to meet interrupt nesting
4、Adjust the conditions for returning MSP and PSP;
5、remove setintstack;

Signed-off-by: wangming9 <wangming9@xiaomi.com>
This commit is contained in:
wangming9
2023-07-08 19:37:54 +08:00
committed by Xiang Xiao
parent f8aaed780a
commit 5cdfa6fec4
6 changed files with 120 additions and 95 deletions
+3 -14
View File
@@ -47,20 +47,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
PANIC(); PANIC();
#else #else
/* Nested interrupts are not supported in this implementation. If you if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
* want to implement nested interrupts, you would have to (1) change the
* way that CURRENT_REGS is handled and (2) the design associated with
* CONFIG_ARCH_INTERRUPTSTACK.
*/
/* Current regs non-zero indicates that we are processing an interrupt;
* CURRENT_REGS is also used to manage interrupt level context switches.
*/
if (CURRENT_REGS == NULL)
{ {
CURRENT_REGS = regs; CURRENT_REGS = regs;
regs = NULL;
} }
/* Acknowledge the interrupt */ /* Acknowledge the interrupt */
@@ -69,7 +58,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
/* Deliver the IRQ */ /* Deliver the IRQ */
irq_dispatch(irq, (uint32_t *)CURRENT_REGS); irq_dispatch(irq, regs);
/* If a context switch occurred while processing the interrupt then /* If a context switch occurred while processing the interrupt then
* CURRENT_REGS may have change value. If we return any value different * CURRENT_REGS may have change value. If we return any value different
@@ -77,7 +66,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
* switch occurred during interrupt processing. * switch occurred during interrupt processing.
*/ */
if (regs == NULL) if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
{ {
/* Restore the cpu lock */ /* Restore the cpu lock */
+22 -47
View File
@@ -92,29 +92,6 @@
.thumb .thumb
.file "arm_exception.S" .file "arm_exception.S"
/****************************************************************************
* Macro Definitions
****************************************************************************/
/****************************************************************************
* Name: setintstack
*
* Description:
* Set the current stack pointer to the "top" the interrupt stack. Single CPU
* case. Must be provided by MCU-specific logic in the SMP case.
*
****************************************************************************/
#if !defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 7
.macro setintstack, tmp1, tmp2
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
ldr \tmp1, =g_intstackalloc
msr msplim, \tmp1
#endif
ldr sp, =g_intstacktop
.endm
#endif
/**************************************************************************** /****************************************************************************
* .text * .text
****************************************************************************/ ****************************************************************************/
@@ -145,31 +122,34 @@
.type exception_common, function .type exception_common, function
exception_common: exception_common:
mrs r0, ipsr /* R0=exception number */
mrs r12, control /* R12=control */ mrs r12, control /* R12=control */
/* Complete the context save */ /* Complete the context save */
/* The EXC_RETURN value tells us whether the context is on the MSP or PSP */ /* The EXC_RETURN value tells us whether the context is on the MSP or PSP */
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */ tst r14, #EXC_RETURN_PROCESS_STACK /* Nonzero if context on process stack */
beq 1f /* Branch if context already on the MSP */ beq 1f /* Branch if context already on the MSP */
mrs r1, psp /* R1=The process stack pointer (PSP) */ mrs r1, psp /* R1=The process stack pointer (PSP) */
mov sp, r1 /* Set the MSP to the PSP */ b 2f
1: 1:
mov r2, sp /* R2=Copy of the main/process stack pointer */ mrs r1, msp /* R1=The main stack pointer (MSP) */
sub r2, r1, #SW_XCPT_SIZE /* Reserve the stack space */
msr msp, r2
2:
mov r2, r1 /* R2=Copy of the main/process stack pointer */
add r2, #HW_XCPT_SIZE /* R2=MSP/PSP before the interrupt was taken */ add r2, #HW_XCPT_SIZE /* R2=MSP/PSP before the interrupt was taken */
/* (ignoring the xPSR[9] alignment bit) */ /* (ignoring the xPSR[9] alignment bit) */
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE #ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
mov r3, #0x0 mov r3, #0x0
ittee eq ittee eq
mrseq r1, msplim mrseq r0, msplim
msreq msplim, r3 msreq msplim, r3
mrsne r1, psplim mrsne r0, psplim
msrne psplim, r3 msrne psplim, r3
stmdb sp!, {r1} stmdb r1!, {r0}
#endif #endif
#ifdef CONFIG_ARMV8M_USEBASEPRI #ifdef CONFIG_ARMV8M_USEBASEPRI
@@ -195,11 +175,11 @@ exception_common:
tst r14, #EXC_RETURN_STD_CONTEXT tst r14, #EXC_RETURN_STD_CONTEXT
ite eq ite eq
vstmdbeq sp!, {s16-s31} /* Save the non-volatile FP context */ vstmdbeq r1!, {s16-s31} /* Save the non-volatile FP context */
subne sp, #(4*SW_FPU_REGS) subne r1, #(4*SW_FPU_REGS)
#endif #endif
stmdb sp!, {r2-r12,r14} /* Save the remaining registers plus the SP/PRIMASK values */ stmdb r1!, {r2-r12,r14} /* Save the remaining registers plus the SP/PRIMASK values */
/* There are two arguments to arm_doirq: /* There are two arguments to arm_doirq:
* *
@@ -207,19 +187,12 @@ exception_common:
* R1 = The top of the stack points to the saved state * R1 = The top of the stack points to the saved state
*/ */
mov r1, sp mrs r0, ipsr
#if CONFIG_ARCH_INTERRUPTSTACK > 7 #if CONFIG_ARCH_INTERRUPTSTACK < 7
/* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will set the MSP to use /* If CONFIG_ARCH_INTERRUPTSTACK is not defined, we will re-use the
* a special special interrupt stack pointer. The way that this is done * interrupted thread's stack. That may mean using either MSP or PSP
* here prohibits nested interrupts without some additional logic! * stack for interrupt level processing (in kernel mode).
*/
setintstack r2, r3 /* SP = IRQ stack top */
#else
/* 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).
*/ */
/* If the interrupt stack is disabled, reserve xcpcontext to ensure /* If the interrupt stack is disabled, reserve xcpcontext to ensure
@@ -232,10 +205,12 @@ exception_common:
* ---------------------- <- SP * ---------------------- <- SP
* also the sp should be restore after arm_doirq() * also the sp should be restore after arm_doirq()
*/ */
tst r14, #EXC_RETURN_THREAD_MODE /* Nonzero if context on thread mode */
beq 3f /* Branch if context already on the handle mode */
sub r2, r1, #XCPTCONTEXT_SIZE /* Reserve signal context */ sub r2, r1, #XCPTCONTEXT_SIZE /* Reserve signal context */
bic r2, r2, #7 /* Get the stack pointer with 8-byte alignment */ bic r2, r2, #7 /* Get the stack pointer with 8-byte alignment */
mov sp, r2 /* Instantiate the aligned stack */ mov sp, r2 /* Instantiate the aligned stack */
3:
#endif #endif
bl arm_doirq /* R0=IRQ, R1=register save (msp) */ bl arm_doirq /* R0=IRQ, R1=register save (msp) */
@@ -261,7 +236,7 @@ exception_common:
/* The EXC_RETURN value tells us whether we are returning on the MSP or PSP /* The EXC_RETURN value tells us whether we are returning on the MSP or PSP
*/ */
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */ tst r14, #EXC_RETURN_PROCESS_STACK /* Nonzero if context on process stack */
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE #ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
itete eq itete eq
msreq msplim, r1 msreq msplim, r1
+64 -1
View File
@@ -148,7 +148,7 @@ void up_initial_state(struct tcb_s *tcb)
* mode before transferring control to the user task. * mode before transferring control to the user task.
*/ */
xcp->regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; xcp->regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
xcp->regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; xcp->regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
@@ -174,3 +174,66 @@ void up_initial_state(struct tcb_s *tcb)
#endif /* CONFIG_SUPPRESS_INTERRUPTS */ #endif /* CONFIG_SUPPRESS_INTERRUPTS */
} }
#if CONFIG_ARCH_INTERRUPTSTACK > 7
/****************************************************************************
* Name: arm_initialize_stack
*
* Description:
* If interrupt stack is defined, the PSP and MSP need to be reinitialized.
*
****************************************************************************/
noinline_function void arm_initialize_stack(void)
{
#ifdef CONFIG_SMP
uint32_t stack = (uint32_t)arm_intstack_top();
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
uint32_t stacklim = (uint32_t)arm_intstack_alloc();
#endif
#else
uint32_t stack = (uint32_t)g_intstacktop;
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
uint32_t stacklim = (uint32_t)g_intstackalloc;
#endif
#endif
uint32_t temp = 0;
__asm__ __volatile__
(
"mrs %1, CONTROL\n"
"tst %1, #2\n"
"bne 1f\n"
/* Initialize PSP */
"mrs %1, msp\n"
"msr psp, %1\n"
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
"mrs %1, msplim\n"
"msr psplim, %1\n"
#endif
/* Select PSP */
"mrs %1, CONTROL\n"
"orr %1, #2\n"
"msr CONTROL, %1\n"
"isb sy\n"
/* Initialize MSP */
"1:\n"
"msr msp, %0\n"
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
"msr msplim, %2\n"
#endif
:
#ifdef CONFIG_ARMV8M_STACKCHECK_HARDWARE
: "r" (stack), "r" (temp), "r" (stacklim)
#else
: "r" (stack), "r" (temp)
#endif
: "memory");
}
#endif
+6 -6
View File
@@ -160,8 +160,8 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif #endif
CURRENT_REGS[REG_XPSR] = ARMV8M_XPSR_T; CURRENT_REGS[REG_XPSR] = ARMV8M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED #ifdef CONFIG_BUILD_PROTECTED
CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_LR] = EXC_RETURN_THREAD;
CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_THREAD;
CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif #endif
} }
@@ -209,7 +209,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif #endif
tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED #ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif #endif
} }
@@ -320,7 +320,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif #endif
tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED #ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif #endif
} }
@@ -367,7 +367,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif #endif
CURRENT_REGS[REG_XPSR] = ARMV8M_XPSR_T; CURRENT_REGS[REG_XPSR] = ARMV8M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED #ifdef CONFIG_BUILD_PROTECTED
CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR; CURRENT_REGS[REG_LR] = EXC_RETURN_THREAD;
CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif #endif
} }
@@ -434,7 +434,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif #endif
tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T; tcb->xcp.regs[REG_XPSR] = ARMV8M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED #ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR; tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV; tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif #endif
} }
+5 -5
View File
@@ -270,7 +270,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/ */
regs[REG_PC] = (uint32_t)USERSPACE->task_startup & ~1; regs[REG_PC] = (uint32_t)USERSPACE->task_startup & ~1;
regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR; regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return unprivileged mode */ /* Return unprivileged mode */
@@ -308,7 +308,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/ */
regs[REG_PC] = (uint32_t)regs[REG_R1] & ~1; /* startup */ regs[REG_PC] = (uint32_t)regs[REG_R1] & ~1; /* startup */
regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR; regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return unprivileged mode */ /* Return unprivileged mode */
@@ -353,7 +353,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/ */
regs[REG_PC] = (uint32_t)USERSPACE->signal_handler & ~1; regs[REG_PC] = (uint32_t)USERSPACE->signal_handler & ~1;
regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR; regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return unprivileged mode */ /* Return unprivileged mode */
@@ -390,7 +390,7 @@ int arm_svcall(int irq, void *context, void *arg)
DEBUGASSERT(rtcb->xcp.sigreturn != 0); DEBUGASSERT(rtcb->xcp.sigreturn != 0);
regs[REG_PC] = rtcb->xcp.sigreturn & ~1; regs[REG_PC] = rtcb->xcp.sigreturn & ~1;
regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return privileged mode */ /* Return privileged mode */
@@ -429,7 +429,7 @@ int arm_svcall(int irq, void *context, void *arg)
rtcb->xcp.nsyscalls = index + 1; rtcb->xcp.nsyscalls = index + 1;
regs[REG_PC] = (uint32_t)dispatch_syscall & ~1; regs[REG_PC] = (uint32_t)dispatch_syscall & ~1;
regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR; regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return privileged mode */ /* Return privileged mode */
+20 -22
View File
@@ -91,9 +91,9 @@
/* EXC_RETURN_BASE: Bits that are always set in an EXC_RETURN value. */ /* EXC_RETURN_BASE: Bits that are always set in an EXC_RETURN value. */
#ifdef CONFIG_ARCH_TRUSTZONE_NONSECURE #ifdef CONFIG_ARCH_TRUSTZONE_NONSECURE
#define EXC_RETURN_BASE (0xffffff80) # define EXC_RETURN_BASE (0xffffff80)
#else #else
#define EXC_RETURN_BASE (0xffffff80 | EXC_RETURN_EXC_SECURE | \ # define EXC_RETURN_BASE (0xffffff80 | EXC_RETURN_EXC_SECURE | \
EXC_RETURN_SECURE_STACK) EXC_RETURN_SECURE_STACK)
#endif #endif
@@ -104,35 +104,33 @@
#define EXC_RETURN_HANDLER (EXC_RETURN_BASE | EXC_RETURN_DEF_STACKING | \ #define EXC_RETURN_HANDLER (EXC_RETURN_BASE | EXC_RETURN_DEF_STACKING | \
EXC_RETURN_STD_CONTEXT) EXC_RETURN_STD_CONTEXT)
/* EXC_RETURN_PRIVTHR: Return to privileged thread mode. Exception return
* gets state from the main stack. Execution uses MSP after return.
*/
#ifdef CONFIG_ARCH_FPU #ifdef CONFIG_ARCH_FPU
# define EXC_RETURN_PRIVTHR (EXC_RETURN_BASE | EXC_RETURN_THREAD_MODE | \ # define EXC_RETURN_FPU 0
EXC_RETURN_DEF_STACKING)
#else #else
# define EXC_RETURN_PRIVTHR (EXC_RETURN_BASE | EXC_RETURN_STD_CONTEXT | \ # define EXC_RETURN_FPU EXC_RETURN_STD_CONTEXT
EXC_RETURN_THREAD_MODE | EXC_RETURN_DEF_STACKING)
#endif #endif
/* EXC_RETURN_UNPRIVTHR: Return to unprivileged thread mode. Exception return #if CONFIG_ARCH_INTERRUPTSTACK > 7
* gets state from the process stack. Execution uses PSP after return. # define EXC_RETURN_STACK EXC_RETURN_PROCESS_STACK
*/
#ifdef CONFIG_ARCH_FPU
# define EXC_RETURN_UNPRIVTHR (EXC_RETURN_BASE | EXC_RETURN_THREAD_MODE | \
EXC_RETURN_PROCESS_STACK | EXC_RETURN_DEF_STACKING)
#else #else
# define EXC_RETURN_UNPRIVTHR (EXC_RETURN_BASE | EXC_RETURN_STD_CONTEXT | \ # define EXC_RETURN_STACK 0
EXC_RETURN_THREAD_MODE | EXC_RETURN_PROCESS_STACK | \
EXC_RETURN_DEF_STACKING)
#endif #endif
/* EXC_RETURN_THREAD: Return to thread mode.
* If EXC_RETURN_STACK is 0, Return to thread mode.
* Execution uses MSP after return.
* If EXC_RETURN_STACK is EXC_RETURN_PROCESS_STACK, Return to
* thread mode. Execution uses PSP after return.
*/
#define EXC_RETURN_THREAD (EXC_RETURN_BASE | EXC_RETURN_FPU | \
EXC_RETURN_THREAD_MODE | EXC_RETURN_STACK | \
EXC_RETURN_DEF_STACKING)
#ifdef CONFIG_ARCH_FPU #ifdef CONFIG_ARCH_FPU
#define EXC_INTEGRITY_SIGNATURE (0xfefa125a) # define EXC_INTEGRITY_SIGNATURE (0xfefa125a)
#else #else
#define EXC_INTEGRITY_SIGNATURE (0xfefa125b) # define EXC_INTEGRITY_SIGNATURE (0xfefa125b)
#endif #endif
/* FUNC_RETURN_EXC_SECURE: Exception Secure. The security domain the /* FUNC_RETURN_EXC_SECURE: Exception Secure. The security domain the