This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch releases/12.7
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 8b8a2610abceb1f8b90a79e28512d8e4f39fb132
Author: ligd <[email protected]>
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 <[email protected]>
---
 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 62f57e302a..bab2404669 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 6c6f507aec..bfa2dc59f8 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 aeb427322c..0eef206fdf 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
 };

Reply via email to