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 <qinwei1@xiaomi.com>
This commit is contained in:
parent
068c7176bb
commit
40d40015f4
@ -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"
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user