diff options
Diffstat (limited to 'core/cortex-m/panic.c')
-rw-r--r-- | core/cortex-m/panic.c | 172 |
1 files changed, 120 insertions, 52 deletions
diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 7daedbf7ab..c4954ec000 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -77,44 +77,28 @@ static int32_t is_frame_in_handler_stack(const uint32_t exc_return) } #ifdef CONFIG_DEBUG_EXCEPTIONS -/* 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 each of the bits in the cfs register, starting at bit 0 */ +static const char * const cfsr_name[32] = { + /* MMFSR */ + [0] = "Instruction access violation", + [1] = "Data access violation", + [3] = "Unstack from exception violation", + [4] = "Stack from exception violation", + + /* BFSR */ + [8] = "Instruction bus error", + [9] = "Precise data bus error", + [10] = "Imprecise data bus error", + [11] = "Unstack from exception bus fault", + [12] = "Stack from exception bus fault", + + /* UFSR */ + [16] = "Undefined instructions", + [17] = "Invalid state", + [18] = "Invalid PC", + [19] = "No coprocessor", + [24] = "Unaligned", + [25] = "Divide by 0", }; /* Names for the first 5 bits in the DFSR */ @@ -146,19 +130,19 @@ static void do_separate(int *count) * * A list of detected faults is shown, with no trailing newline. * - * @param mmfs Value of Memory Manage Fault Status + * @param cfsr Value of Configurable 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) +static void show_fault(uint32_t cfsr, 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]) { + if ((cfsr & (1 << upto)) && cfsr_name[upto]) { do_separate(&count); - panic_puts(mmfs_name[upto]); + panic_puts(cfsr_name[upto]); } } @@ -235,15 +219,16 @@ static uint32_t get_process_stack_position(const struct panic_data *pdata) */ static void panic_show_extra(const struct panic_data *pdata) { - show_fault(pdata->cm.mmfs, pdata->cm.hfsr, pdata->cm.dfsr); - if (pdata->cm.mmfs & CPU_NVIC_MMFS_BFARVALID) + show_fault(pdata->cm.cfsr, pdata->cm.hfsr, pdata->cm.dfsr); + if (pdata->cm.cfsr & CPU_NVIC_CFSR_BFARVALID) panic_printf(", bfar = %x", pdata->cm.bfar); - if (pdata->cm.mmfs & CPU_NVIC_MMFS_MFARVALID) + if (pdata->cm.cfsr & CPU_NVIC_CFSR_MFARVALID) panic_printf(", mfar = %x", pdata->cm.mfar); - panic_printf("\nmmfs = %x, ", pdata->cm.mmfs); + panic_printf("\ncfsr = %x, ", pdata->cm.cfsr); panic_printf("shcsr = %x, ", pdata->cm.shcsr); panic_printf("hfsr = %x, ", pdata->cm.hfsr); - panic_printf("dfsr = %x\n", pdata->cm.dfsr); + panic_printf("dfsr = %x, ", pdata->cm.dfsr); + panic_printf("ipsr = %x\n", pdata->cm.regs[1]); } /* @@ -284,9 +269,18 @@ void panic_data_print(const struct panic_data *pdata) if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) sregs = pdata->cm.frame; - panic_printf("\n=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n", - in_handler ? "HANDLER" : "PROCESS", - lregs[1] & 0xff, sregs ? sregs[7] : -1); + if (((pdata->cm.hfsr >> 26) & 0xf) == HFSR_FLAG_WATCHDOG) { + panic_printf("\n### WATCHDOG PC=%08x / LR=%08x / task=%d\n", + lregs[4], lregs[1], (pdata->cm.hfsr >> 2) & 0xff); + } else if (((pdata->cm.hfsr >> 26) & 0xf) == HFSR_FLAG_ASSERT) { + panic_printf("\nASSERTION FAILURE in %s() at %s:%d\n", + lregs[3], lregs[4], + (pdata->cm.hfsr >> 10) & 0xffff); + } else { + panic_printf("\n=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n", + in_handler ? "HANDLER" : "PROCESS", + lregs[1] & 0xff, sregs ? sregs[7] : -1); + } for (i = 0; i < 4; i++) print_reg(i, sregs, i); for (i = 4; i < 10; i++) @@ -324,19 +318,36 @@ void __keep report_panic(void) sp <= CONFIG_RAM_BASE + CONFIG_RAM_SIZE - 8 * sizeof(uint32_t)) { const uint32_t *sregs = (const uint32_t *)sp; int i; - for (i = 0; i < 8; i++) + + /* Skip r0-r3 and r12 registers if necessary */ + for (i = CORTEX_PANIC_FRAME_REGISTER_R0; + i <= CORTEX_PANIC_FRAME_REGISTER_R12; i++) + if (IS_ENABLED(CONFIG_PANIC_STRIP_GPR)) + pdata->cm.frame[i] = 0; + else + pdata->cm.frame[i] = sregs[i]; + + for (i = CORTEX_PANIC_FRAME_REGISTER_LR; + i < NUM_CORTEX_PANIC_FRAME_REGISTERS; i++) pdata->cm.frame[i] = sregs[i]; + pdata->flags |= PANIC_DATA_FLAG_FRAME_VALID; } /* Save extra information */ - pdata->cm.mmfs = CPU_NVIC_MMFS; + pdata->cm.cfsr = CPU_NVIC_CFSR; pdata->cm.bfar = CPU_NVIC_BFAR; pdata->cm.mfar = CPU_NVIC_MFAR; pdata->cm.shcsr = CPU_NVIC_SHCSR; pdata->cm.hfsr = CPU_NVIC_HFSR; pdata->cm.dfsr = CPU_NVIC_DFSR; + /* Store LR & PC in cm.regs to make them survive a PMIC reset. */ + if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) { + pdata->cm.regs[3] = pdata->cm.frame[5]; /* LR */ + pdata->cm.regs[4] = pdata->cm.frame[6]; /* PC */ + } + #ifdef CONFIG_UART_PAD_SWITCH uart_reset_default_pad_panic(); #endif @@ -364,6 +375,33 @@ void exception_panic(void) "mrs r1, psp\n" "mrs r2, ipsr\n" "mov r3, sp\n" +#ifdef CONFIG_PANIC_STRIP_GPR + /* + * Check if we are in exception. This is similar to + * in_interrupt_context(). Exception bits are 9 LSB, so + * we can perform left shift for 23 bits and check if result + * is 0 (lsls instruction is setting appropriate flags). + */ + "lsls r6, r2, #23\n" + /* + * If this is software panic (shift result == 0) then register + * r4 and r5 contain additional info about panic. + * Clear r6-r11 always and r4, r5 only if this is exception + * panic. To clear r4 and r5, 'movne' conditional instruction + * is used. It works only when flags contain information that + * result was != 0. Itt is pseudo instruction which is used + * to make sure we are using correct conditional instructions. + */ + "itt ne\n" + "movne r4, #0\n" + "movne r5, #0\n" + "mov r6, #0\n" + "mov r7, #0\n" + "mov r8, #0\n" + "mov r9, #0\n" + "mov r10, #0\n" + "mov r11, #0\n" +#endif "stmia r0, {r1-r11, lr}\n" "mov sp, %[pstack]\n" "bl report_panic\n" : : @@ -418,6 +456,36 @@ void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception) } #endif +void panic_assert(const char *func, const char *file, uint16_t line) +{ + struct panic_data *pdata = pdata_ptr; + + pdata->magic = PANIC_DATA_MAGIC; + pdata->struct_size = sizeof(*pdata); + pdata->struct_version = 2; + pdata->arch = PANIC_ARCH_CORTEX_M; + pdata->flags = 0; + pdata->reserved = 0; + + /* + * Panic data is cleared by PMIC reset on Nami. HFSR is used because + * it's saved to BBRAM by the released RO (before PMIC reset). Bit + * assignments are as follows: + * + * ([31:30] Used for DEBUGEVT and FORCED) + * [29:26] Flags + * [25:10] Line # + * [9:2] Task # + * ([1:0] Used for VECTTBLE and reserved) + */ + pdata->cm.hfsr = HFSR_FLAG_ASSERT << 26 | line << 10 + | (task_get_current() & 0xff) << 2; + pdata->cm.regs[3] = (uint32_t)func; + pdata->cm.regs[4] = (uint32_t)file; + + panic_reboot(); +} + void bus_fault_handler(void) { if (!bus_fault_ignored) |