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 af3c159cffc13e933c6a89f85f9342272d24bc9a
Author: buxiasen <[email protected]>
AuthorDate: Wed Dec 4 14:08:51 2024 +0800

    arm-v6/7/8m: sigaction forward to pendsv
    
    For exception directly, tcb->xcp.regs should not be used.
    
    Signed-off-by: buxiasen <[email protected]>
---
 arch/arm/src/armv6-m/arm_doirq.c             | 10 ++++++++--
 arch/arm/src/armv6-m/arm_schedulesigaction.c | 16 +++++++++++++---
 arch/arm/src/armv7-m/arm_doirq.c             | 10 ++++++++--
 arch/arm/src/armv7-m/arm_schedulesigaction.c | 16 +++++++++++++---
 arch/arm/src/armv8-m/arm_doirq.c             | 10 ++++++++--
 arch/arm/src/armv8-m/arm_schedulesigaction.c | 16 +++++++++++++---
 6 files changed, 63 insertions(+), 15 deletions(-)

diff --git a/arch/arm/src/armv6-m/arm_doirq.c b/arch/arm/src/armv6-m/arm_doirq.c
index e3e6383e48..ae928c8e0e 100644
--- a/arch/arm/src/armv6-m/arm_doirq.c
+++ b/arch/arm/src/armv6-m/arm_doirq.c
@@ -57,7 +57,7 @@ void exception_direct(void)
 uint32_t *arm_doirq(int irq, uint32_t *regs)
 {
   struct tcb_s **running_task = &g_running_tasks[this_cpu()];
-  FAR struct tcb_s *tcb;
+  struct tcb_s *tcb           = *running_task;
 
   /* This judgment proves that (*running_task)->xcp.regs
    * is invalid, and we can safely overwrite it.
@@ -65,7 +65,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
 
   if (!(NVIC_IRQ_SVCALL == irq && regs[REG_R0] == SYS_restore_context))
     {
-      (*running_task)->xcp.regs = regs;
+      tcb->xcp.regs = regs;
     }
 
   board_autoled_on(LED_INIRQ);
@@ -84,6 +84,12 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
 
       irq_dispatch(irq, regs);
 #endif
+      if (tcb->sigdeliver)
+        {
+          /* Pendsv able to access running tcb with no critical section */
+
+          up_schedule_sigaction(tcb);
+        }
 
       up_irq_save();
     }
diff --git a/arch/arm/src/armv6-m/arm_schedulesigaction.c 
b/arch/arm/src/armv6-m/arm_schedulesigaction.c
index 7020982141..9702814cdb 100644
--- a/arch/arm/src/armv6-m/arm_schedulesigaction.c
+++ b/arch/arm/src/armv6-m/arm_schedulesigaction.c
@@ -37,6 +37,7 @@
 #include "sched/sched.h"
 #include "arm_internal.h"
 #include "irq/irq.h"
+#include "nvic.h"
 
 /****************************************************************************
  * Public Functions
@@ -80,13 +81,14 @@
 
 void up_schedule_sigaction(struct tcb_s *tcb)
 {
-  FAR struct tcb_s *rtcb = running_task();
+  struct tcb_s *rtcb = running_task();
+  uint32_t      ipsr = getipsr();
 
   /* First, handle some special cases when the signal is
    * being delivered to the currently executing task.
    */
 
-  if (tcb == rtcb && !up_interrupt_context())
+  if (tcb == rtcb && ipsr == 0)
     {
       /* In this case just deliver the signal now.
        * REVISIT:  Signal handle will run in a critical section!
@@ -95,7 +97,15 @@ void up_schedule_sigaction(struct tcb_s *tcb)
       (tcb->sigdeliver)(tcb);
       tcb->sigdeliver = NULL;
     }
-  else
+  else if (tcb == rtcb && ipsr != NVIC_IRQ_PENDSV)
+    {
+      /* Context switch should be done in pendsv, for exception directly
+       * last regs is not saved tcb->xcp.regs.
+       */
+
+      up_trigger_irq(NVIC_IRQ_PENDSV, 0);
+    }
+  else /* ipsr == NVIC_IRQ_PENDSV || tcb != rtcb */
     {
       /* Save the return PC, CPSR and either the BASEPRI or PRIMASK
        * registers (and perhaps also the LR).  These will be restored
diff --git a/arch/arm/src/armv7-m/arm_doirq.c b/arch/arm/src/armv7-m/arm_doirq.c
index dcbdd9dc12..8313073ffb 100644
--- a/arch/arm/src/armv7-m/arm_doirq.c
+++ b/arch/arm/src/armv7-m/arm_doirq.c
@@ -57,7 +57,7 @@ void exception_direct(void)
 uint32_t *arm_doirq(int irq, uint32_t *regs)
 {
   struct tcb_s **running_task = &g_running_tasks[this_cpu()];
-  FAR struct tcb_s *tcb;
+  struct tcb_s *tcb           = *running_task;
 
   /* This judgment proves that (*running_task)->xcp.regs
    * is invalid, and we can safely overwrite it.
@@ -65,7 +65,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
 
   if (!(NVIC_IRQ_SVCALL == irq && regs[REG_R0] == SYS_restore_context))
     {
-      (*running_task)->xcp.regs = regs;
+      tcb->xcp.regs = regs;
     }
 
   board_autoled_on(LED_INIRQ);
@@ -84,6 +84,12 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
 
       irq_dispatch(irq, regs);
 #endif
+      if (tcb->sigdeliver)
+        {
+          /* Pendsv able to access running tcb with no critical section */
+
+          up_schedule_sigaction(tcb);
+        }
 
       up_irq_save();
     }
diff --git a/arch/arm/src/armv7-m/arm_schedulesigaction.c 
b/arch/arm/src/armv7-m/arm_schedulesigaction.c
index 8987c36b3c..1825242110 100644
--- a/arch/arm/src/armv7-m/arm_schedulesigaction.c
+++ b/arch/arm/src/armv7-m/arm_schedulesigaction.c
@@ -38,6 +38,7 @@
 #include "sched/sched.h"
 #include "arm_internal.h"
 #include "irq/irq.h"
+#include "nvic.h"
 
 /****************************************************************************
  * Public Functions
@@ -81,13 +82,14 @@
 
 void up_schedule_sigaction(struct tcb_s *tcb)
 {
-  FAR struct tcb_s *rtcb = running_task();
+  struct tcb_s *rtcb = running_task();
+  uint32_t      ipsr = getipsr();
 
   /* First, handle some special cases when the signal is
    * being delivered to the currently executing task.
    */
 
-  if (tcb == rtcb && !up_interrupt_context())
+  if (tcb == rtcb && ipsr == 0)
     {
       /* In this case just deliver the signal now.
        * REVISIT:  Signal handle will run in a critical section!
@@ -96,7 +98,15 @@ void up_schedule_sigaction(struct tcb_s *tcb)
       (tcb->sigdeliver)(tcb);
       tcb->sigdeliver = NULL;
     }
-  else
+  else if (tcb == rtcb && ipsr != NVIC_IRQ_PENDSV)
+    {
+      /* Context switch should be done in pendsv, for exception directly
+       * last regs is not saved tcb->xcp.regs.
+       */
+
+      up_trigger_irq(NVIC_IRQ_PENDSV, 0);
+    }
+  else /* ipsr == NVIC_IRQ_PENDSV || tcb != rtcb */
     {
       /* Save the return PC, CPSR and either the BASEPRI or PRIMASK
        * registers (and perhaps also the LR).  These will be restored
diff --git a/arch/arm/src/armv8-m/arm_doirq.c b/arch/arm/src/armv8-m/arm_doirq.c
index 55183573a5..77cef0bde6 100644
--- a/arch/arm/src/armv8-m/arm_doirq.c
+++ b/arch/arm/src/armv8-m/arm_doirq.c
@@ -68,7 +68,7 @@ void exception_direct(void)
 uint32_t *arm_doirq(int irq, uint32_t *regs)
 {
   struct tcb_s **running_task = &g_running_tasks[this_cpu()];
-  FAR struct tcb_s *tcb;
+  struct tcb_s *tcb           = *running_task;
 
   /* This judgment proves that (*running_task)->xcp.regs
    * is invalid, and we can safely overwrite it.
@@ -76,7 +76,7 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
 
   if (!(NVIC_IRQ_SVCALL == irq && regs[REG_R0] == SYS_restore_context))
     {
-      (*running_task)->xcp.regs = regs;
+      tcb->xcp.regs = regs;
     }
 
   board_autoled_on(LED_INIRQ);
@@ -95,6 +95,12 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
 
       irq_dispatch(irq, regs);
 #endif
+      if (tcb->sigdeliver)
+        {
+          /* Pendsv able to access running tcb with no critical section */
+
+          up_schedule_sigaction(tcb);
+        }
 
       up_irq_save();
     }
diff --git a/arch/arm/src/armv8-m/arm_schedulesigaction.c 
b/arch/arm/src/armv8-m/arm_schedulesigaction.c
index 230f374eae..2983b2470a 100644
--- a/arch/arm/src/armv8-m/arm_schedulesigaction.c
+++ b/arch/arm/src/armv8-m/arm_schedulesigaction.c
@@ -38,6 +38,7 @@
 #include "sched/sched.h"
 #include "arm_internal.h"
 #include "irq/irq.h"
+#include "nvic.h"
 
 /****************************************************************************
  * Public Functions
@@ -81,13 +82,14 @@
 
 void up_schedule_sigaction(struct tcb_s *tcb)
 {
-  FAR struct tcb_s *rtcb = running_task();
+  struct tcb_s *rtcb = running_task();
+  uint32_t      ipsr = getipsr();
 
   /* First, handle some special cases when the signal is
    * being delivered to the currently executing task.
    */
 
-  if (tcb == rtcb && !up_interrupt_context())
+  if (tcb == rtcb && ipsr == 0)
     {
       /* In this case just deliver the signal now.
        * REVISIT:  Signal handle will run in a critical section!
@@ -96,7 +98,15 @@ void up_schedule_sigaction(struct tcb_s *tcb)
       (tcb->sigdeliver)(tcb);
       tcb->sigdeliver = NULL;
     }
-  else
+  else if (tcb == rtcb && ipsr != NVIC_IRQ_PENDSV)
+    {
+      /* Context switch should be done in pendsv, for exception directly
+       * last regs is not saved tcb->xcp.regs.
+       */
+
+      up_trigger_irq(NVIC_IRQ_PENDSV, 0);
+    }
+  else /* ipsr == NVIC_IRQ_PENDSV || tcb != rtcb */
     {
       /* Save the return PC, CPSR and either the BASEPRI or PRIMASK
        * registers (and perhaps also the LR).  These will be restored

Reply via email to