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 f164840ff3f arch/armv7-a: End the process of a user fault, not the 
system.
f164840ff3f is described below

commit f164840ff3f46d05baab144cf1ff5b63db6bfd02
Author: Marco Casaroli <[email protected]>
AuthorDate: Wed Oct 21 14:20:13 2026 +0200

    arch/armv7-a: End the process of a user fault, not the system.
    
    A data abort, a prefetch abort or an undefined instruction of user code
    caused a panic of the whole system, also in the kernel build.  As on
    arm64 and RISC-V, it now ends only the task with SIGSEGV: the exception
    returns to _exit() in SYS mode, on the kernel stack of the task if it
    has one.  A fault of the kernel, also of a system call, is fatal as
    before.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 arch/arm/src/armv7-a/CMakeLists.txt                |  1 +
 arch/arm/src/armv7-a/Make.defs                     |  2 +-
 arch/arm/src/armv7-a/arm.h                         | 11 ++++
 arch/arm/src/armv7-a/arm_dataabort.c               |  5 +-
 arch/arm/src/armv7-a/arm_prefetchabort.c           |  5 +-
 arch/arm/src/armv7-a/arm_undefinedinsn.c           | 11 +++-
 .../{arm_undefinedinsn.c => arm_userfault.c}       | 67 ++++++++++++++++------
 7 files changed, 79 insertions(+), 23 deletions(-)

diff --git a/arch/arm/src/armv7-a/CMakeLists.txt 
b/arch/arm/src/armv7-a/CMakeLists.txt
index 27cfd8bbb82..029fdfecf9b 100644
--- a/arch/arm/src/armv7-a/CMakeLists.txt
+++ b/arch/arm/src/armv7-a/CMakeLists.txt
@@ -46,6 +46,7 @@ list(
   arm_syscall.c
   arm_tcbinfo.c
   arm_undefinedinsn.c
+  arm_userfault.c
   arm_perf.c
   cp15_cacheops.c)
 
diff --git a/arch/arm/src/armv7-a/Make.defs b/arch/arm/src/armv7-a/Make.defs
index 07154bda712..4bcc3938d43 100644
--- a/arch/arm/src/armv7-a/Make.defs
+++ b/arch/arm/src/armv7-a/Make.defs
@@ -39,7 +39,7 @@ CMN_CSRCS += arm_cache.c arm_cpuinfo.c arm_dataabort.c
 CMN_CSRCS += arm_doirq.c arm_gicv2.c arm_gicv2_dump.c
 CMN_CSRCS += arm_initialstate.c arm_mmu.c arm_prefetchabort.c
 CMN_CSRCS += arm_syscall.c arm_tcbinfo.c arm_undefinedinsn.c
-CMN_CSRCS += arm_perf.c cp15_cacheops.c
+CMN_CSRCS += arm_perf.c arm_userfault.c cp15_cacheops.c
 
 ifeq ($(CONFIG_ENABLE_ALL_SIGNALS),y)
 CMN_CSRCS += arm_schedulesigaction.c arm_sigdeliver.c
diff --git a/arch/arm/src/armv7-a/arm.h b/arch/arm/src/armv7-a/arm.h
index d9d78aec777..4593fab6463 100644
--- a/arch/arm/src/armv7-a/arm.h
+++ b/arch/arm/src/armv7-a/arm.h
@@ -111,6 +111,17 @@ extern "C"
 
 void arm_data_initialize(void);
 
+/****************************************************************************
+ * Name: arm_fault_kill
+ *
+ * Description:
+ *   End the task of a fault of user code with SIGSEGV.  Return false if
+ *   the fault is fatal.  See arm_userfault.c.
+ *
+ ****************************************************************************/
+
+bool arm_fault_kill(uint32_t *regs);
+
 #undef EXTERN
 #ifdef __cplusplus
 }
diff --git a/arch/arm/src/armv7-a/arm_dataabort.c 
b/arch/arm/src/armv7-a/arm_dataabort.c
index 5609b7bc7ee..cd707aa4373 100644
--- a/arch/arm/src/armv7-a/arm_dataabort.c
+++ b/arch/arm/src/armv7-a/arm_dataabort.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <assert.h>
 
@@ -33,12 +34,12 @@
 #include <nuttx/irq.h>
 
 #include "mmu.h"
+#include "arm.h"
 #include "sched/sched.h"
 #include "arm_internal.h"
 
 #ifdef CONFIG_LEGACY_PAGING
 #  include <nuttx/page.h>
-#  include "arm.h"
 #endif
 
 /****************************************************************************
@@ -169,7 +170,7 @@ uint32_t *arm_dataabort(uint32_t *regs, uint32_t dfar, 
uint32_t dfsr)
     {
       arm_dbgmonitor(0, (void *)dfar, regs);
     }
-  else
+  else if (!arm_fault_kill(regs))
     {
       PANIC_WITH_REGS("panic", regs);
     }
diff --git a/arch/arm/src/armv7-a/arm_prefetchabort.c 
b/arch/arm/src/armv7-a/arm_prefetchabort.c
index ab59f0fa069..e02a1fa1f4f 100644
--- a/arch/arm/src/armv7-a/arm_prefetchabort.c
+++ b/arch/arm/src/armv7-a/arm_prefetchabort.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <assert.h>
 
@@ -36,6 +37,7 @@
 #endif
 
 #include "mmu.h"
+#include "arm.h"
 #include "sched/sched.h"
 #include "arm_internal.h"
 
@@ -91,6 +93,7 @@ uint32_t *arm_prefetchabort(uint32_t *regs, uint32_t ifar, 
uint32_t ifsr)
        */
 
       struct tcb_s *tcb = this_task();
+
       tcb->xcp.far  = regs[REG_R15];
 
       /* Call pg_miss() to schedule the page fill.  A consequences of this
@@ -140,7 +143,7 @@ uint32_t *arm_prefetchabort(uint32_t *regs, uint32_t ifar, 
uint32_t ifsr)
     {
       arm_dbgmonitor(0, (void *)regs[REG_PC], regs);
     }
-  else
+  else if (!arm_fault_kill(regs))
     {
       PANIC_WITH_REGS("panic", regs);
     }
diff --git a/arch/arm/src/armv7-a/arm_undefinedinsn.c 
b/arch/arm/src/armv7-a/arm_undefinedinsn.c
index 7eb882448e0..cfd3d9d3b31 100644
--- a/arch/arm/src/armv7-a/arm_undefinedinsn.c
+++ b/arch/arm/src/armv7-a/arm_undefinedinsn.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
 #include <stdint.h>
 #include <assert.h>
 #include <nuttx/debug.h>
@@ -33,6 +34,7 @@
 #include <nuttx/arch.h>
 #include <sched/sched.h>
 
+#include "arm.h"
 #include "arm_internal.h"
 
 /****************************************************************************
@@ -60,6 +62,11 @@ uint32_t *arm_undefinedinsn(uint32_t *regs)
       _alert("Undefined instruction at 0x%" PRIx32 "\n", regs[REG_PC]);
     }
 
-  PANIC_WITH_REGS("panic", regs);
-  return regs; /* To keep the compiler happy */
+  if (!arm_fault_kill(regs))
+    {
+      PANIC_WITH_REGS("panic", regs);
+    }
+
+  up_set_interrupt_context(false);
+  return regs;
 }
diff --git a/arch/arm/src/armv7-a/arm_undefinedinsn.c 
b/arch/arm/src/armv7-a/arm_userfault.c
similarity index 53%
copy from arch/arm/src/armv7-a/arm_undefinedinsn.c
copy to arch/arm/src/armv7-a/arm_userfault.c
index 7eb882448e0..96a890a9b9b 100644
--- a/arch/arm/src/armv7-a/arm_undefinedinsn.c
+++ b/arch/arm/src/armv7-a/arm_userfault.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/arm/src/armv7-a/arm_undefinedinsn.c
+ * arch/arm/src/armv7-a/arm_userfault.c
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -26,13 +26,16 @@
 
 #include <nuttx/config.h>
 
+#include <stdbool.h>
 #include <stdint.h>
-#include <assert.h>
-#include <nuttx/debug.h>
+#include <signal.h>
+#include <unistd.h>
 
-#include <nuttx/arch.h>
-#include <sched/sched.h>
+#include <nuttx/debug.h>
+#include <nuttx/irq.h>
 
+#include "arm.h"
+#include "sched/sched.h"
 #include "arm_internal.h"
 
 /****************************************************************************
@@ -40,26 +43,56 @@
  ****************************************************************************/
 
 /****************************************************************************
- * Name: arm_undefinedinsn
+ * Name: arm_fault_kill
+ *
+ * Description:
+ *   A fault of user code ends the process (SIGSEGV), not the system: the
+ *   abort returns to _exit() in SYS mode, on the kernel stack of the task
+ *   if it has one.  A fault of the kernel (also of a system call) is not
+ *   handled here.
+ *
+ * Input Parameters:
+ *   regs - The register state of the abort
+ *
+ * Returned Value:
+ *   True if the task ends; false if the abort is fatal.
+ *
  ****************************************************************************/
 
-uint32_t *arm_undefinedinsn(uint32_t *regs)
+bool arm_fault_kill(uint32_t *regs)
 {
   struct tcb_s *tcb = this_task();
+  struct tcb_s *ptcb;
 
-  tcb->xcp.regs = regs;
-  up_set_interrupt_context(true);
-
-  if (regs[REG_PC] >= (uint32_t)_stext && regs[REG_PC] < (uint32_t)_etext)
+  if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_KERNEL ||
+      (tcb->flags & TCB_FLAG_SYSCALL) != 0 ||
+      (regs[REG_CPSR] & PSR_MODE_MASK) != PSR_MODE_USR)
     {
-      _alert("Undefined instruction at 0x%" PRIx32 ": 0x%" PRIx32 "\n",
-             regs[REG_PC], *(uint32_t *)regs[REG_PC]);
+      return false;
     }
-  else
+
+  ptcb = nxsched_get_tcb(tcb->group->tg_pid);
+  _alert("Segmentation fault in %s (PID %d: %s)\n",
+         ptcb != NULL ? get_task_name(ptcb) : "<gone>",
+         tcb->pid, get_task_name(tcb));
+
+  tcb->flags |= TCB_FLAG_FORCED_CANCEL;
+
+  regs[REG_PC]   = (uint32_t)_exit;
+  regs[REG_R0]   = SIGSEGV;
+  regs[REG_CPSR] = PSR_MODE_SYS;
+#ifdef CONFIG_ARM_THUMB
+  regs[REG_CPSR] |= PSR_T_BIT;
+#endif
+
+#ifdef CONFIG_ARCH_KERNEL_STACK
+  /* The frames on the kernel stack are no longer needed */
+
+  if (tcb->xcp.kstack != NULL)
     {
-      _alert("Undefined instruction at 0x%" PRIx32 "\n", regs[REG_PC]);
+      regs[REG_SP] = (uint32_t)tcb->xcp.kstack + ARCH_KERNEL_STACKSIZE;
     }
+#endif
 
-  PANIC_WITH_REGS("panic", regs);
-  return regs; /* To keep the compiler happy */
+  return true;
 }

Reply via email to