arch/armv6-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-05 21:37:14 +08:00 committed by Xiang Xiao
parent cedc034d9e
commit 2684642a7a
8 changed files with 86 additions and 84 deletions

View File

@ -34,6 +34,7 @@
#include <sched/sched.h>
#include "arm_internal.h"
#include "exc_return.h"
/****************************************************************************
* Public Functions
@ -46,20 +47,9 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
PANIC();
#else
/* Nested interrupts are not supported in this implementation. If you
* want to implement nested interrupts, you would have to (1) change the
* way that CURRENT_REGS is handled and (2) the design associated with
* CONFIG_ARCH_INTERRUPTSTACK.
*/
/* 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)
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
{
CURRENT_REGS = regs;
regs = NULL;
}
/* Acknowledge the interrupt */
@ -68,7 +58,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
/* Deliver the IRQ */
irq_dispatch(irq, (uint32_t *)CURRENT_REGS);
irq_dispatch(irq, regs);
/* If a context switch occurred while processing the interrupt then
* CURRENT_REGS may have change value. If we return any value different
@ -76,7 +66,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
* switch occurred during interrupt processing.
*/
if (regs == NULL)
if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
{
/* Restore the cpu lock */

View File

@ -58,26 +58,6 @@
.globl exception_common
.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 > 3
.macro setintstack, tmp1, tmp2
ldr \tmp1, =g_intstacktop
mov sp, \tmp1
.endm
#endif
/****************************************************************************
* .text
****************************************************************************/
@ -118,10 +98,13 @@ exception_common:
lsls r0, #(31 - EXC_RETURN_PROCESS_BITNO) /* Move to bit 31 */
bmi 1f /* Test bit 31 */
mrs r1, msp /* R1=The main stack pointer */
subs r1, #SW_XCPT_SIZE /* R1=Beginning of context array on the stack */
msr msp, r1 /* Reserved stack space */
b 2f
1:
mrs r1, psp /* R1=The process stack pointer */
subs r1, #SW_XCPT_SIZE /* R1=Beginning of context array on the stack */
/* R1 is the current stack pointer. HW_XCPT_REGS were pushed onto the stack
* when the interrupt was taken so (R1)+HW_XCPT_SIZE is the value of the
@ -133,7 +116,6 @@ exception_common:
2:
/* Save SP, PRIMASK, and R4-R7 in the context array */
subs r1, #SW_XCPT_SIZE /* R1=Beginning of context array on the stack */
movs r2, #XCPTCONTEXT_SIZE /* R2=Size of the context array */
add r2, r1 /* R2=MSP/PSP before the interrupt was taken */
/* (ignoring the xPSR[9] alignment bit) */
@ -160,9 +142,7 @@ exception_common:
* Otherwise, we will use the stack that was current when the interrupt was taken.
*/
#if CONFIG_ARCH_INTERRUPTSTACK > 3
setintstack r7, r6 /* SP = IRQ stack top */
#else
#if CONFIG_ARCH_INTERRUPTSTACK < 3
/* 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):
@ -174,9 +154,13 @@ exception_common:
* also the sp should be restore after arm_doirq()
*/
mov r2, r14
lsls r2, #(31 - EXC_RETURN_THREAD_BITNO) /* Move to bit 31 */
bpl 3f /* Test bit 31 */
mov r2, r1 /* Reserve signal context */
subs r2, r2, #XCPTCONTEXT_SIZE
msr msp, r2 /* We are using the main stack pointer */
3:
#endif
bl arm_doirq /* R0=IRQ, R1=register save area on stack */
@ -211,14 +195,14 @@ exception_common:
mov r0, r14 /* Copy high register to low register */
lsls r0, #(31 - EXC_RETURN_PROCESS_BITNO) /* Move to bit 31 */
bmi 3f /* Test bit 31 */
bmi 4f /* Test bit 31 */
msr msp, r1 /* R1=The main stack pointer */
b 4f
3:
msr psp, r1 /* R1=The process stack pointer */
b 5f
4:
msr psp, r1 /* R1=The process stack pointer */
5:
/* Restore the interrupt state */

View File

@ -135,7 +135,7 @@ void up_initial_state(struct tcb_s *tcb)
* 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;
@ -145,3 +145,46 @@ void up_initial_state(struct tcb_s *tcb)
xcp->regs[REG_PRIMASK] = 1;
#endif /* CONFIG_SUPPRESS_INTERRUPTS */
}
#if CONFIG_ARCH_INTERRUPTSTACK > 3
/****************************************************************************
* 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();
#else
uint32_t stack = (uint32_t)g_intstacktop;
#endif
uint32_t tempa = 0;
uint32_t tempb = 2;
__asm__ __volatile__
(
/* Initialize PSP */
"mov %1, sp\n"
"msr psp, %1\n"
/* Select PSP */
"mrs %1, CONTROL\n"
"orr %1, %2\n"
"msr CONTROL, %1\n"
"isb sy\n"
/* Initialize MSP */
"msr msp, %0\n"
:
: "r" (stack), "r" (tempa), "r" (tempb)
: "memory");
}
#endif

View File

@ -155,8 +155,8 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
CURRENT_REGS[REG_PRIMASK] = 1;
CURRENT_REGS[REG_XPSR] = ARMV6M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED
CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR;
CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
CURRENT_REGS[REG_LR] = EXC_RETURN_THREAD;
CURRENT_REGS[REG_EXC_RETURN] = EXC_RETURN_THREAD;
CURRENT_REGS[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif
}
@ -200,7 +200,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
tcb->xcp.regs[REG_PRIMASK] = 1;
tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR;
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif
}
@ -307,7 +307,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
tcb->xcp.regs[REG_PRIMASK] = 1;
tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR;
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif
}
@ -350,7 +350,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
CURRENT_REGS[REG_PRIMASK] = 1;
CURRENT_REGS[REG_XPSR] = ARMV6M_XPSR_T;
#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;
#endif
}
@ -409,7 +409,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
tcb->xcp.regs[REG_PRIMASK] = 1;
tcb->xcp.regs[REG_XPSR] = ARMV6M_XPSR_T;
#ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR;
tcb->xcp.regs[REG_LR] = EXC_RETURN_THREAD;
tcb->xcp.regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
#endif
}

View File

@ -262,7 +262,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/
regs[REG_PC] = (uint32_t)USERSPACE->task_startup;
regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return unprivileged mode */
@ -299,7 +299,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/
regs[REG_PC] = (uint32_t)regs[REG_R1]; /* startup */
regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return unprivileged mode */
@ -344,7 +344,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/
regs[REG_PC] = (uint32_t)USERSPACE->signal_handler;
regs[REG_EXC_RETURN] = EXC_RETURN_UNPRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return unprivileged mode */
@ -381,7 +381,7 @@ int arm_svcall(int irq, void *context, void *arg)
DEBUGASSERT(rtcb->xcp.sigreturn != 0);
regs[REG_PC] = rtcb->xcp.sigreturn;
regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return privileged mode */
@ -419,7 +419,7 @@ int arm_svcall(int irq, void *context, void *arg)
rtcb->xcp.nsyscalls = index + 1;
regs[REG_PC] = (uint32_t)dispatch_syscall;
regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return privileged mode */

View File

@ -71,17 +71,17 @@
#define EXC_RETURN_HANDLER 0xfffffff1
/* EXC_RETURN_PRIVTHR: Return to privileged thread mode. Exception return
* gets state from the main stack. Execution uses MSP after return.
*/
#if CONFIG_ARCH_INTERRUPTSTACK > 3
#define EXC_RETURN_PRIVTHR 0xfffffff9
/* Execution uses PSP after return */
/* EXC_RETURN_UNPRIVTHR: Return to unprivileged thread mode. Exception return
* gets state from the process stack. Execution uses PSP after return.
*/
# define EXC_RETURN_THREAD 0xfffffffd
#else
#define EXC_RETURN_UNPRIVTHR 0xfffffffd
/* Execution uses MSP after return */
# define EXC_RETURN_THREAD 0xfffffff9
#endif
/****************************************************************************
* Inline Functions

View File

@ -57,26 +57,5 @@
#ifdef __ASSEMBLY__
/****************************************************************************
* Name: setintstack
*
* Description:
* Set the current stack pointer to the "top" the correct interrupt stack
* for the current CPU.
*
****************************************************************************/
#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 3
.macro setintstack, tmp1, tmp2
ldr \tmp1, =RP2040_SIO_CPUID
ldr \tmp1, [\tmp1, #0]
lsls \tmp1, \tmp1, #2
ldr \tmp2, =g_cpu_intstack_top
add \tmp2, \tmp2, \tmp1
ldr \tmp2, [\tmp2, #0]
mov sp, \tmp2 /* sp = g_cpu_intstack_top[cpuid] */
.endm
#endif /* CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 7 */
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_RP2040_CHIP_H */

View File

@ -137,6 +137,12 @@ static int fifo_comm(uint32_t msg)
static void core1_boot(void)
{
#if CONFIG_ARCH_INTERRUPTSTACK > 3
/* Initializes the stack pointer */
arm_initialize_stack();
#endif
fifo_drain();
/* Setup NVIC */