diff --git a/README b/README index e87846bf7d..9d9484f79f 100644 --- a/README +++ b/README @@ -39,3 +39,18 @@ Build Options When reporting a panic, change to a completely new stack. This might help get a useful trace out a situation where the stack or stack pointer has been corrupted. + +- CONFIG_PANIC_HELP + + Report extra information about a panic, such as the fault address, + here shown as bfar. This shows the reason for the fault and may help + to determine the cause. + + === EXCEPTION: 03 ====== xPSR: 01000000 =========== + r0 :0000000b r1 :00000047 r2 :60000000 r3 :200013dd + r4 :00000000 r5 :080053f4 r6 :200013d0 r7 :00000002 + r8 :00000000 r9 :200013de r10:00000000 r11:00000000 + r12:00000000 sp :200009a0 lr :08002b85 pc :08003a8a + Precise data bus error, Forced hard fault, Vector catch, bfar = 60000000 + mmfs = 00008200, shcsr = 00000000, hfsr = 40000000, dfsr = 00000008 + diff --git a/core/cortex-m/cpu.h b/core/cortex-m/cpu.h index 7e032164a7..2e75d6c1c5 100644 --- a/core/cortex-m/cpu.h +++ b/core/cortex-m/cpu.h @@ -23,4 +23,24 @@ #define CPU_SCB_SYSCTRL CPUREG(0xe000ed10) +#define CPU_NVIC_CCR CPUREG(0xe000ed14) +#define CPU_NVIC_SHCSR CPUREG(0xe000ed24) +#define CPU_NVIC_MMFS CPUREG(0xe000ed28) +#define CPU_NVIC_HFSR CPUREG(0xe000ed2c) +#define CPU_NVIC_DFSR CPUREG(0xe000ed30) +#define CPU_NVIC_MFAR CPUREG(0xe000ed34) +#define CPU_NVIC_BFAR CPUREG(0xe000ed38) + +enum { + CPU_NVIC_MMFS_BFARVALID = 1 << 15, + CPU_NVIC_MMFS_MFARVALID = 1 << 7, + + CPU_NVIC_CCR_DIV_0_TRAP = 1 << 4, + CPU_NVIC_CCR_UNALIGN_TRAP = 1 << 3, + + CPU_NVIC_HFSR_DEBUGEVT = 1UL << 31, + CPU_NVIC_HFSR_FORCED = 1 << 30, + CPU_NVIC_HFSR_VECTTBL = 1 << 1, +}; + #endif /* __CPU_H */ diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 8e022857ef..d249974b06 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -150,6 +150,141 @@ static void print_reg(int regnum, uint32_t *regs, int index) panic_putc((regnum & 3) == 3 ? '\n' : ' '); } +#ifdef CONFIG_PANIC_HELP +/* Names for each of the bits in the mmfs register, starting at bit 0 */ +static const char * const mmfs_name[32] = { + "Instruction access violation", + "Data access violation", + NULL, + "Unstack from exception violation", + "Stack from exception violation", + NULL, + NULL, + NULL, + + "Instruction bus error", + "Precise data bus error", + "Imprecise data bus error", + "Unstack from exception bus fault", + "Stack from exception bus fault", + NULL, + NULL, + NULL, + + "Undefined instructions", + "Invalid state", + "Invalid PC", + "No coprocessor", + NULL, + NULL, + NULL, + NULL, + + "Unaligned", + "Divide by 0", + NULL, + NULL, + + NULL, + NULL, + NULL, + NULL, +}; + + +/* Names for the first 5 bits in the DFSR */ +static const char * const dfsr_name[] = { + "Halt request", + "Breakpoint", + "Data watchpoint/trace", + "Vector catch", + "External debug request", +}; + + +/** + * Helper function to display a separator after the previous item + * + * If items have been displayed already, we display a comma separator. + * In any case, the count of items displayed is incremeneted. + * + * @param count Number of items displayed so far (0 for none) + */ +static void do_separate(int *count) +{ + if (*count) + panic_puts(", "); + (*count)++; +} + + +/** + * Show a textual representaton of the fault registers + * + * A list of detected faults is shown, with no trailing newline. + * + * @param mmfs Value of Memory Manage Fault Status + * @param hfsr Value of Hard Fault Status + * @param dfsr Value of Debug Fault Status + */ +static void show_fault(uint32_t mmfs, uint32_t hfsr, uint32_t dfsr) +{ + unsigned int upto; + int count = 0; + + for (upto = 0; upto < 32; upto++) { + if ((mmfs & (1 << upto)) && mmfs_name[upto]) { + do_separate(&count); + panic_puts(mmfs_name[upto]); + } + } + + if (hfsr & CPU_NVIC_HFSR_DEBUGEVT) { + do_separate(&count); + panic_puts("Debug event"); + } + if (hfsr & CPU_NVIC_HFSR_FORCED) { + do_separate(&count); + panic_puts("Forced hard fault"); + } + if (hfsr & CPU_NVIC_HFSR_VECTTBL) { + do_separate(&count); + panic_puts("Vector table bus fault"); + } + + for (upto = 0; upto < 5; upto++) { + if ((dfsr & (1 << upto))) { + do_separate(&count); + panic_puts(dfsr_name[upto]); + } + } +} + + +/** + * Show extra information that might be useful to understand a panic() + * + * We show fault register information, including the fault address registers + * if valid. + */ +static void panic_show_extra(void) +{ + uint32_t mmfs; + + mmfs = CPU_NVIC_MMFS; + show_fault(mmfs, CPU_NVIC_HFSR, CPU_NVIC_DFSR); + if (mmfs & CPU_NVIC_MMFS_BFARVALID) + panic_printf(", bfar = %x", CPU_NVIC_BFAR); + if (mmfs & CPU_NVIC_MMFS_MFARVALID) + panic_printf(", mfar = %x", CPU_NVIC_MFAR); + panic_putc('\n'); + panic_printf("mmfs = %x, ", mmfs); + panic_printf("shcsr = %x, ", CPU_NVIC_SHCSR); + panic_printf("hfsr = %x, ", CPU_NVIC_HFSR); + panic_printf("dfsr = %x", CPU_NVIC_DFSR); +} +#endif /* CONFIG_PANIC_HELP */ + /** * Display a message and reboot @@ -186,6 +321,9 @@ void report_panic(const char *msg, uint32_t *lregs) print_reg(13, &psp, 0); print_reg(14, sregs, 5); print_reg(15, sregs, 6); +#ifdef CONFIG_PANIC_HELP + panic_show_extra(); +#endif } panic_reboot();