xtensa: cleanup fatal error handling

1) Fatal errors now all go through _SysFatalErrorHandler. When the
simulator is used, only the death of 'essential' threads will result
in the simulator exiting; some test cases that test exceptions may
actually expect a thread to terminate abnormally.

2) The human readability of the exception errors is improved.

Change-Id: I77f57ea0eae15b0c55237681b959cd21e3fe8c1c
Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2017-02-06 12:25:02 -08:00
commit 9249f876a9
2 changed files with 182 additions and 56 deletions

View file

@ -3,20 +3,28 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <arch/cpu.h>
#include <kernel_structs.h>
#include <inttypes.h>
#include <kernel_arch_data.h>
#ifdef CONFIG_PRINTK
#include <misc/printk.h>
#define PR_EXC(...) printk(__VA_ARGS__)
#else
#define PR_EXC(...)
#endif /* CONFIG_PRINTK */
#include <xtensa/specreg.h>
const NANO_ESF _default_esf = {
{0xdeaddead}, /* sp */
0xdeaddead, /* pc */
};
FUNC_NORETURN void exit(int exit_code);
/* Need to do this as a macro since regnum must be an immediate value */
#define get_sreg(regnum_p) ({ \
unsigned int retval; \
__asm__ volatile( \
"rsr %[retval], %[regnum]\n\t" \
: [retval] "=r" (retval) \
: [regnum] "i" (regnum_p)); \
retval; \
})
/**
*
@ -40,25 +48,30 @@ FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason,
const NANO_ESF *pEsf)
{
switch (reason) {
case _NANO_ERR_HW_EXCEPTION:
case _NANO_ERR_RESERVED_IRQ:
break;
case _NANO_ERR_INVALID_TASK_EXIT:
PR_EXC("***** Invalid Exit Software Error! *****\n");
printk("***** Invalid Exit Software Error! *****\n");
break;
#if defined(CONFIG_STACK_CANARIES)
case _NANO_ERR_STACK_CHK_FAIL:
PR_EXC("***** Stack Check Fail! *****\n");
printk("***** Stack Check Fail! *****\n");
break;
#endif /* CONFIG_STACK_CANARIES */
case _NANO_ERR_ALLOCATION_FAIL:
PR_EXC("**** Kernel Allocation Failure! ****\n");
printk("**** Kernel Allocation Failure! ****\n");
break;
default:
PR_EXC("**** Unknown Fatal Error %d! ****\n", reason);
printk("**** Unknown Fatal Error %d! ****\n", reason);
break;
}
PR_EXC("Current thread ID = %p\n"
printk("Current thread ID = %p\n"
"Faulting instruction address = 0x%x\n",
k_current_get(),
pEsf->pc);
/*
* Now that the error has been reported, call the user implemented
* policy
@ -66,57 +79,164 @@ FUNC_NORETURN void _NanoFatalErrorHandler(unsigned int reason,
* appropriate to the various errors are something the customer must
* decide.
*/
/* TODO: call _SysFatalErrorHandler(reason, pEsf); */
exit(253);
_SysFatalErrorHandler(reason, pEsf);
}
void FatalErrorHandler(void)
#ifdef CONFIG_PRINTK
static char *cause_str(unsigned int cause_code)
{
unsigned int tmpReg = 0;
unsigned int Esf[5];
__asm__ volatile("rsr %0, 177\n\t" : "=r"(tmpReg)); /* epc */
Esf[0] = tmpReg;
__asm__ volatile("rsr %0, 232\n\t" : "=r"(tmpReg)); /* exccause */
Esf[1] = tmpReg;
__asm__ volatile("rsr %0, 209\n\t" : "=r"(tmpReg)); /* excsave */
Esf[2] = tmpReg;
__asm__ volatile("rsr %0, 230\n\t" : "=r"(tmpReg)); /* ps */
Esf[3] = tmpReg;
__asm__ volatile("rsr %0, 238\n\t" : "=r"(tmpReg)); /* excvaddr */
Esf[4] = tmpReg;
PR_EXC("Error\nEPC = 0x%x\n"
"EXCCAUSE = 0x%x\n"
"EXCSAVE = 0x%x\n"
"PS = 0x%x\n"
"EXCVADDR = 0x%x\n",
Esf[0], Esf[1], Esf[2], Esf[3], Esf[4]);
exit(255);
switch (cause_code) {
case 0:
return "illegal instruction";
case 1:
return "syscall";
case 2:
return "instr fetch error";
case 3:
return "load/store error";
case 4:
return "level-1 interrupt";
case 5:
return "alloca";
case 6:
return "divide by zero";
case 8:
return "privileged";
case 9:
return "load/store alignment";
case 12:
return "instr PIF data error";
case 13:
return "load/store PIF data error";
case 14:
return "instr PIF addr error";
case 15:
return "load/store PIF addr error";
case 16:
return "instr TLB miss";
case 17:
return "instr TLB multi hit";
case 18:
return "instr fetch privilege";
case 20:
return "inst fetch prohibited";
case 24:
return "load/store TLB miss";
case 25:
return "load/store TLB multi hit";
case 26:
return "load/store privilege";
case 28:
return "load prohibited";
case 29:
return "store prohibited";
case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39:
return "coprocessor disabled";
default:
return "unknown/reserved";
}
}
#endif
void ReservedInterruptHandler(unsigned int intNo)
static inline unsigned int get_bits(int offset, int num_bits, unsigned int val)
{
unsigned int tmpReg = 0;
unsigned int Esf[5];
int mask;
__asm__ volatile("rsr %0, 177\n\t" : "=r"(tmpReg)); /* epc */
Esf[0] = tmpReg;
__asm__ volatile("rsr %0, 232\n\t" : "=r"(tmpReg)); /* exccause */
Esf[1] = tmpReg;
__asm__ volatile("rsr %0, 209\n\t" : "=r"(tmpReg)); /* excsave */
Esf[2] = tmpReg;
__asm__ volatile("rsr %0, 230\n\t" : "=r"(tmpReg)); /* ps */
Esf[3] = tmpReg;
__asm__ volatile("rsr %0, 228\n\t" : "=r"(tmpReg)); /* intenable */
Esf[4] = tmpReg;
PR_EXC("Error, unhandled interrupt\n"
"EPC = 0x%x\n"
"EXCCAUSE = 0x%x\n"
"EXCSAVE = 0x%x\n"
"PS = 0x%x\n"
"INTENABLE = 0x%x\n"
"INTERRUPT = 0x%x\n",
Esf[0], Esf[1], Esf[2], Esf[3], Esf[4], (1 << intNo));
exit(254);
mask = (1 << num_bits) - 1;
val = val >> offset;
return val & mask;
}
static void dump_exc_state(void)
{
#ifdef CONFIG_PRINTK
unsigned int cause, ps;
cause = get_sreg(EXCCAUSE);
ps = get_sreg(PS);
printk("Exception cause %d (%s):\n"
" EPC1 : 0x%08x EXCSAVE1 : 0x%08x EXCVADDR : 0x%08x\n",
cause, cause_str(cause), get_sreg(EPC_1),
get_sreg(EXCSAVE_1), get_sreg(EXCVADDR));
printk("Program state (PS):\n"
" INTLEVEL : %02d EXCM : %d UM : %d RING : %d WOE : %d\n",
get_bits(0, 4, ps), get_bits(4, 1, ps), get_bits(5, 1, ps),
get_bits(6, 2, ps), get_bits(18, 1, ps));
#ifndef __XTENSA_CALL0_ABI__
printk(" OWB : %02d CALLINC : %d\n",
get_bits(8, 4, ps), get_bits(16, 2, ps));
#endif
#endif /* CONFIG_PRINTK */
}
FUNC_NORETURN void FatalErrorHandler(void)
{
printk("*** Unhandled exception ****\n");
dump_exc_state();
_NanoFatalErrorHandler(_NANO_ERR_HW_EXCEPTION, &_default_esf);
}
FUNC_NORETURN void ReservedInterruptHandler(unsigned int intNo)
{
printk("*** Reserved Interrupt ***\n");
dump_exc_state();
printk("INTENABLE = 0x%x\n"
"INTERRUPT = 0x%x (%d)\n",
get_sreg(INTENABLE), (1 << intNo), intNo);
_NanoFatalErrorHandler(_NANO_ERR_RESERVED_IRQ, &_default_esf);
}
/* Implemented in Xtensa HAL */
extern FUNC_NORETURN void exit(int exit_code);
/**
*
* @brief Fatal error handler
*
* This routine implements the corrective action to be taken when the system
* detects a fatal error.
*
* This sample implementation attempts to abort the current thread and allow
* the system to continue executing, which may permit the system to continue
* functioning with degraded capabilities.
*
* System designers may wish to enhance or substitute this sample
* implementation to take other actions, such as logging error (or debug)
* information to a persistent repository and/or rebooting the system.
*
* @param reason the fatal error reason
* @param pEsf pointer to exception stack frame
*
* @return N/A
*/
FUNC_NORETURN void _SysFatalErrorHandler(unsigned int reason,
const NANO_ESF *pEsf)
{
ARG_UNUSED(reason);
ARG_UNUSED(pEsf);
#if !defined(CONFIG_SIMPLE_FATAL_ERROR_HANDLER)
if (k_is_in_isr() || _is_thread_essential()) {
printk("Fatal fault in %s! Spinning...\n",
k_is_in_isr() ? "ISR" : "essential thread");
#ifdef XT_SIMULATOR
exit(255 - reason);
#else
for (;;)
; /* spin forever */
#endif
}
printk("Fatal fault in thread %p! Aborting.\n", _current);
k_thread_abort(_current);
#else
for (;;) {
k_cpu_idle();
}
#endif
CODE_UNREACHABLE;
}

View file

@ -33,6 +33,7 @@ extern "C" {
#define _NANO_ERR_INVALID_TASK_EXIT (1) /* Invalid task exit */
#define _NANO_ERR_STACK_CHK_FAIL (2) /* Stack corruption detected */
#define _NANO_ERR_ALLOCATION_FAIL (3) /* Kernel Allocation Failure */
#define _NANO_ERR_RESERVED_IRQ (4) /* Reserved interrupt */
/* Xtensa GPRs are often designated by two different names */
#define sys_define_gpr_with_alias(name1, name2) union { uint32_t name1, name2; }
@ -120,6 +121,11 @@ extern void _irq_priority_set(uint32_t irq, uint32_t prio, uint32_t flags);
_irq_priority_set(irq_p, priority_p, flags_p); \
irq_p; \
})
FUNC_NORETURN void _SysFatalErrorHandler(unsigned int reason,
const NANO_ESF *esf);
#endif /* !defined(_ASMLANGUAGE) && !defined(__ASSEMBLER__) */
#ifdef __cplusplus
}