diff options
-rw-r--r-- | common/panic_output.c | 2 | ||||
-rw-r--r-- | core/cortex-m/panic.c | 54 | ||||
-rw-r--r-- | core/cortex-m/watchdog.c | 13 | ||||
-rw-r--r-- | include/panic.h | 13 |
4 files changed, 73 insertions, 9 deletions
diff --git a/common/panic_output.c b/common/panic_output.c index e6b48a375d..fd1b1999a0 100644 --- a/common/panic_output.c +++ b/common/panic_output.c @@ -98,7 +98,7 @@ void panic_assert_fail(const char *msg, const char *func, const char *fname, panic_printf("\nASSERTION FAILURE '%s' in %s() at %s:%d\n", msg, func, fname, linenum); #ifdef CONFIG_SOFTWARE_PANIC - software_panic(PANIC_SW_ASSERT, linenum); + panic_assert(func, fname, (uint16_t)linenum); #else panic_reboot(); #endif diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index de8ca07b3e..c4954ec000 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -227,7 +227,8 @@ static void panic_show_extra(const struct panic_data *pdata) 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]); } /* @@ -268,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++) @@ -332,6 +342,12 @@ void __keep report_panic(void) 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 @@ -440,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) diff --git a/core/cortex-m/watchdog.c b/core/cortex-m/watchdog.c index 4da32d26d0..f9283bbbd7 100644 --- a/core/cortex-m/watchdog.c +++ b/core/cortex-m/watchdog.c @@ -32,12 +32,17 @@ void __keep watchdog_trace(uint32_t excep_lr, uint32_t excep_sp) panic_set_reason(PANIC_SW_WATCHDOG, stack[6], (excep_lr & 0xf) == 1 ? 0xff : task_get_current()); + /* Copy task# to cm.hfsr[9:2]. */ + pdata_ptr->cm.hfsr = HFSR_FLAG_WATCHDOG << 26 + | (pdata_ptr->cm.regs[1] & 0xff) << 2; + /* - * Store LR to cm.hfsr. It is for HardFault status register but it is - * probably the least informative register used by - * chip_panic_data_backup of the existing RO. + * Store LR in cm.regs[1] (ipsr). IPSR holds exception# but we don't + * need it because the reason (=PANIC_SW_WATCHDOG) is already stored + * in cm.regs[3] (r4). Note this overwrites task# in cm.regs[1] stored + * by panic_set_reason. */ - pdata_ptr->cm.hfsr = stack[5]; + pdata_ptr->cm.regs[1] = stack[5]; panic_printf("### WATCHDOG PC=%08x / LR=%08x / pSP=%08x ", stack[6], stack[5], psp); diff --git a/include/panic.h b/include/panic.h index 47c749d027..d1099d6cce 100644 --- a/include/panic.h +++ b/include/panic.h @@ -188,6 +188,19 @@ void panic_set_reason(uint32_t reason, uint32_t info, uint8_t exception); void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception); #endif +#define HFSR_FLAG_ASSERT 3 +#define HFSR_FLAG_WATCHDOG 4 + +/** + * Save code location in struct panic_data then reboot. + * + * @param func Function name (i.e. __func__). Stored in regs[3]. + * @param file File path (i.e. __FILE__). Stored in regs[4]. + * @param line Line number (i.e. __LINE__). Stored in HFSR[25:10]. + */ +void panic_assert(const char *func, const char *file, uint16_t line) + __attribute__((noreturn)); + /** * Enable/disable bus fault handler * |