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

xiaoxiang pushed a commit to branch releases/12.7
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 40d40015f4c1cbf8df28d2ba32c73cdb786abe7c
Author: qinwei1 <[email protected]>
AuthorDate: Mon Oct 30 22:58:48 2023 +0800

    arm64: refine the fatal handler
    
    Summary
      The original implement for exception handler is very simple and
    haven't framework for breakpoint/watchpoint routine or brk instruction.
      I refine the fatal handler and add framework for debug handler to
    register or unregister. this is a prepare for watchpoint/breakpoint
    implement
    
    Signed-off-by: qinwei1 <[email protected]>
---
 arch/arm64/src/common/arm64_fatal.c        | 682 +++++++++++++++++++----------
 arch/arm64/src/common/arm64_fatal.h        | 158 ++++++-
 arch/arm64/src/common/arm64_vector_table.S |   8 +-
 arch/arm64/src/common/arm64_vectors.S      |  40 +-
 4 files changed, 604 insertions(+), 284 deletions(-)

diff --git a/arch/arm64/src/common/arm64_fatal.c 
b/arch/arm64/src/common/arm64_fatal.c
index 3486fe1d5d..5c1b524190 100644
--- a/arch/arm64/src/common/arm64_fatal.c
+++ b/arch/arm64/src/common/arm64_fatal.c
@@ -39,6 +39,7 @@
 #include <nuttx/syslog/syslog.h>
 #include "sched/sched.h"
 #include "irq/irq.h"
+
 #include "arm64_arch.h"
 #include "arm64_internal.h"
 #include "arm64_fatal.h"
@@ -51,326 +52,527 @@
 #endif
 
 /****************************************************************************
- * Private Functions
+ * Private Type Declarations
  ****************************************************************************/
 
+struct fatal_handle_info
+{
+  fatal_handle_func_t handle_fn;
+  const char *name;
+};
+
 /****************************************************************************
- * Name: print_ec_cause
+ * Private Functions Declarations
  ****************************************************************************/
 
+/* Default callback handler for debug and fatal event
+ * Can be override by other handler
+ */
+
+static int default_debug_handler(struct regs_context *regs,
+                                 uint64_t far, uint64_t esr);
+static int default_fatal_handler(struct regs_context *regs,
+                                 uint64_t far, uint64_t esr);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const char *g_esr_class_str[] =
+{
+  [0 ... ESR_ELX_EC_MAX]   = "UNRECOGNIZED EC",
+  [ESR_ELX_EC_UNKNOWN]     = "Unknown/Uncategorized",
+  [ESR_ELX_EC_WFX]         = "WFI/WFE",
+  [ESR_ELX_EC_CP15_32]     = "CP15 MCR/MRC",
+  [ESR_ELX_EC_CP15_64]     = "CP15 MCRR/MRRC",
+  [ESR_ELX_EC_CP14_MR]     = "CP14 MCR/MRC",
+  [ESR_ELX_EC_CP14_LS]     = "CP14 LDC/STC",
+  [ESR_ELX_EC_FP_ASIMD]    = "ASIMD",
+  [ESR_ELX_EC_CP10_ID]     = "CP10 MRC/VMRS",
+  [ESR_ELX_EC_PAC]         = "PAC",
+  [ESR_ELX_EC_CP14_64]     = "CP14 MCRR/MRRC",
+  [ESR_ELX_EC_BTI]         = "BTI",
+  [ESR_ELX_EC_ILL]         = "PSTATE.IL",
+  [ESR_ELX_EC_SVC32]       = "SVC (AArch32)",
+  [ESR_ELX_EC_HVC32]       = "HVC (AArch32)",
+  [ESR_ELX_EC_SMC32]       = "SMC (AArch32)",
+  [ESR_ELX_EC_SVC64]       = "SVC (AArch64)",
+  [ESR_ELX_EC_HVC64]       = "HVC (AArch64)",
+  [ESR_ELX_EC_SMC64]       = "SMC (AArch64)",
+  [ESR_ELX_EC_SYS64]       = "MSR/MRS (AArch64)",
+  [ESR_ELX_EC_SVE]         = "SVE",
+  [ESR_ELX_EC_ERET]        = "ERET/ERETAA/ERETAB",
+  [ESR_ELX_EC_FPAC]        = "FPAC",
+  [ESR_ELX_EC_SME]         = "SME",
+  [ESR_ELX_EC_IMP_DEF]     = "EL3 IMP DEF",
+  [ESR_ELX_EC_IABT_LOW]    = "IABT (lower EL)",
+  [ESR_ELX_EC_IABT_CUR]    = "IABT (current EL)",
+  [ESR_ELX_EC_PC_ALIGN]    = "PC Alignment",
+  [ESR_ELX_EC_DABT_LOW]    = "DABT (lower EL)",
+  [ESR_ELX_EC_DABT_CUR]    = "DABT (current EL)",
+  [ESR_ELX_EC_SP_ALIGN]    = "SP Alignment",
+  [ESR_ELX_EC_MOPS]        = "MOPS",
+  [ESR_ELX_EC_FP_EXC32]    = "FP (AArch32)",
+  [ESR_ELX_EC_FP_EXC64]    = "FP (AArch64)",
+  [ESR_ELX_EC_SERROR]      = "SError",
+  [ESR_ELX_EC_BREAKPT_LOW] = "Breakpoint (lower EL)",
+  [ESR_ELX_EC_BREAKPT_CUR] = "Breakpoint (current EL)",
+  [ESR_ELX_EC_SOFTSTP_LOW] = "Software Step (lower EL)",
+  [ESR_ELX_EC_SOFTSTP_CUR] = "Software Step (current EL)",
+  [ESR_ELX_EC_WATCHPT_LOW] = "Watchpoint (lower EL)",
+  [ESR_ELX_EC_WATCHPT_CUR] = "Watchpoint (current EL)",
+  [ESR_ELX_EC_BKPT32]      = "BKPT (AArch32)",
+  [ESR_ELX_EC_VECTOR32]    = "Vector catch (AArch32)",
+  [ESR_ELX_EC_BRK64]       = "BRK (AArch64)",
+};
+
+static const char *g_esr_desc_str[] =
+{
+  [0 ... ESR_ELX_EC_MAX] = "UNRECOGNIZED EC",
+  [ESR_ELX_EC_UNKNOWN]   = "Unknown/Uncategorized",
+  [ESR_ELX_EC_WFX]       = "Trapped WFI or WFE instruction execution",
+  [ESR_ELX_EC_CP15_32]   = "Trapped MCR or MRC access with"
+                           "(coproc==0b1111) "
+                           "that is not reported using EC 0b000000",
+  [ESR_ELX_EC_CP15_64]   = "Trapped MCRR or MRRC access with"
+                           "(coproc==0b1111) "
+                           "that is not reported using EC 0b000000",
+  [ESR_ELX_EC_CP14_MR]  = "Trapped MCR or MRC access with (coproc==0b1110)",
+  [ESR_ELX_EC_CP14_LS]  = "Trapped LDC or STC access",
+  [ESR_ELX_EC_FP_ASIMD] = "Trapped access to SVE, Advanced SIMD, or "
+                          "floating-point functionality",
+  [ESR_ELX_EC_CP10_ID] = "CP10 MRC/VMRS",
+  [ESR_ELX_EC_PAC]     = "PAC",
+  [ESR_ELX_EC_CP14_64] = "Trapped MRRC access with (coproc==0b1110)",
+  [ESR_ELX_EC_BTI]     = "Branch Target Exception",
+  [ESR_ELX_EC_ILL]     = "Illegal Execution state",
+  [ESR_ELX_EC_SVC32]   = "SVC instruction execution in AArch32 state",
+  [ESR_ELX_EC_HVC32]   = "HVC (AArch32)",
+  [ESR_ELX_EC_SMC32]   = "SMC (AArch32)",
+  [ESR_ELX_EC_SVC64]   = "SVC (AArch64)",
+  [ESR_ELX_EC_HVC64]   = "HVC (AArch64)",
+  [ESR_ELX_EC_SMC64]   = "SMC (AArch64)",
+  [ESR_ELX_EC_SYS64]   = "Trapped MSR, MRS or System instruction "
+                         "execution in AArch64 state, that is not "
+                         "reported using EC 0b000000, 0b000001 or 0b000111",
+  [ESR_ELX_EC_SVE]  = "Trapped access to SVE functionality",
+  [ESR_ELX_EC_ERET] = "ERET/ERETAA/ERETAB",
+  [ESR_ELX_EC_FPAC] = "Exception from a Pointer Authentication "
+                      "instruction authentication failure",
+  [ESR_ELX_EC_SME] = "SME",
+  [ESR_ELX_EC_IMP_DEF]  = "EL3 IMP DEF",
+  [ESR_ELX_EC_IABT_LOW] = "Instruction Abort from a lower Exception level, "
+                          "that might be using AArch32 or AArch64",
+  [ESR_ELX_EC_IABT_CUR] = "Instruction Abort taken without a change "
+                          "in Exception level",
+  [ESR_ELX_EC_PC_ALIGN] = "PC alignment fault exception.",
+  [ESR_ELX_EC_DABT_LOW] = "Data Abort from a lower Exception level, "
+                          "that might be using AArch32 or AArch64",
+  [ESR_ELX_EC_DABT_CUR] = "Data Abort taken without a change in "
+                          "Exception level",
+  [ESR_ELX_EC_SP_ALIGN] = "SP alignment fault exception",
+  [ESR_ELX_EC_MOPS]     = "MOPS",
+  [ESR_ELX_EC_FP_EXC32] = "Trapped floating-point exception taken from "
+                          "AArch32 state",
+  [ESR_ELX_EC_FP_EXC64] = "Trapped floating-point exception taken from "
+                          "AArch64 state",
+  [ESR_ELX_EC_SERROR]   = "SError interrupt",
+  [ESR_ELX_EC_BREAKPT_LOW] = "Breakpoint exception from a lower "
+                             "Exception level, "
+                             "that might be using AArch32 or AArch64",
+  [ESR_ELX_EC_BREAKPT_CUR] = "Breakpoint exception taken without a change "
+                             "in Exception level",
+  [ESR_ELX_EC_SOFTSTP_LOW] = "Software Step exception from a lower "
+                             "Exception level,"
+                             "that might be using AArch32 or AArch64",
+  [ESR_ELX_EC_SOFTSTP_CUR] = "Software Step exception taken without a "
+                             "change in Exception level",
+  [ESR_ELX_EC_WATCHPT_LOW] = "Watchpoint exception from a lower "
+                             "Exception level, "
+                             "that might be using AArch32 or AArch64",
+  [ESR_ELX_EC_WATCHPT_CUR] = "Watchpoint exception taken without "
+                             "a change in Exception level.",
+  [ESR_ELX_EC_BKPT32]   = "BKPT instruction execution in AArch32 state",
+  [ESR_ELX_EC_VECTOR32] = "Vector catch (AArch32)",
+  [ESR_ELX_EC_BRK64]    = "BRK instruction execution in AArch64 state.",
+};
+
+static struct fatal_handle_info g_fatal_handler[] =
+{
+  { default_fatal_handler, "ttbr address size fault" },
+  { default_fatal_handler, "level 1 address size fault" },
+  { default_fatal_handler, "level 2 address size fault" },
+  { default_fatal_handler, "level 3 address size fault" },
+  { default_fatal_handler, "level 0 translation fault" },
+  { default_fatal_handler, "level 1 translation fault" },
+  { default_fatal_handler, "level 2 translation fault" },
+  { default_fatal_handler, "level 3 translation fault" },
+  { default_fatal_handler, "unknown 8"                 },
+  { default_fatal_handler, "level 1 access flag fault" },
+  { default_fatal_handler, "level 2 access flag fault" },
+  { default_fatal_handler, "level 3 access flag fault" },
+  { default_fatal_handler, "unknown 12"                },
+  { default_fatal_handler, "level 1 permission fault"  },
+  { default_fatal_handler, "level 2 permission fault"  },
+  { default_fatal_handler, "level 3 permission fault"  },
+  { default_fatal_handler, "synchronous external abort" },
+  { default_fatal_handler, "synchronous tag check fault" },
+  { default_fatal_handler, "unknown 18" },
+  { default_fatal_handler, "unknown 19" },
+  { default_fatal_handler, "level 0 (translation table walk)" },
+  { default_fatal_handler, "level 1 (translation table walk)" },
+  { default_fatal_handler, "level 2 (translation table walk)" },
+  { default_fatal_handler, "level 3 (translation table walk)" },
+  { default_fatal_handler, "synchronous parity or ECC error" },
+  { default_fatal_handler, "unknown 25" },
+  { default_fatal_handler, "unknown 26" },
+  { default_fatal_handler, "unknown 27" },
+  { default_fatal_handler, "level 0 synchronous parity "
+                      "error (translation table walk)" },
+  { default_fatal_handler, "level 1 synchronous parity "
+                      "error (translation table walk)" },
+  { default_fatal_handler, "level 2 synchronous parity "
+                      "error (translation table walk)" },
+  { default_fatal_handler, "level 3 synchronous parity "
+                      "error (translation table walk)" },
+  { default_fatal_handler, "unknown 32"   },
+  { default_fatal_handler, "alignment fault" },
+  { default_fatal_handler, "unknown 34" },
+  { default_fatal_handler, "unknown 35" },
+  { default_fatal_handler, "unknown 36" },
+  { default_fatal_handler, "unknown 37" },
+  { default_fatal_handler, "unknown 38" },
+  { default_fatal_handler, "unknown 39" },
+  { default_fatal_handler, "unknown 40" },
+  { default_fatal_handler, "unknown 41" },
+  { default_fatal_handler, "unknown 42" },
+  { default_fatal_handler, "unknown 43" },
+  { default_fatal_handler, "unknown 44" },
+  { default_fatal_handler, "unknown 45" },
+  { default_fatal_handler, "unknown 46" },
+  { default_fatal_handler, "unknown 47" },
+  { default_fatal_handler, "TLB conflict abort" },
+  { default_fatal_handler, "Unsupported atomic hardware update fault" },
+  { default_fatal_handler, "unknown 50" },
+  { default_fatal_handler, "unknown 51" },
+  { default_fatal_handler, "implementation fault (lockdown abort)" },
+  { default_fatal_handler, "implementation fault (unsupported exclusive)" },
+  { default_fatal_handler, "unknown 54" },
+  { default_fatal_handler, "unknown 55" },
+  { default_fatal_handler, "unknown 56" },
+  { default_fatal_handler, "unknown 57" },
+  { default_fatal_handler, "unknown 58" },
+  { default_fatal_handler, "unknown 59" },
+  { default_fatal_handler, "unknown 60" },
+  { default_fatal_handler, "section domain fault" },
+  { default_fatal_handler, "page domain fault" },
+  { default_fatal_handler, "unknown 63" },
+};
+
+static struct fatal_handle_info g_debug_handler[] =
+{
+  { default_debug_handler, "hardware breakpoint"  },
+  { default_debug_handler, "hardware single-step" },
+  { default_debug_handler, "hardware watchpoint"  },
+  { default_debug_handler, "unknown 3"            },
+  { default_debug_handler, "aarch32 BKPT"         },
+  { default_debug_handler, "aarch32 vector catch" },
+  { default_debug_handler, "aarch64 BRK"          },
+  { default_debug_handler, "unknown 7"            },
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static const char *esr_get_class_string(uint64_t esr)
+{
+  uint32_t ec = ESR_ELX_EC(esr);
+
+  return g_esr_class_str[ec];
+}
+
+static const char *esr_get_desc_string(uint64_t esr)
+{
+  uint32_t ec = ESR_ELX_EC(esr);
+
+  return g_esr_desc_str[ec];
+}
+
 static void print_ec_cause(uint64_t esr)
 {
-  uint32_t ec = (uint32_t)esr >> 26;
+  sinfo("%s\n", esr_get_class_string(esr));
+  sinfo("%s\n", esr_get_desc_string(esr));
+}
 
-  switch (ec)
-    {
-      case 0b000000:
-        {
-          sinfo("Unknown reason\n");
-          break;
-        }
+static int default_fatal_handler(struct regs_context *regs,
+                                 uint64_t far, uint64_t esr)
+{
+  struct fatal_handle_info *inf = g_fatal_handler + (esr & ESR_ELX_FSC);
 
-      case 0b000001:
-        {
-          sinfo("Trapped WFI or WFE instruction execution\n");
-          break;
-        }
+  /* Data Fault Status Code. */
 
-      case 0b000011:
-        {
-          sinfo(
-             "Trapped MCR or MRC access with (coproc==0b1111) that "
-             "is not reported using EC 0b000000\n");
-          break;
-        }
+  sinfo("(IFSC/DFSC) for Data/Instruction aborts: %s\n", inf->name);
 
-      case 0b000100:
-        {
-          sinfo(
-             "Trapped MCRR or MRRC access with (coproc==0b1111) "
-             "that is not reported using EC 0b000000\n");
-          break;
-        }
+  return -EINVAL; /* "fault" */
+}
 
-      case 0b000101:
-        {
-          sinfo("Trapped MCR or MRC access with (coproc==0b1110)\n");
-          break;
-        }
+static int default_debug_handler(struct regs_context *regs,
+                                 uint64_t far, uint64_t esr)
+{
+  struct fatal_handle_info *inf = g_debug_handler + DBG_ESR_EVT(esr);
 
-      case 0b000110:
-        {
-          sinfo("Trapped LDC or STC access\n");
-          break;
-        }
+  sinfo("Default Debug Handler: %s\n", inf->name);
+  return -1; /* "fault" */
+}
 
-      case 0b000111:
-        {
-          sinfo(
-             "Trapped access to SVE, Advanced SIMD, or "
-             "floating-point functionality\n");
-          break;
-        }
+static int arm64_el1_abort(struct regs_context *regs, uint64_t esr)
+{
+  uint64_t                  far = read_sysreg(far_el1);
+  struct fatal_handle_info *inf = g_fatal_handler + (esr & ESR_ELX_FSC);
 
-      case 0b001100:
-        {
-          sinfo("Trapped MRRC access with (coproc==0b1110)\n");
-          break;
-        }
+  return inf->handle_fn(regs, far, esr);
+}
 
-      case 0b001101:
-        {
-          sinfo("Branch Target Exception\n");
-          break;
-        }
+static int arm64_el1_pc(struct regs_context *regs, uint64_t esr)
+{
+  uint64_t far = read_sysreg(far_el1);
 
-      case 0b001110:
-        {
-          sinfo("Illegal Execution state\n");
-          break;
-        }
+  sinfo("SP/PC alignment exception at 0x%" PRIx64 "\n", far);
+  return -EINVAL; /* "fault" */
+}
 
-      case 0b010001:
-        {
-          sinfo("SVC instruction execution in AArch32 state\n");
-          break;
-        }
+static int arm64_el1_bti(struct regs_context *regs, uint64_t esr)
+{
+  uint64_t far = read_sysreg(far_el1);
 
-      case 0b011000:
-        {
-          sinfo(
-             "Trapped MSR, MRS or System instruction execution in "
-             "AArch64 state, that is not reported using EC "
-             "0b000000, 0b000001 or 0b000111\n");
-          break;
-        }
+  sinfo("BTI exception at 0x%" PRIx64 "\n", far);
+  return -EINVAL; /* "fault" */
+}
 
-      case 0b011001:
-        {
-          sinfo("Trapped access to SVE functionality\n");
-          break;
-        }
+static int arm64_el1_undef(struct regs_context *regs, uint64_t esr)
+{
+  uint32_t insn;
+
+  sinfo("Undefined instruction at 0x%" PRIx64 ", dump:\n", regs->elr);
+  memcpy(&insn, (void *)(regs->elr - 8), 4);
+  sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr - 8, insn);
+  memcpy(&insn, (void *)(regs->elr - 4), 4);
+  sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr - 4, insn);
+  memcpy(&insn, (void *)(regs->elr), 4);
+  sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr, insn);
+  memcpy(&insn, (void *)(regs->elr + 4), 4);
+  sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr + 4, insn);
+  memcpy(&insn, (void *)(regs->elr + 8), 4);
+  sinfo("0x%" PRIx64 " : 0x%" PRIx32 "\n", regs->elr + 8, insn);
+
+  return -1;
+}
 
-      case 0b100000:
-        {
-          sinfo(
-             "Instruction Abort from a lower Exception level, that "
-             "might be using AArch32 or AArch64\n");
-          break;
-        }
+static int arm64_el1_fpac(struct regs_context *regs, uint64_t esr)
+{
+  uint64_t far = read_sysreg(far_el1);
 
-      case 0b100001:
-        {
-          sinfo(
-             "Instruction Abort taken without a change "
-             "in Exception level.\n");
-          break;
-        }
+  /* Unexpected FPAC exception in the kernel. */
 
-      case 0b100010:
-        {
-          sinfo("PC alignment fault exception.\n");
-          break;
-        }
+  sinfo("Unexpected FPAC exception at 0x%" PRIx64 "\n", far);
+  return -EINVAL;
+}
 
-      case 0b100100:
-        {
-          sinfo(
-             "Data Abort from a lower Exception level, that might "
-             "be using AArch32 or AArch64\n");
-          break;
-        }
+static int arm64_el1_dbg(struct regs_context *regs, uint64_t esr)
+{
+  uint64_t                  far = read_sysreg(far_el1);
+  struct fatal_handle_info *inf = g_debug_handler + DBG_ESR_EVT(esr);
 
-      case 0b100101:
-        {
-          sinfo("Data Abort taken without a change in Exception level\n");
-          break;
-        }
+  return inf->handle_fn(regs, far, esr);
+}
 
-      case 0b100110:
-        {
-          sinfo("SP alignment fault exception\n");
-          break;
-        }
+static int arm64_el1_exception_handler(uint64_t esr,
+                                       struct regs_context *regs)
+{
+  uint32_t  ec = ESR_ELX_EC(esr);
+  int       ret;
 
-      case 0b101000:
-        {
-          sinfo(
-             "Trapped floating-point exception "
-             "taken from AArch32 state\n");
-          break;
-        }
+  switch (ec)
+    {
+      /* Data/Instruction Abort at EL1 */
 
-      case 0b101100:
+      case ESR_ELX_EC_DABT_CUR:
+      case ESR_ELX_EC_IABT_CUR:
         {
-          sinfo(
-             "Trapped floating-point exception "
-             "taken from AArch64 state.\n");
+          ret = arm64_el1_abort(regs, esr);
           break;
         }
 
-      case 0b101111:
-        {
-          sinfo("SError interrupt\n");
-          break;
-        }
+      /* PC alignment fault exception. */
 
-      case 0b110000:
+      case ESR_ELX_EC_PC_ALIGN:
         {
-          sinfo(
-             "Breakpoint exception from a lower Exception level, "
-             "that might be using AArch32 or AArch64\n");
+          ret = arm64_el1_pc(regs, esr);
           break;
         }
 
-      case 0b110001:
-        {
-          sinfo(
-             "Breakpoint exception taken without a change in "
-             "Exception level\n");
-          break;
-        }
+      /* Trapped MSR, MRS or System instruction execution
+       * in AArch64 state
+       */
 
-      case 0b110010:
+      case ESR_ELX_EC_SYS64:
+      case ESR_ELX_EC_UNKNOWN:
         {
-          sinfo(
-             "Software Step exception from a lower Exception level, "
-             "that might be using AArch32 or AArch64\n");
+          ret = arm64_el1_undef(regs, esr);
           break;
         }
 
-      case 0b110011:
-        {
-          sinfo(
-             "Software Step exception taken without a change in "
-             "Exception level\n");
-          break;
-        }
+      /* Branch Target Exception */
 
-      case 0b110100:
+      case ESR_ELX_EC_BTI:
         {
-          sinfo(
-             "Watchpoint exception from a lower Exception level, "
-             "that might be using AArch32 or AArch64\n");
+          ret = arm64_el1_bti(regs, esr);
           break;
         }
 
-      case 0b110101:
+      case ESR_ELX_EC_BREAKPT_CUR:
+
+      /* Breakpoint exception taken in current Exception level */
+
+      case ESR_ELX_EC_SOFTSTP_CUR:
+
+      /* Software Step exception taken in current Exception level */
+
+      case ESR_ELX_EC_WATCHPT_CUR:
+
+      /* Watchpoint exception taken in current Exception level */
+
+      case ESR_ELX_EC_BRK64:
         {
-          sinfo(
-             "Watchpoint exception taken without a change in "
-             "Exception level.\n");
+          /* BRK instruction execution in AArch64 state */
+
+          ret = arm64_el1_dbg(regs, esr);
           break;
         }
 
-      case 0b111000:
+      case ESR_ELX_EC_FPAC:
         {
-          sinfo("BKPT instruction execution in AArch32 state\n");
+          /* Exception from a Pointer Authentication
+           * instruction authentication failure
+           */
+
+          ret = arm64_el1_fpac(regs, esr);
           break;
         }
 
-      case 0b111100:
+      default:
         {
-          sinfo("BRK instruction execution in AArch64 state.\n");
-          break;
+          sinfo("64-bit el1h sync, esr = 0x%x", ec);
+          ret = -EINVAL;
         }
+  }
 
-      default:
-        break;
-    }
+  return ret;
 }
 
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
+static int arm64_exception_handler(struct regs_context *regs)
+{
+  uint64_t    el;
+  uint64_t    esr;
+  uint64_t    elr;
+  uint64_t    far;
+  const char *el_str;
+  int         ret = -EINVAL;
+
+  el = arm64_current_el();
+
+  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;
+    }
 
-/****************************************************************************
- * Name: up_mdelay
- ****************************************************************************/
+    case MODE_EL2:
+    {
+      el_str = "MODE_EL2";
+      esr    = read_sysreg(esr_el2);
+      far    = read_sysreg(far_el2);
+      elr    = read_sysreg(elr_el2);
+      break;
+    }
 
-void up_mdelay(unsigned int milliseconds)
-{
-  volatile unsigned int i;
-  volatile unsigned int j;
+#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;
+    }
 
-  for (i = 0; i < milliseconds; i++)
+#endif
+    default:
     {
-      for (j = 0; j < CONFIG_BOARD_LOOPSPERMSEC; j++)
-        {
-        }
+      el_str = "Unknown";
+
+      /* Just to keep the compiler happy */
+
+      esr = elr = far = 0;
+      break;
+    }
+  }
+
+  if (ret != 0)
+    {
+      sinfo("CurrentEL: %s\n", el_str);
+      sinfo("ESR_ELn: 0x%" PRIx64 "\n", esr);
+      sinfo("FAR_ELn: 0x%" PRIx64 "\n", far);
+      sinfo("ELR_ELn: 0x%" PRIx64 "\n", elr);
+
+      print_ec_cause(esr);
     }
+
+  return ret;
 }
 
 /****************************************************************************
- * Name: arm64_fatal_error
- *
- * Description:
- *
+ * Public Functions
  ****************************************************************************/
 
-void arm64_fatal_error(unsigned int reason, struct regs_context * reg)
+void arm64_fatal_handler(struct regs_context *regs)
 {
-  uint64_t el, esr, elr, far;
+  int ret;
 
-  sinfo("reason = %d\n", reason);
+  /* Nested exception are not supported */
 
-  up_set_current_regs((uint64_t *)reg);
+  DEBUGASSERT(up_current_regs() == NULL);
 
-  if (reason != K_ERR_SPURIOUS_IRQ)
-    {
-      __asm__ volatile ("mrs %0, CurrentEL" : "=r" (el));
+  up_set_current_regs((uint64_t *)regs);
 
-      switch (GET_EL(el))
-        {
-          case MODE_EL1:
-            {
-              sinfo("CurrentEL: MODE_EL1\n");
-              __asm__ volatile ("mrs %0, esr_el1" : "=r" (esr));
-              __asm__ volatile ("mrs %0, far_el1" : "=r" (far));
-              __asm__ volatile ("mrs %0, elr_el1" : "=r" (elr));
-              break;
-            }
-
-          case MODE_EL2:
-            {
-              sinfo("CurrentEL: MODE_EL2\n");
-              __asm__ volatile ("mrs %0, esr_el2" : "=r" (esr));
-              __asm__ volatile ("mrs %0, far_el2" : "=r" (far));
-              __asm__ volatile ("mrs %0, elr_el2" : "=r" (elr));
-              break;
-            }
+  ret = arm64_exception_handler(regs);
 
-#ifdef CONFIG_ARCH_HAVE_EL3
-          case MODE_EL3:
-            {
-              sinfo("CurrentEL: MODE_EL3\n");
-              __asm__ volatile ("mrs %0, esr_el3" : "=r" (esr));
-              __asm__ volatile ("mrs %0, far_el3" : "=r" (far));
-              __asm__ volatile ("mrs %0, elr_el3" : "=r" (elr));
-              break;
-            }
-#endif
+  if (ret != 0)
+    {
+      /* The fatal is not handled, print error and hung */
 
-          default:
-            {
-              sinfo("CurrentEL: unknown\n");
+      PANIC_WITH_REGS("panic", regs);
+    }
 
-              /* Just to keep the compiler happy */
+  /* Set CURRENT_REGS to NULL to indicate that we are no longer in an
+   * Exception handler.
+   */
 
-              esr = elr = far = 0;
-              break;
-            }
-        }
+  up_set_current_regs(NULL);
+}
 
-      if (GET_EL(el) != MODE_EL0)
-        {
-          sinfo("ESR_ELn: 0x%"PRIx64"\n", esr);
-          sinfo("FAR_ELn: 0x%"PRIx64"\n", far);
-          sinfo("ELR_ELn: 0x%"PRIx64"\n", elr);
+void arm64_register_debug_hook(int nr, fatal_handle_func_t fn)
+{
+  DEBUGVERIFY(nr > 0 && nr <= nitems(g_debug_handler));
 
-          print_ec_cause(esr);
-        }
-    }
+  /* Override the default handler */
 
-  PANIC_WITH_REGS("panic", reg);
+  g_debug_handler[nr].handle_fn = fn;
 }
diff --git a/arch/arm64/src/common/arm64_fatal.h 
b/arch/arm64/src/common/arm64_fatal.h
index 360a28e8fa..301e158f00 100644
--- a/arch/arm64/src/common/arm64_fatal.h
+++ b/arch/arm64/src/common/arm64_fatal.h
@@ -21,12 +21,6 @@
 #ifndef __ARCH_ARM64_SRC_COMMON_ARM64_FATAL_H
 #define __ARCH_ARM64_SRC_COMMON_ARM64_FATAL_H
 
-/* Fatal error APIs */
-
-#define K_ERR_CPU_EXCEPTION     (0)
-#define K_ERR_CPU_MODE32        (1)
-#define K_ERR_SPURIOUS_IRQ      (2)
-
 #ifndef __ASSEMBLY__
 
 /****************************************************************************
@@ -43,6 +37,123 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+#define ESR_ELX_EC_UNKNOWN      (0x00)
+#define ESR_ELX_EC_WFX          (0x01)
+
+/* Unallocated EC: 0x02 */
+
+#define ESR_ELX_EC_CP15_32      (0x03)
+#define ESR_ELX_EC_CP15_64      (0x04)
+#define ESR_ELX_EC_CP14_MR      (0x05)
+#define ESR_ELX_EC_CP14_LS      (0x06)
+#define ESR_ELX_EC_FP_ASIMD     (0x07)
+#define ESR_ELX_EC_CP10_ID      (0x08)  /* EL2 only */
+#define ESR_ELX_EC_PAC          (0x09)  /* EL2 and above */
+
+/* Unallocated EC: 0x0A - 0x0B */
+
+#define ESR_ELX_EC_CP14_64      (0x0C)
+#define ESR_ELX_EC_BTI          (0x0D)
+#define ESR_ELX_EC_ILL          (0x0E)
+
+/* Unallocated EC: 0x0F - 0x10 */
+
+#define ESR_ELX_EC_SVC32        (0x11)
+#define ESR_ELX_EC_HVC32        (0x12)  /* EL2 only */
+#define ESR_ELX_EC_SMC32        (0x13)  /* EL2 and above */
+
+/* Unallocated EC: 0x14 */
+
+#define ESR_ELX_EC_SVC64        (0x15)
+#define ESR_ELX_EC_HVC64        (0x16)  /* EL2 and above */
+#define ESR_ELX_EC_SMC64        (0x17)  /* EL2 and above */
+#define ESR_ELX_EC_SYS64        (0x18)
+#define ESR_ELX_EC_SVE          (0x19)
+#define ESR_ELX_EC_ERET         (0x1a)  /* EL2 only */
+
+/* Unallocated EC: 0x1B */
+
+#define ESR_ELX_EC_FPAC         (0x1C)  /* EL1 and above */
+#define ESR_ELX_EC_SME          (0x1D)
+
+/* Unallocated EC: 0x1D - 0x1E */
+
+#define ESR_ELX_EC_IMP_DEF      (0x1f)  /* EL3 only */
+#define ESR_ELX_EC_IABT_LOW     (0x20)
+#define ESR_ELX_EC_IABT_CUR     (0x21)
+#define ESR_ELX_EC_PC_ALIGN     (0x22)
+
+/* Unallocated EC: 0x23 */
+
+#define ESR_ELX_EC_DABT_LOW     (0x24)
+#define ESR_ELX_EC_DABT_CUR     (0x25)
+#define ESR_ELX_EC_SP_ALIGN     (0x26)
+#define ESR_ELX_EC_MOPS         (0x27)
+#define ESR_ELX_EC_FP_EXC32     (0x28)
+
+/* Unallocated EC: 0x29 - 0x2B */
+
+#define ESR_ELX_EC_FP_EXC64     (0x2C)
+
+/* Unallocated EC: 0x2D - 0x2E */
+
+#define ESR_ELX_EC_SERROR       (0x2F)
+#define ESR_ELX_EC_BREAKPT_LOW  (0x30)
+#define ESR_ELX_EC_BREAKPT_CUR  (0x31)
+#define ESR_ELX_EC_SOFTSTP_LOW  (0x32)
+#define ESR_ELX_EC_SOFTSTP_CUR  (0x33)
+#define ESR_ELX_EC_WATCHPT_LOW  (0x34)
+#define ESR_ELX_EC_WATCHPT_CUR  (0x35)
+
+/* Unallocated EC: 0x36 - 0x37 */
+
+#define ESR_ELX_EC_BKPT32       (0x38)
+
+/* Unallocated EC: 0x39 */
+
+#define ESR_ELX_EC_VECTOR32     (0x3A) /* EL2 only */
+
+/* Unallocated EC: 0x3B */
+
+#define ESR_ELX_EC_BRK64        (0x3C)
+
+/* Unallocated EC: 0x3D - 0x3F */
+
+#define ESR_ELX_EC_MAX          (0x3F)
+
+#define ESR_ELX_EC_SHIFT        (26)
+#define ESR_ELX_EC_WIDTH        (6)
+#define ESR_ELX_EC_MASK         (0x3F << ESR_ELX_EC_SHIFT)
+#define ESR_ELX_EC(esr)         (((esr) & ESR_ELX_EC_MASK) \
+                                >> ESR_ELX_EC_SHIFT)
+
+/* Shared ISS fault status code(IFSC/DFSC) for Data/Instruction aborts */
+
+#define ESR_ELX_FSC             (0x3F)
+#define ESR_ELX_FSC_TYPE        (0x3C)
+#define ESR_ELX_FSC_LEVEL       (0x03)
+#define ESR_ELX_FSC_EXTABT      (0x10)
+#define ESR_ELX_FSC_MTE         (0x11)
+#define ESR_ELX_FSC_SERROR      (0x11)
+#define ESR_ELX_FSC_ACCESS      (0x08)
+#define ESR_ELX_FSC_FAULT       (0x04)
+#define ESR_ELX_FSC_PERM        (0x0C)
+#define ESR_ELX_FSC_SEA_TTW0    (0x14)
+#define ESR_ELX_FSC_SEA_TTW1    (0x15)
+#define ESR_ELX_FSC_SEA_TTW2    (0x16)
+#define ESR_ELX_FSC_SEA_TTW3    (0x17)
+#define ESR_ELX_FSC_SECC        (0x18)
+#define ESR_ELX_FSC_SECC_TTW0   (0x1c)
+#define ESR_ELX_FSC_SECC_TTW1   (0x1d)
+#define ESR_ELX_FSC_SECC_TTW2   (0x1e)
+#define ESR_ELX_FSC_SECC_TTW3   (0x1f)
+
+#define DBG_ESR_EVT(x)          (((x) >> 27) & 0x7)
+#define DBG_ESR_EVT_HWBP        (0x0)
+#define DBG_ESR_EVT_HWSS        (0x1)
+#define DBG_ESR_EVT_HWWP        (0x2)
+#define DBG_ESR_EVT_BRK         (0x6)
+
 #define __builtin_unreachable()    \
   do                               \
     {                              \
@@ -51,28 +162,49 @@
     } while (true)
 
 /****************************************************************************
- * Public Data
+ * Public Type Declarations
  ****************************************************************************/
 
+typedef int (*fatal_handle_func_t)(struct regs_context *regs,
+                                   uint64_t far, uint64_t esr);
+
 /****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
 
 /****************************************************************************
- * Name: arm64_fatal_error
+ * Name: arm64_fatal_handler
  *
  * Description:
- *       fatal error handle for arm64
+ *   Fatal handle for arm64
  * Input Parameters:
- *   reason: error reason
  *   reg:    exception stack reg context
  *
- * Returned Value:
+ * Returned Value: None
+ *   If the function return, the exception has been handled
+ *
+ ****************************************************************************/
+
+void arm64_fatal_handler(struct regs_context *reg);
+
+/****************************************************************************
+ * Name: arm64_register_debug_hook
+ *
+ * Description:
+ *   Register a hook function for DEBUG event
+ * Input Parameters:
+ *   nr:   DEBUG event
+ *           DBG_ESR_EVT_HWBP : Hardware BreakPoint
+ *           DBG_ESR_EVT_HWSS : Hardware SingleStep
+ *           DBG_ESR_EVT_HWWP : Hardware WatchPoint
+ *           DBG_ESR_EVT_BRK  : Brk instruction trigger
+ *   fn:   hook function
+ *
+ * Returned Value: none
  *
  ****************************************************************************/
 
-void arm64_fatal_error(unsigned int reason, struct regs_context * reg);
-void arm64_dump_fatal(struct regs_context * reg);
+void arm64_register_debug_hook(int nr, fatal_handle_func_t fn);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/arch/arm64/src/common/arm64_vector_table.S 
b/arch/arm64/src/common/arm64_vector_table.S
index fa81c4e888..1c05814c87 100644
--- a/arch/arm64/src/common/arm64_vector_table.S
+++ b/arch/arm64/src/common/arm64_vector_table.S
@@ -216,25 +216,25 @@ 
SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)
 
     .align 7
     arm64_enter_exception x0, x1
-    b    arm64_mode32_error
+    b    arm64_mode32_handler
 
     /* Lower EL using AArch32 / IRQ */
 
     .align 7
     arm64_enter_exception x0, x1
-    b    arm64_mode32_error
+    b    arm64_mode32_handler
 
     /* Lower EL using AArch32 / FIQ */
 
     .align 7
     arm64_enter_exception x0, x1
-    b    arm64_mode32_error
+    b    arm64_mode32_handler
 
     /* Lower EL using AArch32 / SError */
 
     .align 7
     arm64_enter_exception x0, x1
-    b    arm64_mode32_error
+    b    arm64_mode32_handler
 
 /* Restore Corruptible Registers and exception context
  * from the task stack.
diff --git a/arch/arm64/src/common/arm64_vectors.S 
b/arch/arm64/src/common/arm64_vectors.S
index d2d1e5c95a..2a04bdcd33 100644
--- a/arch/arm64/src/common/arm64_vectors.S
+++ b/arch/arm64/src/common/arm64_vectors.S
@@ -355,16 +355,13 @@ save_context:
     b    arm64_exit_exception
 
 exc_handle:
-    arm64_exception_context_save x0 x1 sp
-    mov    x0, #K_ERR_CPU_EXCEPTION
-    mov    x1, sp
+    mov    x0, sp
 
-    /* void arm64_fatal_error(unsigned int reason, const uint64_t *regs)
-     * x0 = reason
-     * x1 = Exception stack frame
+    /* void arm64_fatal_handler(struct regs_context * reg);
+     * x0 = Exception stack frame
      */
 
-    bl    arm64_fatal_error
+    bl    arm64_fatal_handler
 
     /* Return here only in case of recoverable error */
 
@@ -445,28 +442,20 @@ irq_context_switch:
 irq_exit:
     b     arm64_exit_exception
 
-/* TODO: if the arm64_fatal_error return success, maybe need context switch */
+/* TODO: if the arm64_fatal_handler return success, maybe need context switch 
*/
 
 GTEXT(arm64_serror_handler)
 SECTION_FUNC(text, arm64_serror_handler)
-    arm64_exception_context_save x0 x1 sp
-
-    mov    x0, #K_ERR_CPU_EXCEPTION
-    mov    x1, sp
-
-    bl    arm64_fatal_error
+    mov   x0, sp
+    bl    arm64_fatal_handler
     /* Return here only in case of recoverable error */
 
     b    arm64_exit_exception
 
-GTEXT(arm64_mode32_error)
-SECTION_FUNC(text, arm64_mode32_error)
-    arm64_exception_context_save x0 x1 sp
-
-    mov    x1, sp
-    mov    x0, #K_ERR_CPU_MODE32
-
-    bl    arm64_fatal_error
+GTEXT(arm64_mode32_handler)
+SECTION_FUNC(text, arm64_mode32_handler)
+    mov   x0, sp
+    bl    arm64_fatal_handler
     /* Return here only in case of recoverable error */
 
     b    arm64_exit_exception
@@ -474,12 +463,9 @@ SECTION_FUNC(text, arm64_mode32_error)
 GTEXT(arm64_fiq_handler)
 SECTION_FUNC(text, arm64_fiq_handler)
 #ifndef CONFIG_ARM64_DECODEFIQ
-    arm64_exception_context_save x0 x1 sp
-
-    mov    x1, sp
-    mov    x0, #K_ERR_SPURIOUS_IRQ /* K_ERR_SPURIOUS_IRQ */
 
-    bl    arm64_fatal_error
+    mov   x0, sp
+    bl    arm64_fatal_handler
 
     /* Return here only in case of recoverable error */
 


Reply via email to