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 2024/10/09 17:01:26 UTC
(nuttx) 03/06: armv6/7/8m: use pendsv to handle context switch
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 780acd78271a986a571429a7609411e526ac7621
Author: ligd <li...@xiaomi.com>
AuthorDate: Thu Jul 18 21:22:27 2024 +0800
armv6/7/8m: use pendsv to handle context switch
This PR support Nested interrupt in armv6/7/8m:
There are two types of nested interrupt model:
Zero latency nested interrupt
Interrupt Priority Note
Data abort Highest
SVC 0x50
High irq1 0x60 ISR can't access system API
irq_save() 0x70
High irq2 0x80 ISR can't access system API
normal irq3 0xB0
We have already support this mode before this PR
Nested interrupt which interrupt level lower than up_irq_save()
Interrupt Priority Note
Data abort Highest
SVC 0x70
irq_save() 0x80
High irq1 0x90 ISR can access system API
High irq2 0xA0 ISR can access system API
normal irq3 0xB0
Now, this PR can support this mode
Signed-off-by: ligd <li...@xiaomi.com>
---
arch/arm/src/armv6-m/arm_doirq.c | 63 ++++++++++++-----------
arch/arm/src/armv6-m/arm_svcall.c | 1 -
arch/arm/src/armv6-m/arm_vectors.c | 9 +++-
arch/arm/src/armv7-m/arm_doirq.c | 63 ++++++++++++-----------
arch/arm/src/armv7-m/arm_svcall.c | 6 +--
arch/arm/src/armv7-m/arm_vectors.c | 6 ++-
arch/arm/src/armv8-m/arm_doirq.c | 100 +++++++++++--------------------------
arch/arm/src/armv8-m/arm_svcall.c | 5 +-
arch/arm/src/armv8-m/arm_vectors.c | 9 +++-
9 files changed, 120 insertions(+), 142 deletions(-)
diff --git a/arch/arm/src/armv6-m/arm_doirq.c b/arch/arm/src/armv6-m/arm_doirq.c
index 3065a4f4da..93703b4512 100644
--- a/arch/arm/src/armv6-m/arm_doirq.c
+++ b/arch/arm/src/armv6-m/arm_doirq.c
@@ -35,11 +35,25 @@
#include "arm_internal.h"
#include "exc_return.h"
+#include "nvic.h"
/****************************************************************************
* Public Functions
****************************************************************************/
+void exception_direct(void)
+{
+ int irq = getipsr();
+
+ arm_ack_irq(irq);
+ irq_dispatch(irq, NULL);
+
+ if (g_running_tasks[this_cpu()] != this_task())
+ {
+ up_trigger_irq(NVIC_IRQ_PENDSV, 0);
+ }
+}
+
uint32_t *arm_doirq(int irq, uint32_t *regs)
{
struct tcb_s *tcb = this_task();
@@ -49,19 +63,20 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
PANIC();
#else
- if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
- {
- tcb->xcp.regs = regs;
- up_set_current_regs(regs);
- }
-
/* Acknowledge the interrupt */
arm_ack_irq(irq);
- /* Deliver the IRQ */
-
- irq_dispatch(irq, regs);
+ if (irq == NVIC_IRQ_PENDSV)
+ {
+ up_irq_save();
+ g_running_tasks[this_cpu()]->xcp.regs = regs;
+ }
+ else
+ {
+ tcb->xcp.regs = 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
@@ -69,30 +84,20 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
* switch occurred during interrupt processing.
*/
- if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
- {
- tcb = this_task();
-
- if (regs != tcb->xcp.regs)
- {
- /* Update scheduler parameters */
-
- nxsched_suspend_scheduler(g_running_tasks[this_cpu()]);
- nxsched_resume_scheduler(tcb);
+ tcb = this_task();
- /* Record the new "running" task when context switch occurred.
- * g_running_tasks[] is only used by assertion logic for reporting
- * crashes.
- */
+ /* Update scheduler parameters */
- g_running_tasks[this_cpu()] = tcb;
- regs = tcb->xcp.regs;
- }
+ nxsched_suspend_scheduler(g_running_tasks[this_cpu()]);
+ nxsched_resume_scheduler(tcb);
- /* Update the current_regs to NULL. */
+ /* Record the new "running" task when context switch occurred.
+ * g_running_tasks[] is only used by assertion logic for reporting
+ * crashes.
+ */
- up_set_current_regs(NULL);
- }
+ g_running_tasks[this_cpu()] = tcb;
+ regs = tcb->xcp.regs;
#endif
board_autoled_off(LED_INIRQ);
diff --git a/arch/arm/src/armv6-m/arm_svcall.c b/arch/arm/src/armv6-m/arm_svcall.c
index 4bda7e1ad6..820a18ff83 100644
--- a/arch/arm/src/armv6-m/arm_svcall.c
+++ b/arch/arm/src/armv6-m/arm_svcall.c
@@ -121,7 +121,6 @@ int arm_svcall(int irq, void *context, void *arg)
uint32_t *regs = (uint32_t *)context;
uint32_t cmd;
- DEBUGASSERT(regs && regs == up_current_regs());
cmd = regs[REG_R0];
/* The SVCall software interrupt is called with R0 = system call command
diff --git a/arch/arm/src/armv6-m/arm_vectors.c b/arch/arm/src/armv6-m/arm_vectors.c
index 8beb9443c1..dbb336ae15 100644
--- a/arch/arm/src/armv6-m/arm_vectors.c
+++ b/arch/arm/src/armv6-m/arm_vectors.c
@@ -45,6 +45,8 @@
#include "chip.h"
#include "arm_internal.h"
+#include "ram_vectors.h"
+#include "nvic.h"
/****************************************************************************
* Pre-processor Definitions
@@ -81,6 +83,7 @@ static void start(void)
/* Common exception entrypoint */
extern void exception_common(void);
+extern void exception_direct(void);
/****************************************************************************
* Public data
@@ -92,7 +95,7 @@ extern void exception_common(void);
* As all exceptions (interrupts) are routed via exception_common, we just
* need to fill this array with pointers to it.
*
- * Note that the [ ... ] designated initialiser is a GCC extension.
+ * Note that the [ ... ] designated initializer is a GCC extension.
*/
const void * const _vectors[] locate_data(".vectors") =
@@ -107,5 +110,7 @@ const void * const _vectors[] locate_data(".vectors") =
/* Vectors 2 - n point directly at the generic handler */
- [2 ... (15 + ARMV6M_PERIPHERAL_INTERRUPTS)] = exception_common
+ [2 ... NVIC_IRQ_PENDSV] = &exception_common,
+ [(NVIC_IRQ_PENDSV + 1) ... (15 + ARMV6M_PERIPHERAL_INTERRUPTS)]
+ = &exception_direct
};
diff --git a/arch/arm/src/armv7-m/arm_doirq.c b/arch/arm/src/armv7-m/arm_doirq.c
index 5c31de792e..b74414c59a 100644
--- a/arch/arm/src/armv7-m/arm_doirq.c
+++ b/arch/arm/src/armv7-m/arm_doirq.c
@@ -35,11 +35,25 @@
#include "arm_internal.h"
#include "exc_return.h"
+#include "nvic.h"
/****************************************************************************
* Public Functions
****************************************************************************/
+void exception_direct(void)
+{
+ int irq = getipsr();
+
+ arm_ack_irq(irq);
+ irq_dispatch(irq, NULL);
+
+ if (g_running_tasks[this_cpu()] != this_task())
+ {
+ up_trigger_irq(NVIC_IRQ_PENDSV, 0);
+ }
+}
+
uint32_t *arm_doirq(int irq, uint32_t *regs)
{
struct tcb_s *tcb = this_task();
@@ -49,19 +63,20 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
PANIC();
#else
- if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
- {
- tcb->xcp.regs = regs;
- up_set_current_regs(regs);
- }
-
/* Acknowledge the interrupt */
arm_ack_irq(irq);
- /* Deliver the IRQ */
-
- irq_dispatch(irq, regs);
+ if (irq == NVIC_IRQ_PENDSV)
+ {
+ up_irq_save();
+ g_running_tasks[this_cpu()]->xcp.regs = regs;
+ }
+ else
+ {
+ tcb->xcp.regs = 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
@@ -69,30 +84,20 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
* switch occurred during interrupt processing.
*/
- if (regs[REG_EXC_RETURN] & EXC_RETURN_THREAD_MODE)
- {
- tcb = this_task();
-
- if (regs != tcb->xcp.regs)
- {
- /* Update scheduler parameters */
-
- nxsched_suspend_scheduler(g_running_tasks[this_cpu()]);
- nxsched_resume_scheduler(tcb);
+ tcb = this_task();
- /* Record the new "running" task when context switch occurred.
- * g_running_tasks[] is only used by assertion logic for reporting
- * crashes.
- */
+ /* Update scheduler parameters */
- g_running_tasks[this_cpu()] = tcb;
- regs = tcb->xcp.regs;
- }
+ nxsched_suspend_scheduler(g_running_tasks[this_cpu()]);
+ nxsched_resume_scheduler(tcb);
- /* Update the current_regs to NULL. */
+ /* Record the new "running" task when context switch occurred.
+ * g_running_tasks[] is only used by assertion logic for reporting
+ * crashes.
+ */
- up_set_current_regs(NULL);
- }
+ g_running_tasks[this_cpu()] = tcb;
+ regs = tcb->xcp.regs;
#endif
board_autoled_off(LED_INIRQ);
diff --git a/arch/arm/src/armv7-m/arm_svcall.c b/arch/arm/src/armv7-m/arm_svcall.c
index 1ccd70650d..d00c394c82 100644
--- a/arch/arm/src/armv7-m/arm_svcall.c
+++ b/arch/arm/src/armv7-m/arm_svcall.c
@@ -129,7 +129,6 @@ int arm_svcall(int irq, void *context, void *arg)
uint32_t *regs = (uint32_t *)context;
uint32_t cmd;
- DEBUGASSERT(regs && regs == up_current_regs());
cmd = regs[REG_R0];
/* The SVCall software interrupt is called with R0 = system call command
@@ -299,8 +298,9 @@ int arm_svcall(int irq, void *context, void *arg)
* At this point, the following values are saved in context:
*
* R0 = SYS_pthread_start
- * R1 = entrypt
- * R2 = arg
+ * R1 = startup (trampoline)
+ * R2 = entrypt
+ * R3 = arg
*/
#if !defined(CONFIG_BUILD_FLAT) && !defined(CONFIG_DISABLE_PTHREAD)
diff --git a/arch/arm/src/armv7-m/arm_vectors.c b/arch/arm/src/armv7-m/arm_vectors.c
index c4674ab20f..f007d021f0 100644
--- a/arch/arm/src/armv7-m/arm_vectors.c
+++ b/arch/arm/src/armv7-m/arm_vectors.c
@@ -41,6 +41,7 @@
#include "chip.h"
#include "arm_internal.h"
#include "ram_vectors.h"
+#include "nvic.h"
/****************************************************************************
* Pre-processor Definitions
@@ -71,6 +72,7 @@ static void start(void)
/* Common exception entrypoint */
extern void exception_common(void);
+extern void exception_direct(void);
/****************************************************************************
* Public data
@@ -98,5 +100,7 @@ const void * const _vectors[] locate_data(".vectors")
/* Vectors 2 - n point directly at the generic handler */
- [2 ... (15 + ARMV7M_PERIPHERAL_INTERRUPTS)] = exception_common
+ [2 ... NVIC_IRQ_PENDSV] = &exception_common,
+ [(NVIC_IRQ_PENDSV + 1) ... (15 + ARMV7M_PERIPHERAL_INTERRUPTS)]
+ = &exception_direct
};
diff --git a/arch/arm/src/armv8-m/arm_doirq.c b/arch/arm/src/armv8-m/arm_doirq.c
index 3e2fe2e961..536d7c4e75 100644
--- a/arch/arm/src/armv8-m/arm_doirq.c
+++ b/arch/arm/src/armv8-m/arm_doirq.c
@@ -35,60 +35,25 @@
#include "arm_internal.h"
#include "exc_return.h"
+#include "nvic.h"
/****************************************************************************
- * Inline Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: arm_from_thread
- *
- * Description:
- * If not defined CONFIG_ARCH_HAVE_TRUSTZONE
- * Return true if interrupt return to thread mode, false otherwise.
- *
- * If defined CONFIG_ARCH_HAVE_TRUSTZONE
- * Return true if interrupt return to thread mode, or if it is the first
- * interrupt from TEE to REE, or REE to TEE, false otherwise.
- *
- * Interrupt nesting between TEE and REE can be determined based
- * on the S and ES bits of EXC_RETURN
- * If TEE interrupts REE, then EXC_RETURN.S=0, EXC_RETURN.ES=1;
- * Conversely, EXC_RETURN.S=1, EXC_RETURN.ES=0.
- *
- * But only one level nesting between TEE and REE is supported, and
- * recursive nesting between TEE and REE is not supported.
- *
+ * Public Functions
****************************************************************************/
-static inline bool arm_from_thread(uint32_t excret)
+void exception_direct(void)
{
- if (excret & EXC_RETURN_THREAD_MODE)
- {
- return true;
- }
+ int irq = getipsr();
-#if defined(CONFIG_ARCH_TRUSTZONE_SECURE)
- if (!(excret & EXC_RETURN_SECURE_STACK) &&
- (excret & EXC_RETURN_EXC_SECURE))
- {
- return true;
- }
+ arm_ack_irq(irq);
+ irq_dispatch(irq, NULL);
- if (!(excret & EXC_RETURN_EXC_SECURE) &&
- (excret & EXC_RETURN_SECURE_STACK))
+ if (g_running_tasks[this_cpu()] != this_task())
{
- return true;
+ up_trigger_irq(NVIC_IRQ_PENDSV, 0);
}
-#endif
-
- return false;
}
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
uint32_t *arm_doirq(int irq, uint32_t *regs)
{
struct tcb_s *tcb = this_task();
@@ -98,19 +63,20 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
PANIC();
#else
- if (arm_from_thread(regs[REG_EXC_RETURN]))
- {
- tcb->xcp.regs = regs;
- up_set_current_regs(regs);
- }
-
/* Acknowledge the interrupt */
arm_ack_irq(irq);
- /* Deliver the IRQ */
-
- irq_dispatch(irq, regs);
+ if (irq == NVIC_IRQ_PENDSV)
+ {
+ up_irq_save();
+ g_running_tasks[this_cpu()]->xcp.regs = regs;
+ }
+ else
+ {
+ tcb->xcp.regs = 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
@@ -118,30 +84,20 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
* switch occurred during interrupt processing.
*/
- if (arm_from_thread(regs[REG_EXC_RETURN]))
- {
- tcb = this_task();
+ tcb = this_task();
- if (regs != tcb->xcp.regs)
- {
- /* Update scheduler parameters */
+ /* Update scheduler parameters */
- nxsched_suspend_scheduler(g_running_tasks[this_cpu()]);
- nxsched_resume_scheduler(tcb);
+ nxsched_suspend_scheduler(g_running_tasks[this_cpu()]);
+ nxsched_resume_scheduler(tcb);
- /* Record the new "running" task when context switch occurred.
- * g_running_tasks[] is only used by assertion logic for reporting
- * crashes.
- */
-
- g_running_tasks[this_cpu()] = tcb;
- regs = tcb->xcp.regs;
- }
-
- /* Update the current_regs to NULL. */
+ /* Record the new "running" task when context switch occurred.
+ * g_running_tasks[] is only used by assertion logic for reporting
+ * crashes.
+ */
- up_set_current_regs(NULL);
- }
+ g_running_tasks[this_cpu()] = tcb;
+ regs = tcb->xcp.regs;
#endif
board_autoled_off(LED_INIRQ);
diff --git a/arch/arm/src/armv8-m/arm_svcall.c b/arch/arm/src/armv8-m/arm_svcall.c
index f364767c40..3af74d1ac0 100644
--- a/arch/arm/src/armv8-m/arm_svcall.c
+++ b/arch/arm/src/armv8-m/arm_svcall.c
@@ -24,6 +24,7 @@
#include <nuttx/config.h>
+#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
@@ -128,7 +129,6 @@ int arm_svcall(int irq, void *context, void *arg)
uint32_t *regs = (uint32_t *)context;
uint32_t cmd;
- DEBUGASSERT(regs && regs == up_current_regs());
cmd = regs[REG_R0];
/* The SVCall software interrupt is called with R0 = system call command
@@ -398,7 +398,6 @@ int arm_svcall(int irq, void *context, void *arg)
/* Return privileged mode */
regs[REG_CONTROL] = getcontrol() & ~CONTROL_NPRIV;
-
rtcb->xcp.sigreturn = 0;
}
break;
@@ -447,7 +446,7 @@ int arm_svcall(int irq, void *context, void *arg)
rtcb->flags |= TCB_FLAG_SYSCALL;
#else
- svcerr("ERROR: Bad SYS call: %d\n", (int)regs[REG_R0]);
+ svcerr("ERROR: Bad SYS call: %" PRId32 "\n", regs[REG_R0]);
#endif
}
break;
diff --git a/arch/arm/src/armv8-m/arm_vectors.c b/arch/arm/src/armv8-m/arm_vectors.c
index 75308996e1..5f83341c1b 100644
--- a/arch/arm/src/armv8-m/arm_vectors.c
+++ b/arch/arm/src/armv8-m/arm_vectors.c
@@ -40,6 +40,8 @@
#include "chip.h"
#include "arm_internal.h"
+#include "ram_vectors.h"
+#include "nvic.h"
/****************************************************************************
* Pre-processor Definitions
@@ -74,12 +76,13 @@ static void start(void)
/* Common exception entrypoint */
extern void exception_common(void);
+extern void exception_direct(void);
/****************************************************************************
* Public data
****************************************************************************/
-/* The v7m vector table consists of an array of function pointers, with the
+/* The v8m vector table consists of an array of function pointers, with the
* first slot (vector zero) used to hold the initial stack pointer.
*
* As all exceptions (interrupts) are routed via exception_common, we just
@@ -100,5 +103,7 @@ const void * const _vectors[] locate_data(".vectors") =
/* Vectors 2 - n point directly at the generic handler */
- [2 ... (15 + ARMV8M_PERIPHERAL_INTERRUPTS)] = &exception_common
+ [2 ... NVIC_IRQ_PENDSV] = &exception_common,
+ [(NVIC_IRQ_PENDSV + 1) ... (15 + ARMV8M_PERIPHERAL_INTERRUPTS)]
+ = &exception_direct
};