2019-11-10 16:17:19 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2019 Carlo Caione <ccaione@baylibre.com>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file
|
|
|
|
* @brief Kernel fatal error handler for ARM64 Cortex-A
|
|
|
|
*
|
|
|
|
* This module provides the z_arm64_fatal_error() routine for ARM64 Cortex-A
|
2020-11-06 18:55:16 +01:00
|
|
|
* CPUs and z_arm64_do_kernel_oops() routine to manage software-generated fatal
|
|
|
|
* exceptions
|
2019-11-10 16:17:19 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <kernel.h>
|
|
|
|
#include <logging/log.h>
|
|
|
|
|
2020-11-26 19:32:34 +01:00
|
|
|
LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
|
2019-11-10 16:17:19 +00:00
|
|
|
|
2020-11-10 11:45:46 +01:00
|
|
|
#ifdef CONFIG_EXCEPTION_DEBUG
|
2020-11-09 16:00:37 +01:00
|
|
|
static void dump_esr(uint64_t esr, bool *dump_far)
|
2019-11-10 16:17:19 +00:00
|
|
|
{
|
2020-11-09 16:00:37 +01:00
|
|
|
const char *err;
|
2019-11-10 16:17:19 +00:00
|
|
|
|
2021-02-11 15:22:04 +01:00
|
|
|
switch (GET_ESR_EC(esr)) {
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b000000: /* 0x00 */
|
|
|
|
err = "Unknown reason";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b000001: /* 0x01 */
|
|
|
|
err = "Trapped WFI or WFE instruction execution";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b000011: /* 0x03 */
|
|
|
|
err = "Trapped MCR or MRC access with (coproc==0b1111) that "
|
|
|
|
"is not reported using EC 0b000000";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b000100: /* 0x04 */
|
|
|
|
err = "Trapped MCRR or MRRC access with (coproc==0b1111) "
|
|
|
|
"that is not reported using EC 0b000000";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b000101: /* 0x05 */
|
|
|
|
err = "Trapped MCR or MRC access with (coproc==0b1110)";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b000110: /* 0x06 */
|
|
|
|
err = "Trapped LDC or STC access";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b000111: /* 0x07 */
|
|
|
|
err = "Trapped access to SVE, Advanced SIMD, or "
|
|
|
|
"floating-point functionality";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b001100: /* 0x0c */
|
|
|
|
err = "Trapped MRRC access with (coproc==0b1110)";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b001101: /* 0x0d */
|
|
|
|
err = "Branch Target Exception";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b001110: /* 0x0e */
|
|
|
|
err = "Illegal Execution state";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b010001: /* 0x11 */
|
|
|
|
err = "SVC instruction execution in AArch32 state";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b011000: /* 0x18 */
|
|
|
|
err = "Trapped MSR, MRS or System instruction execution in "
|
|
|
|
"AArch64 state, that is not reported using EC "
|
|
|
|
"0b000000, 0b000001 or 0b000111";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b011001: /* 0x19 */
|
|
|
|
err = "Trapped access to SVE functionality";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b100000: /* 0x20 */
|
|
|
|
*dump_far = true;
|
|
|
|
err = "Instruction Abort from a lower Exception level, that "
|
|
|
|
"might be using AArch32 or AArch64";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b100001: /* 0x21 */
|
|
|
|
*dump_far = true;
|
|
|
|
err = "Instruction Abort taken without a change in Exception "
|
|
|
|
"level.";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b100010: /* 0x22 */
|
|
|
|
*dump_far = true;
|
|
|
|
err = "PC alignment fault exception.";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b100100: /* 0x24 */
|
|
|
|
*dump_far = true;
|
|
|
|
err = "Data Abort from a lower Exception level, that might "
|
|
|
|
"be using AArch32 or AArch64";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b100101: /* 0x25 */
|
|
|
|
*dump_far = true;
|
|
|
|
err = "Data Abort taken without a change in Exception level";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b100110: /* 0x26 */
|
|
|
|
err = "SP alignment fault exception";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b101000: /* 0x28 */
|
|
|
|
err = "Trapped floating-point exception taken from AArch32 "
|
|
|
|
"state";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b101100: /* 0x2c */
|
|
|
|
err = "Trapped floating-point exception taken from AArch64 "
|
|
|
|
"state.";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b101111: /* 0x2f */
|
|
|
|
err = "SError interrupt";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b110000: /* 0x30 */
|
|
|
|
err = "Breakpoint exception from a lower Exception level, "
|
|
|
|
"that might be using AArch32 or AArch64";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b110001: /* 0x31 */
|
|
|
|
err = "Breakpoint exception taken without a change in "
|
|
|
|
"Exception level";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b110010: /* 0x32 */
|
|
|
|
err = "Software Step exception from a lower Exception level, "
|
|
|
|
"that might be using AArch32 or AArch64";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b110011: /* 0x33 */
|
|
|
|
err = "Software Step exception taken without a change in "
|
|
|
|
"Exception level";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b110100: /* 0x34 */
|
|
|
|
*dump_far = true;
|
|
|
|
err = "Watchpoint exception from a lower Exception level, "
|
|
|
|
"that might be using AArch32 or AArch64";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b110101: /* 0x35 */
|
|
|
|
*dump_far = true;
|
|
|
|
err = "Watchpoint exception taken without a change in "
|
|
|
|
"Exception level.";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b111000: /* 0x38 */
|
|
|
|
err = "BKPT instruction execution in AArch32 state";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
case 0b111100: /* 0x3c */
|
|
|
|
err = "BRK instruction execution in AArch64 state.";
|
2019-11-10 16:17:19 +00:00
|
|
|
break;
|
2020-11-09 16:00:37 +01:00
|
|
|
default:
|
|
|
|
err = "Unknown";
|
2019-11-10 16:17:19 +00:00
|
|
|
}
|
2020-11-09 16:00:37 +01:00
|
|
|
|
|
|
|
LOG_ERR("ESR_ELn: 0x%016llx", esr);
|
2021-02-11 15:22:04 +01:00
|
|
|
LOG_ERR(" EC: 0x%llx (%s)", GET_ESR_EC(esr), err);
|
|
|
|
LOG_ERR(" IL: 0x%llx", GET_ESR_IL(esr));
|
|
|
|
LOG_ERR(" ISS: 0x%llx", GET_ESR_ISS(esr));
|
2019-11-10 16:17:19 +00:00
|
|
|
}
|
|
|
|
|
2020-01-20 16:14:17 +01:00
|
|
|
static void esf_dump(const z_arch_esf_t *esf)
|
|
|
|
{
|
2020-11-11 15:19:24 +01:00
|
|
|
LOG_ERR("x0: 0x%016llx x1: 0x%016llx", esf->x0, esf->x1);
|
|
|
|
LOG_ERR("x2: 0x%016llx x3: 0x%016llx", esf->x2, esf->x3);
|
|
|
|
LOG_ERR("x4: 0x%016llx x5: 0x%016llx", esf->x4, esf->x5);
|
|
|
|
LOG_ERR("x6: 0x%016llx x7: 0x%016llx", esf->x6, esf->x7);
|
|
|
|
LOG_ERR("x8: 0x%016llx x9: 0x%016llx", esf->x8, esf->x9);
|
|
|
|
LOG_ERR("x10: 0x%016llx x11: 0x%016llx", esf->x10, esf->x11);
|
|
|
|
LOG_ERR("x12: 0x%016llx x13: 0x%016llx", esf->x12, esf->x13);
|
|
|
|
LOG_ERR("x14: 0x%016llx x15: 0x%016llx", esf->x14, esf->x15);
|
|
|
|
LOG_ERR("x16: 0x%016llx x17: 0x%016llx", esf->x16, esf->x17);
|
|
|
|
LOG_ERR("x18: 0x%016llx x30: 0x%016llx", esf->x18, esf->x30);
|
2020-01-20 16:14:17 +01:00
|
|
|
}
|
2020-11-10 11:45:46 +01:00
|
|
|
#endif /* CONFIG_EXCEPTION_DEBUG */
|
2020-01-20 16:14:17 +01:00
|
|
|
|
2020-11-09 16:03:35 +01:00
|
|
|
static bool is_recoverable(z_arch_esf_t *esf, uint64_t esr, uint64_t far,
|
|
|
|
uint64_t elr)
|
|
|
|
{
|
|
|
|
if (!esf)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Empty */
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void z_arm64_fatal_error(unsigned int reason, z_arch_esf_t *esf)
|
2019-11-10 16:17:19 +00:00
|
|
|
{
|
2020-10-06 12:51:33 +02:00
|
|
|
uint64_t esr = 0;
|
|
|
|
uint64_t elr = 0;
|
|
|
|
uint64_t far = 0;
|
|
|
|
uint64_t el;
|
2019-11-10 16:17:19 +00:00
|
|
|
|
|
|
|
if (reason != K_ERR_SPURIOUS_IRQ) {
|
2021-02-12 13:58:06 +01:00
|
|
|
el = read_currentel();
|
2019-11-10 16:17:19 +00:00
|
|
|
|
2020-10-06 12:51:33 +02:00
|
|
|
switch (GET_EL(el)) {
|
|
|
|
case MODE_EL1:
|
2021-02-12 13:58:06 +01:00
|
|
|
esr = read_esr_el1();
|
|
|
|
far = read_far_el1();
|
|
|
|
elr = read_elr_el1();
|
2020-10-06 12:51:33 +02:00
|
|
|
break;
|
|
|
|
case MODE_EL3:
|
2021-02-12 13:58:06 +01:00
|
|
|
esr = read_esr_el3();
|
|
|
|
far = read_far_el3();
|
|
|
|
elr = read_elr_el3();
|
2020-10-06 12:51:33 +02:00
|
|
|
break;
|
|
|
|
}
|
2019-11-10 16:17:19 +00:00
|
|
|
|
2020-10-06 12:51:33 +02:00
|
|
|
if (GET_EL(el) != MODE_EL0) {
|
2020-11-10 11:45:46 +01:00
|
|
|
#ifdef CONFIG_EXCEPTION_DEBUG
|
2020-11-09 16:00:37 +01:00
|
|
|
bool dump_far = false;
|
|
|
|
|
2020-09-30 15:47:02 -04:00
|
|
|
LOG_ERR("ELR_ELn: 0x%016llx", elr);
|
2019-11-10 16:17:19 +00:00
|
|
|
|
2020-11-09 16:00:37 +01:00
|
|
|
dump_esr(esr, &dump_far);
|
|
|
|
|
|
|
|
if (dump_far)
|
|
|
|
LOG_ERR("FAR_ELn: 0x%016llx", far);
|
2020-11-10 11:45:46 +01:00
|
|
|
#endif /* CONFIG_EXCEPTION_DEBUG */
|
2020-11-09 16:03:35 +01:00
|
|
|
|
|
|
|
if (is_recoverable(esf, esr, far, elr))
|
|
|
|
return;
|
2019-11-10 16:17:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 11:45:46 +01:00
|
|
|
#ifdef CONFIG_EXCEPTION_DEBUG
|
2020-01-20 16:14:17 +01:00
|
|
|
if (esf != NULL) {
|
|
|
|
esf_dump(esf);
|
|
|
|
}
|
2020-11-10 11:45:46 +01:00
|
|
|
#endif /* CONFIG_EXCEPTION_DEBUG */
|
|
|
|
|
2020-01-20 16:14:17 +01:00
|
|
|
z_fatal_error(reason, esf);
|
2019-11-10 16:17:19 +00:00
|
|
|
|
|
|
|
CODE_UNREACHABLE;
|
|
|
|
}
|
2020-11-06 18:55:16 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Handle a software-generated fatal exception
|
|
|
|
* (e.g. kernel oops, panic, etc.).
|
|
|
|
*
|
|
|
|
* @param esf exception frame
|
|
|
|
*/
|
|
|
|
void z_arm64_do_kernel_oops(z_arch_esf_t *esf)
|
|
|
|
{
|
|
|
|
/* x8 holds the exception reason */
|
|
|
|
unsigned int reason = esf->x8;
|
|
|
|
|
|
|
|
z_arm64_fatal_error(reason, esf);
|
|
|
|
}
|
2020-11-10 17:09:12 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_USERSPACE
|
|
|
|
FUNC_NORETURN void arch_syscall_oops(void *ssf_ptr)
|
|
|
|
{
|
|
|
|
ARG_UNUSED(ssf_ptr);
|
|
|
|
|
|
|
|
z_arm64_fatal_error(K_ERR_KERNEL_OOPS, NULL);
|
|
|
|
CODE_UNREACHABLE;
|
|
|
|
}
|
|
|
|
#endif
|