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 #include "sched/sched.h" #include "irq/irq.h" + #include "arm64_arch.h" #include "arm64_internal.h" #include "arm64_fatal.h" @@ -50,327 +51,528 @@ #include "arm64_fpu.h" #endif +/**************************************************************************** + * Private Type Declarations + ****************************************************************************/ + +struct fatal_handle_info +{ + fatal_handle_func_t handle_fn; + const char *name; +}; + +/**************************************************************************** + * 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 ****************************************************************************/ -/**************************************************************************** - * Name: print_ec_cause - ****************************************************************************/ +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)); +} + +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); + + /* Data Fault Status Code. */ + + sinfo("(IFSC/DFSC) for Data/Instruction aborts: %s\n", inf->name); + + return -EINVAL; /* "fault" */ +} + +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); + + sinfo("Default Debug Handler: %s\n", inf->name); + return -1; /* "fault" */ +} + +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); + + return inf->handle_fn(regs, far, esr); +} + +static int arm64_el1_pc(struct regs_context *regs, uint64_t esr) +{ + uint64_t far = read_sysreg(far_el1); + + sinfo("SP/PC alignment exception at 0x%" PRIx64 "\n", far); + return -EINVAL; /* "fault" */ +} + +static int arm64_el1_bti(struct regs_context *regs, uint64_t esr) +{ + uint64_t far = read_sysreg(far_el1); + + sinfo("BTI exception at 0x%" PRIx64 "\n", far); + return -EINVAL; /* "fault" */ +} + +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; +} + +static int arm64_el1_fpac(struct regs_context *regs, uint64_t esr) +{ + uint64_t far = read_sysreg(far_el1); + + /* Unexpected FPAC exception in the kernel. */ + + sinfo("Unexpected FPAC exception at 0x%" PRIx64 "\n", far); + return -EINVAL; +} + +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); + + return inf->handle_fn(regs, far, esr); +} + +static int arm64_el1_exception_handler(uint64_t esr, + struct regs_context *regs) +{ + uint32_t ec = ESR_ELX_EC(esr); + int ret; switch (ec) { - case 0b000000: + /* Data/Instruction Abort at EL1 */ + + case ESR_ELX_EC_DABT_CUR: + case ESR_ELX_EC_IABT_CUR: { - sinfo("Unknown reason\n"); + ret = arm64_el1_abort(regs, esr); break; } - case 0b000001: + /* PC alignment fault exception. */ + + case ESR_ELX_EC_PC_ALIGN: { - sinfo("Trapped WFI or WFE instruction execution\n"); + ret = arm64_el1_pc(regs, esr); break; } - case 0b000011: + /* Trapped MSR, MRS or System instruction execution + * in AArch64 state + */ + + case ESR_ELX_EC_SYS64: + case ESR_ELX_EC_UNKNOWN: { - sinfo( - "Trapped MCR or MRC access with (coproc==0b1111) that " - "is not reported using EC 0b000000\n"); + ret = arm64_el1_undef(regs, esr); break; } - case 0b000100: + /* Branch Target Exception */ + + case ESR_ELX_EC_BTI: { - sinfo( - "Trapped MCRR or MRRC access with (coproc==0b1111) " - "that is not reported using EC 0b000000\n"); + ret = arm64_el1_bti(regs, esr); break; } - case 0b000101: + 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("Trapped MCR or MRC access with (coproc==0b1110)\n"); + /* BRK instruction execution in AArch64 state */ + + ret = arm64_el1_dbg(regs, esr); break; } - case 0b000110: + case ESR_ELX_EC_FPAC: { - sinfo("Trapped LDC or STC access\n"); - break; - } + /* Exception from a Pointer Authentication + * instruction authentication failure + */ - case 0b000111: - { - sinfo( - "Trapped access to SVE, Advanced SIMD, or " - "floating-point functionality\n"); - break; - } - - case 0b001100: - { - sinfo("Trapped MRRC access with (coproc==0b1110)\n"); - break; - } - - case 0b001101: - { - sinfo("Branch Target Exception\n"); - break; - } - - case 0b001110: - { - sinfo("Illegal Execution state\n"); - break; - } - - case 0b010001: - { - sinfo("SVC instruction execution in AArch32 state\n"); - break; - } - - 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; - } - - case 0b011001: - { - sinfo("Trapped access to SVE functionality\n"); - break; - } - - case 0b100000: - { - sinfo( - "Instruction Abort from a lower Exception level, that " - "might be using AArch32 or AArch64\n"); - break; - } - - case 0b100001: - { - sinfo( - "Instruction Abort taken without a change " - "in Exception level.\n"); - break; - } - - case 0b100010: - { - sinfo("PC alignment fault exception.\n"); - break; - } - - case 0b100100: - { - sinfo( - "Data Abort from a lower Exception level, that might " - "be using AArch32 or AArch64\n"); - break; - } - - case 0b100101: - { - sinfo("Data Abort taken without a change in Exception level\n"); - break; - } - - case 0b100110: - { - sinfo("SP alignment fault exception\n"); - break; - } - - case 0b101000: - { - sinfo( - "Trapped floating-point exception " - "taken from AArch32 state\n"); - break; - } - - case 0b101100: - { - sinfo( - "Trapped floating-point exception " - "taken from AArch64 state.\n"); - break; - } - - case 0b101111: - { - sinfo("SError interrupt\n"); - break; - } - - case 0b110000: - { - sinfo( - "Breakpoint exception from a lower Exception level, " - "that might be using AArch32 or AArch64\n"); - break; - } - - case 0b110001: - { - sinfo( - "Breakpoint exception taken without a change in " - "Exception level\n"); - break; - } - - case 0b110010: - { - sinfo( - "Software Step exception from a lower Exception level, " - "that might be using AArch32 or AArch64\n"); - break; - } - - case 0b110011: - { - sinfo( - "Software Step exception taken without a change in " - "Exception level\n"); - break; - } - - case 0b110100: - { - sinfo( - "Watchpoint exception from a lower Exception level, " - "that might be using AArch32 or AArch64\n"); - break; - } - - case 0b110101: - { - sinfo( - "Watchpoint exception taken without a change in " - "Exception level.\n"); - break; - } - - case 0b111000: - { - sinfo("BKPT instruction execution in AArch32 state\n"); - break; - } - - case 0b111100: - { - sinfo("BRK instruction execution in AArch64 state.\n"); + ret = arm64_el1_fpac(regs, esr); break; } default: - break; + { + sinfo("64-bit el1h sync, esr = 0x%x", ec); + ret = -EINVAL; + } + } + + return ret; +} + +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; } + + case MODE_EL2: + { + el_str = "MODE_EL2"; + esr = read_sysreg(esr_el2); + far = read_sysreg(far_el2); + elr = read_sysreg(elr_el2); + break; + } + +#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) + { + 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; } /**************************************************************************** * Public Functions ****************************************************************************/ -/**************************************************************************** - * Name: up_mdelay - ****************************************************************************/ - -void up_mdelay(unsigned int milliseconds) +void arm64_fatal_handler(struct regs_context *regs) { - volatile unsigned int i; - volatile unsigned int j; + int ret; - for (i = 0; i < milliseconds; i++) + /* Nested exception are not supported */ + + DEBUGASSERT(up_current_regs() == NULL); + + up_set_current_regs((uint64_t *)regs); + + ret = arm64_exception_handler(regs); + + if (ret != 0) { - for (j = 0; j < CONFIG_BOARD_LOOPSPERMSEC; j++) - { - } - } -} + /* The fatal is not handled, print error and hung */ -/**************************************************************************** - * Name: arm64_fatal_error - * - * Description: - * - ****************************************************************************/ - -void arm64_fatal_error(unsigned int reason, struct regs_context * reg) -{ - uint64_t el, esr, elr, far; - - sinfo("reason = %d\n", reason); - - up_set_current_regs((uint64_t *)reg); - - if (reason != K_ERR_SPURIOUS_IRQ) - { - __asm__ volatile ("mrs %0, CurrentEL" : "=r" (el)); - - 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; - } - -#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 - - default: - { - sinfo("CurrentEL: unknown\n"); - - /* Just to keep the compiler happy */ - - esr = elr = far = 0; - break; - } - } - - 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); - - print_ec_cause(esr); - } + PANIC_WITH_REGS("panic", regs); } - PANIC_WITH_REGS("panic", reg); + /* Set CURRENT_REGS to NULL to indicate that we are no longer in an + * Exception handler. + */ + + up_set_current_regs(NULL); +} + +void arm64_register_debug_hook(int nr, fatal_handle_func_t fn) +{ + DEBUGVERIFY(nr > 0 && nr <= nitems(g_debug_handler)); + + /* Override the default handler */ + + 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_error(unsigned int reason, struct regs_context * reg); -void arm64_dump_fatal(struct regs_context * reg); +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_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 */