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

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new d215909fd9b arch/arm: armv6/7/8-m: dispatch PendSV only if a handler 
is attached
d215909fd9b is described below

commit d215909fd9b0bd8b0f97637972e216edd02de44a
Author: Alan Carvalho de Assis <[email protected]>
AuthorDate: Thu Nov 5 09:37:24 2026 -0300

    arch/arm: armv6/7/8-m: dispatch PendSV only if a handler is attached
    
    With CONFIG_ARCH_HIPRI_INTERRUPT, arm_doirq() passes PendSV to
    irq_dispatch(), because a high priority interrupt can pend PendSV to get
    back into the OS and a handler may be attached for that.
    
    But the OS also pends PendSV itself: up_schedule_sigaction() does it to
    deliver a signal to the running task, and exception_direct() to switch
    context.  When no handler is attached, irq_dispatch() then calls
    irq_unexpected_isr() and the system panics.  This was seen on an
    i.MX RT1052 board (ddcnc-ec300) using a zero latency interrupt: the
    first PHY notification signal to the NETINIT monitor thread halted the
    system, before the network interface was ever brought up.
    
    Dispatch PendSV only when a handler was attached to it, and otherwise
    continue with the normal PendSV processing, as without
    CONFIG_ARCH_HIPRI_INTERRUPT.
    
    Note: many chips attach a diagnostic PendSV handler that panics (when
    CONFIG_DEBUG_FEATURES is set) without checking for
    CONFIG_ARCH_HIPRI_INTERRUPT, e.g. imxrt, stm32f7, samv7, kinetis,
    lpc43xx, rp2040, nrf53, s32k3xx; stm32h7, stm32l4 and nrf52 already
    skip the panic in that case.  Such a handler is only reached when
    PendSV is dispatched, which happens only with high priority
    interrupts, where PendSV is not an error.
    
    Tested on the ddcnc-ec300 (Cortex-M7) with a zero latency step timer
    interrupt: the network comes up and signals are delivered.  Build
    tested for armv6-m (nucleo-g071rb:nsh), armv7-m with and without
    CONFIG_ARCH_HIPRI_INTERRUPT, and armv8-m with it (nucleo-l552ze:nsh).
    
    Signed-off-by: Alan Carvalho de Assis <[email protected]>
    Assisted-by: Claude Opus 5.5
---
 arch/arm/src/armv6-m/arm_doirq.c | 37 +++++++++++++++++++++++++++++++++++--
 arch/arm/src/armv7-m/arm_doirq.c | 36 ++++++++++++++++++++++++++++++++++--
 arch/arm/src/armv8-m/arm_doirq.c | 36 ++++++++++++++++++++++++++++++++++--
 3 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/arch/arm/src/armv6-m/arm_doirq.c b/arch/arm/src/armv6-m/arm_doirq.c
index a94d8a20b78..b5126ab4540 100644
--- a/arch/arm/src/armv6-m/arm_doirq.c
+++ b/arch/arm/src/armv6-m/arm_doirq.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <assert.h>
 
@@ -34,11 +35,39 @@
 #include <nuttx/board.h>
 #include <arch/board/board.h>
 #include <sched/sched.h>
+#include "irq/irq.h"
 
 #include "arm_internal.h"
 #include "exc_return.h"
 #include "nvic.h"
 
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
+/****************************************************************************
+ * Name: arm_pendsv_attached
+ *
+ * Description:
+ *   With high priority interrupts, PendSV is the way a high priority
+ *   interrupt gets back into the OS, so a handler may be attached to it.
+ *   But the OS also pends PendSV itself (up_schedule_sigaction() to deliver
+ *   a signal to the running task, exception_direct()).  So PendSV is only
+ *   dispatched if a handler was attached: otherwise it would end in
+ *   irq_unexpected_isr() and a kernel panic.
+ *
+ ****************************************************************************/
+
+static inline bool arm_pendsv_attached(void)
+{
+  int ndx = IRQ_TO_NDX(NVIC_IRQ_PENDSV);
+
+  return ndx >= 0 && g_irqvector[ndx].handler != NULL &&
+         g_irqvector[ndx].handler != irq_unexpected_isr;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -84,10 +113,14 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
   if (irq == NVIC_IRQ_PENDSV)
     {
 #ifdef CONFIG_ARCH_HIPRI_INTERRUPT
-      /* Dispatch the PendSV interrupt */
+      /* Dispatch the PendSV interrupt, if a handler is attached */
 
-      irq_dispatch(irq, regs);
+      if (arm_pendsv_attached())
+        {
+          irq_dispatch(irq, regs);
+        }
 #endif
+
       up_irq_save();
     }
   else
diff --git a/arch/arm/src/armv7-m/arm_doirq.c b/arch/arm/src/armv7-m/arm_doirq.c
index a70e909c167..1b8927caf6e 100644
--- a/arch/arm/src/armv7-m/arm_doirq.c
+++ b/arch/arm/src/armv7-m/arm_doirq.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <assert.h>
 
@@ -34,11 +35,39 @@
 #include <nuttx/board.h>
 #include <arch/board/board.h>
 #include <sched/sched.h>
+#include "irq/irq.h"
 
 #include "arm_internal.h"
 #include "exc_return.h"
 #include "nvic.h"
 
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
+/****************************************************************************
+ * Name: arm_pendsv_attached
+ *
+ * Description:
+ *   With high priority interrupts, PendSV is the way a high priority
+ *   interrupt gets back into the OS, so a handler may be attached to it.
+ *   But the OS also pends PendSV itself (up_schedule_sigaction() to deliver
+ *   a signal to the running task, exception_direct()).  So PendSV is only
+ *   dispatched if a handler was attached: otherwise it would end in
+ *   irq_unexpected_isr() and a kernel panic.
+ *
+ ****************************************************************************/
+
+static inline bool arm_pendsv_attached(void)
+{
+  int ndx = IRQ_TO_NDX(NVIC_IRQ_PENDSV);
+
+  return ndx >= 0 && g_irqvector[ndx].handler != NULL &&
+         g_irqvector[ndx].handler != irq_unexpected_isr;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -82,9 +111,12 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
   if (irq == NVIC_IRQ_PENDSV)
     {
 #ifdef CONFIG_ARCH_HIPRI_INTERRUPT
-      /* Dispatch the PendSV interrupt */
+      /* Dispatch the PendSV interrupt, if a handler is attached */
 
-      irq_dispatch(irq, regs);
+      if (arm_pendsv_attached())
+        {
+          irq_dispatch(irq, regs);
+        }
 #endif
 
       up_irq_save();
diff --git a/arch/arm/src/armv8-m/arm_doirq.c b/arch/arm/src/armv8-m/arm_doirq.c
index 8f2206aae1b..802e36516f9 100644
--- a/arch/arm/src/armv8-m/arm_doirq.c
+++ b/arch/arm/src/armv8-m/arm_doirq.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <assert.h>
 
@@ -34,12 +35,40 @@
 #include <nuttx/board.h>
 #include <arch/board/board.h>
 #include <sched/sched.h>
+#include "irq/irq.h"
 
 #include "arm_internal.h"
 #include "exc_return.h"
 #include "nvic.h"
 #include "psr.h"
 
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_ARCH_HIPRI_INTERRUPT
+/****************************************************************************
+ * Name: arm_pendsv_attached
+ *
+ * Description:
+ *   With high priority interrupts, PendSV is the way a high priority
+ *   interrupt gets back into the OS, so a handler may be attached to it.
+ *   But the OS also pends PendSV itself (up_schedule_sigaction() to deliver
+ *   a signal to the running task, exception_direct()).  So PendSV is only
+ *   dispatched if a handler was attached: otherwise it would end in
+ *   irq_unexpected_isr() and a kernel panic.
+ *
+ ****************************************************************************/
+
+static inline bool arm_pendsv_attached(void)
+{
+  int ndx = IRQ_TO_NDX(NVIC_IRQ_PENDSV);
+
+  return ndx >= 0 && g_irqvector[ndx].handler != NULL &&
+         g_irqvector[ndx].handler != irq_unexpected_isr;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -94,9 +123,12 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
   if (irq == NVIC_IRQ_PENDSV)
     {
 #ifdef CONFIG_ARCH_HIPRI_INTERRUPT
-      /* Dispatch the PendSV interrupt */
+      /* Dispatch the PendSV interrupt, if a handler is attached */
 
-      irq_dispatch(irq, regs);
+      if (arm_pendsv_attached())
+        {
+          irq_dispatch(irq, regs);
+        }
 #endif
 
       up_irq_save();

Reply via email to