diff options
Diffstat (limited to 'core/cortex-m/panic.c')
-rw-r--r-- | core/cortex-m/panic.c | 98 |
1 files changed, 93 insertions, 5 deletions
diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 91ea733f04..1b28aa00bf 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -119,6 +119,17 @@ static void print_reg(int regnum, const uint32_t *regs, int index) panic_puts((regnum & 3) == 3 ? "\n" : " "); } +/* + * Returns non-zero if the exception frame was created on the main stack, or + * zero if it's on the process stack. + * + * See B1.5.8 "Exception return behavior" of ARM DDI 0403D for details. + */ +static int is_exception_in_handler_context(const uint32_t exc_return) +{ + return (exc_return & 0xf) == 1 || (exc_return & 0xf) == 9; +} + #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] = { @@ -226,7 +237,51 @@ static void show_fault(uint32_t mmfs, uint32_t hfsr, uint32_t dfsr) } } -/** +/* + * Returns the size of the exception frame. + * + * See B1.5.7 "Stack alignment on exception entry" of ARM DDI 0403D for details. + * In short, the exception frame size can be either 0x20, 0x24, 0x68, or 0x6c + * depending on FPU context and padding for 8-byte alignment. + */ +static uint32_t get_exception_frame_size(const struct panic_data *pdata) +{ + uint32_t frame_size = 0; + + /* base exception frame */ + frame_size += 8 * sizeof(uint32_t); + + /* CPU uses xPSR[9] to indicate whether it padded the stack for + * alignment or not. */ + if (pdata->frame[7] & (1 << 9)) + frame_size += sizeof(uint32_t); + +#ifdef CONFIG_FPU + /* CPU uses EXC_RETURN[4] to indicate whether it stored extended + * frame for FPU or not. */ + if (!(pdata->regs[2] & (1 << 4))) + frame_size += 18 * sizeof(uint32_t); +#endif + + return frame_size; +} + +/* + * Returns the position of the process stack before the exception frame. + * It computes the size of the exception frame and adds it to psp. + * If the exception happened in the exception context, it returns psp as is. + */ +static uint32_t get_process_stack_position(const struct panic_data *pdata) +{ + uint32_t psp = pdata->regs[0]; + + if (!is_exception_in_handler_context(pdata->regs[2])) + psp += get_exception_frame_size(pdata); + + return psp; +} + +/* * Show extra information that might be useful to understand a panic() * * We show fault register information, including the fault address registers @@ -243,6 +298,30 @@ static void panic_show_extra(const struct panic_data *pdata) panic_printf("shcsr = %x, ", pdata->shcsr); panic_printf("hfsr = %x, ", pdata->hfsr); panic_printf("dfsr = %x\n", pdata->dfsr); + panic_printf("exc_return = %x\n", pdata->regs[2]); +} + +/* + * Prints process stack contents stored above the exception frame. + */ +static void panic_show_process_stack(const struct panic_data *pdata) +{ + panic_printf("\n=========== Process Stack Contents ==========="); + if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) { + uint32_t psp = get_process_stack_position(pdata); + int i; + for (i = 0; i < 16; i++) { + if (psp + sizeof(uint32_t) > + CONFIG_RAM_BASE + CONFIG_RAM_SIZE) + break; + if (i % 4 == 0) + panic_printf("\n%08x:", psp); + panic_printf(" %08x", *(uint32_t *)psp); + psp += sizeof(uint32_t); + } + } else { + panic_printf("\nBad psp"); + } } #endif /* CONFIG_PANIC_HELP */ @@ -268,7 +347,7 @@ static void panic_print(const struct panic_data *pdata) sregs = pdata->frame; panic_printf("\n=== EXCEPTION: %02x ====== xPSR: %08x ===========\n", - lregs[1] & 7, sregs ? sregs[7] : -1); + lregs[1] & 0xff, sregs ? sregs[7] : -1); for (i = 0; i < 4; i++) print_reg(i, sregs, i); for (i = 4; i < 10; i++) @@ -298,11 +377,12 @@ void report_panic(void) pdata->reserved = 0; /* If stack is valid, save exception frame */ - if (psp >= CONFIG_RAM_BASE && - psp <= CONFIG_RAM_BASE + CONFIG_RAM_SIZE + 8 * sizeof(uint32_t)) { + if (!is_exception_in_handler_context(pdata->regs[2]) && + (psp & 3) == 0 && + psp >= CONFIG_RAM_BASE && + psp <= CONFIG_RAM_BASE + CONFIG_RAM_SIZE - 8 * sizeof(uint32_t)) { const uint32_t *sregs = (const uint32_t *)psp; int i; - for (i = 0; i < 8; i++) pdata->frame[i] = sregs[i]; pdata->flags |= PANIC_DATA_FLAG_FRAME_VALID; @@ -317,6 +397,11 @@ void report_panic(void) pdata->dfsr = CPU_NVIC_DFSR; panic_print(pdata); +#ifdef CONFIG_PANIC_HELP + panic_show_process_stack(pdata); + /* TODO: Dump main stack contents as well if the exception happened + * in a handler's context. */ +#endif panic_reboot(); } @@ -339,6 +424,9 @@ void exception_panic(void) * compute [pregs] below if the asm blocks are separate, but if * they are merged it uses two temporary registers and two * immediate values. + * + * TODO: Save sp somewhere so that we can access exception frame + * when exception happens in handler's context. */ "mov sp, %[pstack]\n" : : [pstack] "r" (pstack_addr) |