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

archer 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 5cd57fa27e5 arch/arm64: handle fatal user exception
5cd57fa27e5 is described below

commit 5cd57fa27e53be50057d6591bbd0276b5a4f100e
Author: Jari Nippula <[email protected]>
AuthorDate: Mon Mar 2 15:57:18 2026 +0200

    arch/arm64: handle fatal user exception
    
    Print user exception reason class and description
    Print register dump
    
    Signed-off-by: Jari Nippula <[email protected]>
---
 arch/arm64/src/common/arm64_fatal.c | 191 ++++++++++++++++++++++++++++--------
 1 file changed, 149 insertions(+), 42 deletions(-)

diff --git a/arch/arm64/src/common/arm64_fatal.c 
b/arch/arm64/src/common/arm64_fatal.c
index e9c23e2dee6..5f39e23ed44 100644
--- a/arch/arm64/src/common/arm64_fatal.c
+++ b/arch/arm64/src/common/arm64_fatal.c
@@ -477,6 +477,112 @@ static int arm64_el1_exception_handler(uint64_t esr,
   return ret;
 }
 
+static void arm64_get_exception_info(uint64_t el, uint64_t *esr,
+                                     uint64_t *far, uint64_t *elr,
+                                     const char **el_str)
+{
+  switch (el)
+    {
+      case MODE_EL1:
+        {
+          if (el_str != NULL)
+            {
+              *el_str = "MODE_EL1";
+            }
+
+          if (esr != NULL)
+            {
+              *esr = read_sysreg(esr_el1);
+            }
+
+          if (far != NULL)
+            {
+              *far = read_sysreg(far_el1);
+            }
+
+          if (elr != NULL)
+            {
+              *elr = read_sysreg(elr_el1);
+            }
+          break;
+        }
+
+      case MODE_EL2:
+        {
+          if (el_str != NULL)
+            {
+              *el_str = "MODE_EL2";
+            }
+
+          if (esr != NULL)
+            {
+              *esr = read_sysreg(esr_el2);
+            }
+
+          if (far != NULL)
+            {
+              *far = read_sysreg(far_el2);
+            }
+
+          if (elr != NULL)
+            {
+              *elr = read_sysreg(elr_el2);
+            }
+          break;
+        }
+
+#ifdef CONFIG_ARCH_HAVE_EL3
+      case MODE_EL3:
+        {
+          if (el_str != NULL)
+            {
+              *el_str = "MODE_EL3";
+            }
+
+          if (esr != NULL)
+            {
+              *esr = read_sysreg(esr_el3);
+            }
+
+          if (far != NULL)
+            {
+              *far = read_sysreg(far_el3);
+            }
+
+          if (elr != NULL)
+            {
+              *elr = read_sysreg(elr_el3);
+            }
+          break;
+        }
+#endif
+
+      default:
+        {
+          if (el_str != NULL)
+            {
+              *el_str = "Unknown";
+            }
+
+          if (esr != NULL)
+            {
+              *esr = 0;
+            }
+
+          if (far != NULL)
+            {
+              *far = 0;
+            }
+
+          if (elr != NULL)
+            {
+              *elr = 0;
+            }
+          break;
+        }
+    }
+}
+
 static int arm64_exception_handler(uint64_t *regs)
 {
   uint64_t    el;
@@ -487,50 +593,13 @@ static int arm64_exception_handler(uint64_t *regs)
   int         ret = -EINVAL;
 
   el = arm64_current_el();
+  arm64_get_exception_info(el, &esr, &far, &elr, &el_str);
 
-  switch (el)
-  {
-    case MODE_EL1:
-    {
-      el_str = "MODE_EL1";
-      esr    = read_sysreg(esr_el1);
-      far    = read_sysreg(far_el1);
-      elr    = read_sysreg(elr_el1);
-      ret    = arm64_el1_exception_handler(esr, regs);
-      break;
-    }
-
-    case MODE_EL2:
+  if (el == MODE_EL1)
     {
-      el_str = "MODE_EL2";
-      esr    = read_sysreg(esr_el2);
-      far    = read_sysreg(far_el2);
-      elr    = read_sysreg(elr_el2);
-      break;
+      ret = arm64_el1_exception_handler(esr, regs);
     }
 
-#ifdef CONFIG_ARCH_HAVE_EL3
-    case MODE_EL3:
-    {
-      el_str = "MODE_EL3";
-      esr    = read_sysreg(esr_el3);
-      far    = read_sysreg(far_el3);
-      elr    = read_sysreg(elr_el3);
-      break;
-    }
-
-#endif
-    default:
-    {
-      el_str = "Unknown";
-
-      /* Just to keep the compiler happy */
-
-      esr = elr = far = 0;
-      break;
-    }
-  }
-
   if (ret != 0)
     {
       serr("CurrentEL: %s\n", el_str);
@@ -567,9 +636,47 @@ uint64_t *arm64_fatal_handler(uint64_t *regs)
 
   if (ret != 0)
     {
-      /* The fatal is not handled, print error and hung */
+      if (((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL) &&
+          ((tcb->flags & TCB_FLAG_SYSCALL) == 0) &&
+          ((regs[REG_SPSR] & SPSR_MODE_MASK) == SPSR_MODE_EL0T))
+        {
+          uint64_t esr;
+          const char *reason;
+          const char *desc;
+
+          arm64_get_exception_info(arm64_current_el(), &esr, NULL,
+                                   NULL, NULL);
+
+          reason = esr_get_class_string(esr);
+          if (reason == NULL)
+            {
+              reason = "Unknown/Uncategorized";
+            }
+
+          desc = esr_get_desc_string(esr);
+          if (desc == NULL)
+            {
+              desc = "";
+            }
+
+          _alert("PANIC: Unhandled user exception in PID %d: %s\n",
+                 tcb->pid, get_task_name(tcb));
+          _alert("Reason: %s - %s\n", reason, desc);
+          up_dump_register(regs);
+
+          tcb->flags |= TCB_FLAG_FORCED_CANCEL;
+
+          regs[REG_ELR] = (uint64_t) _exit;
+          regs[REG_X0] = SIGSEGV;
+          regs[REG_SPSR] &= ~SPSR_MODE_MASK;
+          regs[REG_SPSR] |= SPSR_MODE_EL1H;
+        }
+      else
+        {
+          /* The fatal is not handled, print error and hung */
 
-      PANIC_WITH_REGS("panic", regs);
+          PANIC_WITH_REGS("panic", regs);
+        }
     }
 
   /* Clear irq flag */

Reply via email to