blob: 9ccb4f3fd924503c612f697f75de1e595bf0c37d [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/arch/cpu.h>
#include <zephyr/kernel_structs.h>
#include <inttypes.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
FUNC_NORETURN void z_nios2_fatal_error(unsigned int reason,
const z_arch_esf_t *esf)
{
if (esf != NULL) {
/* Subtract 4 from EA since we added 4 earlier so that the
* faulting instruction isn't retried.
*
* TODO: Only caller-saved registers get saved upon exception
* entry. We may want to introduce a config option to save and
* dump all registers, at the expense of some stack space.
*/
LOG_ERR("Faulting instruction: 0x%08x", esf->instr - 4);
LOG_ERR(" r1: 0x%08x r2: 0x%08x r3: 0x%08x r4: 0x%08x",
esf->r1, esf->r2, esf->r3, esf->r4);
LOG_ERR(" r5: 0x%08x r6: 0x%08x r7: 0x%08x r8: 0x%08x",
esf->r5, esf->r6, esf->r7, esf->r8);
LOG_ERR(" r9: 0x%08x r10: 0x%08x r11: 0x%08x r12: 0x%08x",
esf->r9, esf->r10, esf->r11, esf->r12);
LOG_ERR(" r13: 0x%08x r14: 0x%08x r15: 0x%08x ra: 0x%08x",
esf->r13, esf->r14, esf->r15, esf->ra);
LOG_ERR("estatus: %08x", esf->estatus);
}
z_fatal_error(reason, esf);
CODE_UNREACHABLE;
}
#if defined(CONFIG_EXTRA_EXCEPTION_INFO) && \
(defined(CONFIG_PRINTK) || defined(CONFIG_LOG)) \
&& defined(ALT_CPU_HAS_EXTRA_EXCEPTION_INFO)
static char *cause_str(uint32_t cause_code)
{
switch (cause_code) {
case 0:
return "reset";
case 1:
return "processor-only reset request";
case 2:
return "interrupt";
case 3:
return "trap";
case 4:
return "unimplemented instruction";
case 5:
return "illegal instruction";
case 6:
return "misaligned data address";
case 7:
return "misaligned destination address";
case 8:
return "division error";
case 9:
return "supervisor-only instruction address";
case 10:
return "supervisor-only instruction";
case 11:
return "supervisor-only data address";
case 12:
return "TLB miss";
case 13:
return "TLB permission violation (execute)";
case 14:
return "TLB permission violation (read)";
case 15:
return "TLB permission violation (write)";
case 16:
return "MPU region violation (instruction)";
case 17:
return "MPU region violation (data)";
case 18:
return "ECC TLB error";
case 19:
return "ECC fetch error (instruction)";
case 20:
return "ECC register file error";
case 21:
return "ECC data error";
case 22:
return "ECC data cache writeback error";
case 23:
return "bus instruction fetch error";
case 24:
return "bus data region violation";
default:
return "unknown";
}
}
#endif
FUNC_NORETURN void _Fault(const z_arch_esf_t *esf)
{
#if defined(CONFIG_PRINTK) || defined(CONFIG_LOG)
/* Unfortunately, completely unavailable on Nios II/e cores */
#ifdef ALT_CPU_HAS_EXTRA_EXCEPTION_INFO
uint32_t exc_reg, badaddr_reg, eccftl;
enum nios2_exception_cause cause;
exc_reg = z_nios2_creg_read(NIOS2_CR_EXCEPTION);
/* Bit 31 indicates potentially fatal ECC error */
eccftl = (exc_reg & NIOS2_EXCEPTION_REG_ECCFTL_MASK) != 0U;
/* Bits 2-6 contain the cause code */
cause = (exc_reg & NIOS2_EXCEPTION_REG_CAUSE_MASK)
>> NIOS2_EXCEPTION_REG_CAUSE_OFST;
LOG_ERR("Exception cause: %d ECCFTL: 0x%x", cause, eccftl);
#if CONFIG_EXTRA_EXCEPTION_INFO
LOG_ERR("reason: %s", cause_str(cause));
#endif
if (BIT(cause) & NIOS2_BADADDR_CAUSE_MASK) {
badaddr_reg = z_nios2_creg_read(NIOS2_CR_BADADDR);
LOG_ERR("Badaddr: 0x%x", badaddr_reg);
}
#endif /* ALT_CPU_HAS_EXTRA_EXCEPTION_INFO */
#endif /* CONFIG_PRINTK || CONFIG_LOG */
z_nios2_fatal_error(K_ERR_CPU_EXCEPTION, esf);
}
#ifdef ALT_CPU_HAS_DEBUG_STUB
FUNC_NORETURN void arch_system_halt(unsigned int reason)
{
ARG_UNUSED(reason);
z_nios2_break();
CODE_UNREACHABLE;
}
#endif