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();