You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/08/07 12:43:22 UTC
[nuttx] 02/09: arch/armv7-m: Supports interrupt nesting
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 816b3fb39940f5dec41d378a229c15d0f638c84c
Author: wangming9 <wa...@xiaomi.com>
AuthorDate: Wed Jul 5 16:08:52 2023 +0800
arch/armv7-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,add arm_initialize_stack;
Signed-off-by: wangming9 <wa...@xiaomi.com>
---
arch/arm/src/armv7-m/arm_doirq.c | 18 ++-------
arch/arm/src/armv7-m/arm_exception.S | 56 +++++++++-------------------
arch/arm/src/armv7-m/arm_initialstate.c | 44 +++++++++++++++++++++-
arch/arm/src/armv7-m/arm_schedulesigaction.c | 12 +++---
arch/arm/src/armv7-m/arm_svcall.c | 10 ++---
arch/arm/src/armv7-m/exc_return.h | 31 ++++++++-------
arch/arm/src/common/arm_initialize.c | 6 +++
arch/arm/src/common/arm_internal.h | 4 ++
arch/arm/src/cxd56xx/chip.h | 19 ----------
arch/arm/src/cxd56xx/cxd56_cpustart.c | 6 +++
arch/arm/src/lc823450/chip.h | 18 ---------
arch/arm/src/lc823450/lc823450_cpustart.c | 6 +++
12 files changed, 113 insertions(+), 117 deletions(-)
diff --git a/arch/arm/src/armv7-m/arm_doirq.c b/arch/arm/src/armv7-m/arm_doirq.c
index 564b903142..e7b6411faa 100644
--- a/arch/arm/src/armv7-m/arm_doirq.c
+++ b/arch/arm/src/armv7-m/arm_doirq.c
@@ -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 */
diff --git a/arch/arm/src/armv7-m/arm_exception.S b/arch/arm/src/armv7-m/arm_exception.S
index 6716a9d7f8..de5e8a3852 100644
--- a/arch/arm/src/armv7-m/arm_exception.S
+++ b/arch/arm/src/armv7-m/arm_exception.S
@@ -92,25 +92,6 @@
.thumb
.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
- ldr sp, =g_intstacktop
- .endm
-#endif
-
/****************************************************************************
* .text
****************************************************************************/
@@ -151,9 +132,14 @@ exception_common:
tst r14, #EXC_RETURN_PROCESS_STACK /* nonzero if context on process stack */
beq 1f /* Branch if context already on the MSP */
mrs r1, psp /* R1=The process stack pointer (PSP) */
- mov sp, r1 /* Set the MSP to the PSP */
+ b 2f
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 /* Reserved 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 */
/* (ignoring the xPSR[9] alignment bit) */
#ifdef CONFIG_ARMV7M_USEBASEPRI
@@ -179,11 +165,11 @@ exception_common:
tst r14, #EXC_RETURN_STD_CONTEXT
ite eq
- vstmdbeq sp!, {s16-s31} /* Save the non-volatile FP context */
- subne sp, #(4*SW_FPU_REGS)
+ vstmdbeq r1!, {s16-s31} /* Save the non-volatile FP context */
+ subne r1, #(4*SW_FPU_REGS)
#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:
*
@@ -191,19 +177,10 @@ exception_common:
* R1 = The top of the stack points to the saved state
*/
- mov r1, sp
-
-#if CONFIG_ARCH_INTERRUPTSTACK > 7
- /* If CONFIG_ARCH_INTERRUPTSTACK is defined, we will set the MSP to use
- * a special special interrupt stack pointer. The way that this is done
- * here prohibits nested interrupts without some additional logic!
- */
-
- 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 CONFIG_ARCH_INTERRUPTSTACK < 7
+ /* If CONFIG_ARCH_INTERRUPTSTACK is not defined, 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
@@ -217,9 +194,12 @@ exception_common:
* 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 */
bic r2, r2, #7 /* Get the stack pointer with 8-byte alignment */
mov sp, r2 /* Instantiate the aligned stack */
+3:
#endif
bl arm_doirq /* R0=IRQ, R1=register save (msp) */
@@ -241,7 +221,7 @@ exception_common:
/* 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 */
ite eq /* Next two instructions conditional */
msreq msp, r0 /* R0=The main stack pointer */
msrne psp, r0 /* R0=The process stack pointer */
diff --git a/arch/arm/src/armv7-m/arm_initialstate.c b/arch/arm/src/armv7-m/arm_initialstate.c
index c86390abdc..fe42f23344 100644
--- a/arch/arm/src/armv7-m/arm_initialstate.c
+++ b/arch/arm/src/armv7-m/arm_initialstate.c
@@ -142,7 +142,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;
@@ -168,3 +168,45 @@ void up_initial_state(struct tcb_s *tcb)
#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();
+#else
+ uint32_t stack = (uint32_t)g_intstacktop;
+#endif
+ uint32_t temp = 0;
+
+ __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" (temp)
+ : "memory");
+}
+#endif
diff --git a/arch/arm/src/armv7-m/arm_schedulesigaction.c b/arch/arm/src/armv7-m/arm_schedulesigaction.c
index 127e66fe65..16a05c6f3a 100644
--- a/arch/arm/src/armv7-m/arm_schedulesigaction.c
+++ b/arch/arm/src/armv7-m/arm_schedulesigaction.c
@@ -160,8 +160,8 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
CURRENT_REGS[REG_XPSR] = ARMV7M_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
}
@@ -209,7 +209,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
tcb->xcp.regs[REG_XPSR] = ARMV7M_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
}
@@ -320,7 +320,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
tcb->xcp.regs[REG_XPSR] = ARMV7M_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
}
@@ -367,7 +367,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
CURRENT_REGS[REG_XPSR] = ARMV7M_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
}
@@ -430,7 +430,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#endif
tcb->xcp.regs[REG_XPSR] = ARMV7M_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
}
diff --git a/arch/arm/src/armv7-m/arm_svcall.c b/arch/arm/src/armv7-m/arm_svcall.c
index 336a64dfb7..c761a972a6 100644
--- a/arch/arm/src/armv7-m/arm_svcall.c
+++ b/arch/arm/src/armv7-m/arm_svcall.c
@@ -271,7 +271,7 @@ int arm_svcall(int irq, void *context, void *arg)
*/
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 */
@@ -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_EXC_RETURN] = EXC_RETURN_UNPRIVTHR;
+ regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* 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_EXC_RETURN] = EXC_RETURN_UNPRIVTHR;
+ regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return unprivileged mode */
@@ -390,7 +390,7 @@ int arm_svcall(int irq, void *context, void *arg)
DEBUGASSERT(rtcb->xcp.sigreturn != 0);
regs[REG_PC] = rtcb->xcp.sigreturn & ~1;
- regs[REG_EXC_RETURN] = EXC_RETURN_PRIVTHR;
+ regs[REG_EXC_RETURN] = EXC_RETURN_THREAD;
/* Return privileged mode */
@@ -428,7 +428,7 @@ int arm_svcall(int irq, void *context, void *arg)
rtcb->xcp.nsyscalls = index + 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 */
diff --git a/arch/arm/src/armv7-m/exc_return.h b/arch/arm/src/armv7-m/exc_return.h
index ddac01de57..079bddcd14 100644
--- a/arch/arm/src/armv7-m/exc_return.h
+++ b/arch/arm/src/armv7-m/exc_return.h
@@ -77,29 +77,28 @@
#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.
- */
-
#ifdef CONFIG_ARCH_FPU
-# define EXC_RETURN_PRIVTHR (EXC_RETURN_BASE | EXC_RETURN_THREAD_MODE)
+# define EXC_RETURN_FPU 0
#else
-# define EXC_RETURN_PRIVTHR (EXC_RETURN_BASE | EXC_RETURN_STD_CONTEXT | \
- EXC_RETURN_THREAD_MODE)
+# define EXC_RETURN_FPU EXC_RETURN_STD_CONTEXT
#endif
-/* EXC_RETURN_UNPRIVTHR: Return to unprivileged thread mode. Exception return
- * gets state from the process stack. Execution uses PSP after return.
- */
-
-#ifdef CONFIG_ARCH_FPU
-# define EXC_RETURN_UNPRIVTHR (EXC_RETURN_BASE | EXC_RETURN_THREAD_MODE | \
- EXC_RETURN_PROCESS_STACK)
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+# define EXC_RETURN_STACK EXC_RETURN_PROCESS_STACK
#else
-# define EXC_RETURN_UNPRIVTHR (EXC_RETURN_BASE | EXC_RETURN_STD_CONTEXT | \
- EXC_RETURN_THREAD_MODE | EXC_RETURN_PROCESS_STACK)
+# define EXC_RETURN_STACK 0
#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)
+
/****************************************************************************
* Inline Functions
****************************************************************************/
diff --git a/arch/arm/src/common/arm_initialize.c b/arch/arm/src/common/arm_initialize.c
index 2b457ef0f4..65a09495e5 100644
--- a/arch/arm/src/common/arm_initialize.c
+++ b/arch/arm/src/common/arm_initialize.c
@@ -97,6 +97,12 @@ static inline void arm_color_intstack(void)
void up_initialize(void)
{
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+ /* Reinitializes the stack pointer */
+
+ arm_initialize_stack();
+#endif
+
/* Colorize the interrupt stack */
arm_color_intstack();
diff --git a/arch/arm/src/common/arm_internal.h b/arch/arm/src/common/arm_internal.h
index 75918424c6..ca9517f2ce 100644
--- a/arch/arm/src/common/arm_internal.h
+++ b/arch/arm/src/common/arm_internal.h
@@ -346,6 +346,10 @@ uintptr_t arm_intstack_alloc(void);
uintptr_t arm_intstack_top(void);
#endif
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+void weak_function arm_initialize_stack(void);
+#endif
+
/* Exception handling logic unique to the Cortex-M family */
#if defined(CONFIG_ARCH_ARMV6M) || defined(CONFIG_ARCH_ARMV7M) || \
diff --git a/arch/arm/src/cxd56xx/chip.h b/arch/arm/src/cxd56xx/chip.h
index c43ff78000..2e6f3e9e08 100644
--- a/arch/arm/src/cxd56xx/chip.h
+++ b/arch/arm/src/cxd56xx/chip.h
@@ -49,24 +49,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 > 7
- .macro setintstack, tmp1, tmp2
- ldr \tmp1, =CXD56_ADSP_PID
- ldr \tmp1, [\tmp1, 0]
- sub \tmp1, 2 /* tmp1 = getreg32(CXD56_ADSP_PID) - 2 */
- ldr \tmp2, =g_cpu_intstack_top
- ldr sp, [\tmp2, \tmp1, lsl #2] /* sp = g_cpu_intstack_top[tmp1] */
- .endm
-#endif /* CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 7 */
-
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_CXD56XX_CHIP_H */
diff --git a/arch/arm/src/cxd56xx/cxd56_cpustart.c b/arch/arm/src/cxd56xx/cxd56_cpustart.c
index c2071ea718..6f79626b41 100644
--- a/arch/arm/src/cxd56xx/cxd56_cpustart.c
+++ b/arch/arm/src/cxd56xx/cxd56_cpustart.c
@@ -97,6 +97,12 @@ static void appdsp_boot(void)
cpu = up_cpu_index();
DPRINTF("cpu = %d\n", cpu);
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+ /* Initializes the stack pointer */
+
+ arm_initialize_stack();
+#endif
+
/* Setup NVIC */
up_irqinitialize();
diff --git a/arch/arm/src/lc823450/chip.h b/arch/arm/src/lc823450/chip.h
index 952d6018c8..5a703f6c35 100644
--- a/arch/arm/src/lc823450/chip.h
+++ b/arch/arm/src/lc823450/chip.h
@@ -58,23 +58,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 > 7
- .macro setintstack, tmp1, tmp2
- ldr \tmp1, =CORE_COREID
- ldr \tmp1, [\tmp1, 0] /* tmp1 = getreg32(CORE_COREID) */
- ldr \tmp2, =g_cpu_intstack_top
- ldr sp, [\tmp2, \tmp1, lsl #2] /* sp = g_cpu_intstack_top[tmp1] */
- .endm
-#endif /* CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 7 */
-
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_SRC_LC823450_CHIP_H */
diff --git a/arch/arm/src/lc823450/lc823450_cpustart.c b/arch/arm/src/lc823450/lc823450_cpustart.c
index 5fe44bd671..908eddec82 100644
--- a/arch/arm/src/lc823450/lc823450_cpustart.c
+++ b/arch/arm/src/lc823450/lc823450_cpustart.c
@@ -89,6 +89,12 @@ static void cpu1_boot(void)
DPRINTF("cpu = %d\n", cpu);
+#if CONFIG_ARCH_INTERRUPTSTACK > 7
+ /* Initializes the stack pointer */
+
+ arm_initialize_stack();
+#endif
+
if (cpu == 1)
{
putreg32((uint32_t)_stext, NVIC_VECTAB); /* use CPU0 vectors */