diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-08-28 15:44:47 -0700 |
---|---|---|
committer | David Hendricks <dhendrix@chromium.org> | 2012-09-05 21:04:22 -0700 |
commit | d56c415a90685e6fb43f764cc48f4878422b0e99 (patch) | |
tree | 55cb5dc1c57ae8676dffc063fabe2bf68422f133 | |
parent | 81c9294188ca28c3ba1d5cac4133c9fd341e3bc9 (diff) | |
download | chrome-ec-d56c415a90685e6fb43f764cc48f4878422b0e99.tar.gz |
Place panic data and stack at end of RAM
This is in preparation for saving panic data across reboots for later
retrieval.
BUG=chrome-os-partner:7466
TEST='crash divzero' or 'crash unaligned'; should print dump and reboot
BRANCH=all
Change-Id: I997d160b00d03759eb9c69b53ab0f7a5ae144183
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/31951
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/32353
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Tested-by: David Hendricks <dhendrix@chromium.org>
-rw-r--r-- | core/cortex-m/panic.c | 209 | ||||
-rw-r--r-- | include/panic.h | 10 |
2 files changed, 154 insertions, 65 deletions
diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 26d537ce85..9324ef705b 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -6,6 +6,7 @@ #include <stdarg.h> #include "config.h" +#include "console.h" #include "cpu.h" #include "panic.h" #include "system.h" @@ -22,15 +23,49 @@ /* Whether bus fault is ignored */ static int bus_fault_ignored; -/* We save registers here for display by report_panic() */ -static struct save_area -{ -#ifdef CONFIG_PANIC_NEW_STACK - uint32_t stack[STACK_SIZE_WORDS]; -#endif - uint32_t saved_regs[11]; /* psp, ipsr, lr, r4-r11 */ -} save_area __attribute__((aligned(8))); +/* Data saved across reboots */ +struct panic_data { + uint8_t arch; /* Architecture (PANIC_ARCH_*) */ + uint8_t struct_version; /* Structure version (currently 1) */ + uint8_t flags; /* Flags (PANIC_DATA_FLAG_*) */ + uint8_t reserved; /* Reserved; set 0 */ + uint32_t regs[11]; /* psp, ipsr, lr, r4-r11 */ + uint32_t frame[8]; /* r0-r3, r12, lr, pc, xPSR */ + + uint32_t mmfs; + uint32_t bfar; + uint32_t mfar; + uint32_t shcsr; + uint32_t hfsr; + uint32_t dfsr; + + /* + * These fields go at the END of the struct so we can find it at the + * end of memory. + */ + uint32_t struct_size; /* Size of this struct */ + uint32_t magic; /* PANIC_SAVE_MAGIC if valid */ +}; + +#define PANIC_DATA_MAGIC 0x21636e50 /* "Pnc!" */ + +#define PANIC_ARCH_CORTEX_M 1 + +/* Flags for panic_data.flags */ +#define PANIC_DATA_FLAG_FRAME_VALID (1 << 0) /* panic_data.frame is valid */ + +/* + * Panic data goes at the end of RAM. This is safe because we don't context + * switch away from the panic handler before rebooting, and stacks and data + * start at the beginning of RAM. + */ +static struct panic_data * const pdata_ptr = + (struct panic_data *)(CONFIG_RAM_BASE + CONFIG_RAM_SIZE + - sizeof(struct panic_data)); +/* Preceded by stack, rounded down to nearest 64-bit-aligned boundary */ +static const uint32_t pstack_addr = (CONFIG_RAM_BASE + CONFIG_RAM_SIZE + - sizeof(struct panic_data)) & ~7; void panic_putc(int ch) { @@ -136,7 +171,7 @@ void panic_printf(const char *format, ...) * @param regs Pointer to array holding the registers, or NULL * @param index Index into array where the register value is present */ -static void print_reg(int regnum, uint32_t *regs, int index) +static void print_reg(int regnum, const uint32_t *regs, int index) { static const char regname[] = "r10r11r12sp lr pc "; static char rname[3] = "r "; @@ -269,21 +304,18 @@ static void show_fault(uint32_t mmfs, uint32_t hfsr, uint32_t dfsr) * We show fault register information, including the fault address registers * if valid. */ -static void panic_show_extra(void) +static void panic_show_extra(const struct panic_data *pdata) { - 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); + show_fault(pdata->mmfs, pdata->hfsr, pdata->dfsr); + if (pdata->mmfs & CPU_NVIC_MMFS_BFARVALID) + panic_printf(", bfar = %x", pdata->bfar); + if (pdata->mmfs & CPU_NVIC_MMFS_MFARVALID) + panic_printf(", mfar = %x", pdata->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); + panic_printf("mmfs = %x, ", pdata->mmfs); + panic_printf("shcsr = %x, ", pdata->shcsr); + panic_printf("hfsr = %x, ", pdata->hfsr); + panic_printf("dfsr = %x", pdata->dfsr); } #endif /* CONFIG_PANIC_HELP */ @@ -297,37 +329,67 @@ static void panic_reboot(void) system_reset(0); } - -void report_panic(const char *msg, uint32_t *lregs) +/** + * Print panic data + */ +static void panic_print(const struct panic_data *pdata) { - if (msg) { - panic_printf("\n** PANIC: %s\n", msg); - } else if (lregs) { - uint32_t *sregs = NULL; - uint32_t psp; - int i; + const uint32_t *lregs = pdata->regs; + const uint32_t *sregs = NULL; + int i; + + if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) + sregs = pdata->frame; + + panic_printf("\n=== EXCEPTION: %2x ====== xPSR: %8x ===========\n", + lregs[1] & 7, sregs ? sregs[7] : -1); + for (i = 0; i < 4; i++) + print_reg(i, sregs, i); + for (i = 4; i < 10; i++) + print_reg(i, lregs, i - 1); + print_reg(10, lregs, 9); + print_reg(11, lregs, 10); + print_reg(12, sregs, 4); + print_reg(13, lregs, 0); + print_reg(14, sregs, 5); + print_reg(15, sregs, 6); - psp = lregs[0]; - if (psp >= CONFIG_RAM_BASE - && psp < CONFIG_RAM_BASE + CONFIG_RAM_SIZE) - sregs = (uint32_t *)psp; - panic_printf("\n=== EXCEPTION: %2x ====== xPSR: %8x " - "===========\n", lregs[1] & 7, sregs ? sregs[7] : -1); - for (i = 0; i < 4; i++) - print_reg(i, sregs, i); - for (i = 4; i < 10; i++) - print_reg(i, lregs, i - 1); - print_reg(10, lregs, 9); - print_reg(11, lregs, 10); - print_reg(12, sregs, 4); - print_reg(13, &psp, 0); - print_reg(14, sregs, 5); - print_reg(15, sregs, 6); #ifdef CONFIG_PANIC_HELP - panic_show_extra(); + panic_show_extra(pdata); #endif +} + +void report_panic(void) +{ + struct panic_data *pdata = pdata_ptr; + const uint32_t psp = pdata->regs[0]; + + pdata->magic = PANIC_DATA_MAGIC; + pdata->struct_size = sizeof(*pdata); + pdata->struct_version = 1; + pdata->arch = PANIC_ARCH_CORTEX_M; + pdata->flags = 0; + + /* If stack is valid, save exception frame */ + if (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; } + /* Save extra information */ + pdata->mmfs = CPU_NVIC_MMFS; + pdata->bfar = CPU_NVIC_BFAR; + pdata->mfar = CPU_NVIC_MFAR; + pdata->shcsr = CPU_NVIC_SHCSR; + pdata->hfsr = CPU_NVIC_HFSR; + pdata->dfsr = CPU_NVIC_DFSR; + + panic_print(pdata); panic_reboot(); } @@ -336,6 +398,18 @@ void exception_panic(void) __attribute__((naked)); void exception_panic(void) { /* Naked call so we can extract raw LR and IPSR */ + +#ifdef CONFIG_PANIC_NEW_STACK + asm volatile( + /* + * This instruction will generate ldr rx, [pc, #offset] + * followed by a mov sp, rx. See below for more explanation. + */ + "mov sp, %[pstack]\n" : : + [pstack] "r" (pstack_addr) + ); +#endif + asm volatile( /* * This instruction will generate ldr rx, [pc, #offset] @@ -348,18 +422,13 @@ void exception_panic(void) * If you see a failure in the panic handler, please check * the final assembler output here. */ - "mov r0, %[save_area]\n" + "mov r0, %[pregs]\n" "mrs r1, psp\n" "mrs r2, ipsr\n" "mov r3, lr\n" "stmia r0, {r1-r11}\n" -#ifdef CONFIG_PANIC_NEW_STACK - "mov sp, r0\n" -#endif - "mov r1, r0\n" - "mov r0, #0\n" "b report_panic" : : - [save_area] "r" (save_area.saved_regs) + [pregs] "r" (pdata_ptr->regs) ); } @@ -392,5 +461,35 @@ void panic_assert_fail(const char *msg, const char *func, const char *fname, void panic(const char *msg) { - report_panic(msg, NULL); + panic_printf("\n** PANIC: %s\n", msg); + panic_reboot(); +} + + +/*****************************************************************************/ +/* Console commands */ + +static int command_crash(int argc, char **argv) +{ + if (argc < 2) + return EC_ERROR_PARAM1; + + if (!strcasecmp(argv[1], "divzero")) { + int a = 1, b = 0; + + cflush(); + ccprintf("%08x", a / b); + } else if (!strcasecmp(argv[1], "unaligned")) { + cflush(); + ccprintf("%08x", *(int *)0xcdef); + } else { + return EC_ERROR_PARAM1; + } + + /* Everything crashes, so shouldn't get back here */ + return EC_ERROR_UNKNOWN; } +DECLARE_CONSOLE_COMMAND(crash, command_crash, + "[divzero | unaligned]", + "Crash the system (for testing)", + NULL); diff --git a/include/panic.h b/include/panic.h index d22a0e11be..ecf6eb0232 100644 --- a/include/panic.h +++ b/include/panic.h @@ -76,16 +76,6 @@ void panic_assert_fail(const char *msg, const char *func, const char *fname, void panic(const char *msg); /** - * Report a panic to the panic reporting device - * - * This is exported only to permit use from assembler. - * - * @param msg Panic message - * @param lregs Registers from the exception: psp, ipsr, lr, r4-r11 - */ -void report_panic(const char *msg, uint32_t *lregs); - -/** * Enable/disable bus fault handler * * @param ignored Non-zero if ignoring bus fault |