diff options
-rw-r--r-- | chip/lm4/system.c | 40 | ||||
-rw-r--r-- | chip/stm32/system.c | 39 | ||||
-rw-r--r-- | common/system.c | 2 | ||||
-rw-r--r-- | core/cortex-m/panic.c | 29 | ||||
-rw-r--r-- | core/cortex-m/task.c | 2 | ||||
-rw-r--r-- | core/cortex-m0/panic.c | 29 | ||||
-rw-r--r-- | core/cortex-m0/task.c | 2 | ||||
-rw-r--r-- | include/panic.h | 13 |
8 files changed, 136 insertions, 20 deletions
diff --git a/chip/lm4/system.c b/chip/lm4/system.c index 78db1b38a3..38cde27e1c 100644 --- a/chip/lm4/system.c +++ b/chip/lm4/system.c @@ -10,6 +10,7 @@ #include "console.h" #include "cpu.h" #include "host_command.h" +#include "panic.h" #include "registers.h" #include "system.h" #include "task.h" @@ -18,9 +19,14 @@ /* Indices for hibernate data registers */ enum hibdata_index { - HIBDATA_INDEX_SCRATCHPAD, /* General-purpose scratchpad */ - HIBDATA_INDEX_WAKE, /* Wake reasons for hibernate */ - HIBDATA_INDEX_SAVED_RESET_FLAGS /* Saved reset flags */ + HIBDATA_INDEX_SCRATCHPAD, /* General-purpose scratchpad */ + HIBDATA_INDEX_WAKE, /* Wake reasons for hibernate */ + HIBDATA_INDEX_SAVED_RESET_FLAGS, /* Saved reset flags */ +#ifdef CONFIG_SOFTWARE_PANIC + HIBDATA_INDEX_SAVED_PANIC_REASON, /* Saved panic reason */ + HIBDATA_INDEX_SAVED_PANIC_INFO, /* Saved panic data */ + HIBDATA_INDEX_SAVED_PANIC_EXCEPTION /* Saved panic exception code */ +#endif }; /* Flags for HIBDATA_INDEX_WAKE */ @@ -385,6 +391,10 @@ void system_hibernate(uint32_t seconds, uint32_t microseconds) void system_pre_init(void) { uint32_t hibctl; +#ifdef CONFIG_SOFTWARE_PANIC + uint32_t reason, info; + uint8_t exception; +#endif /* * Enable clocks to the hibernation module in run, sleep, @@ -441,6 +451,19 @@ void system_pre_init(void) check_reset_cause(); +#ifdef CONFIG_SOFTWARE_PANIC + /* Restore then clear saved panic reason */ + reason = hibdata_read(HIBDATA_INDEX_SAVED_PANIC_REASON); + info = hibdata_read(HIBDATA_INDEX_SAVED_PANIC_INFO); + exception = hibdata_read(HIBDATA_INDEX_SAVED_PANIC_EXCEPTION); + if (reason || info || exception) { + panic_set_reason(reason, info, exception); + hibdata_write(HIBDATA_INDEX_SAVED_PANIC_REASON, 0); + hibdata_write(HIBDATA_INDEX_SAVED_PANIC_INFO, 0); + hibdata_write(HIBDATA_INDEX_SAVED_PANIC_EXCEPTION, 0); + } +#endif + /* Initialize bootcfg if needed */ if (LM4_SYSTEM_BOOTCFG != CONFIG_BOOTCFG_VALUE) { /* read-modify-write */ @@ -473,6 +496,17 @@ void system_reset(int flags) hibdata_write(HIBDATA_INDEX_SAVED_RESET_FLAGS, save_flags); if (flags & SYSTEM_RESET_HARD) { +#ifdef CONFIG_SOFTWARE_PANIC + uint32_t reason, info; + uint8_t exception; + + /* Panic data will be wiped by hard reset, so save it */ + panic_get_reason(&reason, &info, &exception); + hibdata_write(HIBDATA_INDEX_SAVED_PANIC_REASON, reason); + hibdata_write(HIBDATA_INDEX_SAVED_PANIC_INFO, info); + hibdata_write(HIBDATA_INDEX_SAVED_PANIC_EXCEPTION, exception); +#endif + /* * Bounce through hibernate to trigger a hard reboot. Do * not wake on wake pin, since we need the full duration. diff --git a/chip/stm32/system.c b/chip/stm32/system.c index 890c704924..0030e1a305 100644 --- a/chip/stm32/system.c +++ b/chip/stm32/system.c @@ -10,6 +10,7 @@ #include "cpu.h" #include "flash.h" #include "registers.h" +#include "panic.h" #include "system.h" #include "task.h" #include "util.h" @@ -19,8 +20,8 @@ #define CONSOLE_BIT_MASK 0x8000 enum bkpdata_index { - BKPDATA_INDEX_SCRATCHPAD, /* General-purpose scratchpad */ - BKPDATA_INDEX_SAVED_RESET_FLAGS,/* Saved reset flags */ + BKPDATA_INDEX_SCRATCHPAD, /* General-purpose scratchpad */ + BKPDATA_INDEX_SAVED_RESET_FLAGS, /* Saved reset flags */ BKPDATA_INDEX_VBNV_CONTEXT0, BKPDATA_INDEX_VBNV_CONTEXT1, BKPDATA_INDEX_VBNV_CONTEXT2, @@ -29,6 +30,11 @@ enum bkpdata_index { BKPDATA_INDEX_VBNV_CONTEXT5, BKPDATA_INDEX_VBNV_CONTEXT6, BKPDATA_INDEX_VBNV_CONTEXT7, +#ifdef CONFIG_SOFTWARE_PANIC + BKPDATA_INDEX_SAVED_PANIC_REASON, /* Saved panic reason */ + BKPDATA_INDEX_SAVED_PANIC_INFO, /* Saved panic data */ + BKPDATA_INDEX_SAVED_PANIC_EXCEPTION, /* Saved panic exception code */ +#endif }; /** @@ -162,6 +168,11 @@ static void check_reset_cause(void) void system_pre_init(void) { +#ifdef CONFIG_SOFTWARE_PANIC + uint16_t reason, info; + uint8_t exception; +#endif + /* enable clock on Power module */ STM32_RCC_APB1ENR |= 1 << 28; /* enable backup registers */ @@ -197,6 +208,19 @@ void system_pre_init(void) #endif check_reset_cause(); + +#ifdef CONFIG_SOFTWARE_PANIC + /* Restore then clear saved panic reason */ + reason = bkpdata_read(BKPDATA_INDEX_SAVED_PANIC_REASON); + info = bkpdata_read(BKPDATA_INDEX_SAVED_PANIC_INFO); + exception = bkpdata_read(BKPDATA_INDEX_SAVED_PANIC_EXCEPTION); + if (reason || info || exception) { + panic_set_reason(reason, info, exception); + bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_REASON, 0); + bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_INFO, 0); + bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_EXCEPTION, 0); + } +#endif } void system_reset(int flags) @@ -223,6 +247,17 @@ void system_reset(int flags) bkpdata_write(BKPDATA_INDEX_SAVED_RESET_FLAGS, save_flags | console_en); if (flags & SYSTEM_RESET_HARD) { +#ifdef CONFIG_SOFTWARE_PANIC + uint32_t reason, info; + uint8_t exception; + + /* Panic data will be wiped by hard reset, so save it */ + panic_get_reason(&reason, &info, &exception); + /* 16 bits stored - upper 16 bits of reason / info are lost */ + bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_REASON, reason); + bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_INFO, info); + bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_EXCEPTION, exception); +#endif #ifdef CHIP_FAMILY_STM32L /* diff --git a/common/system.c b/common/system.c index d57b1ce9ab..4bd70400d0 100644 --- a/common/system.c +++ b/common/system.c @@ -582,7 +582,7 @@ void system_common_pre_init(void) * because it might change panic pointer. */ if (system_get_reset_flags() & RESET_FLAG_WATCHDOG) - panic_log_watchdog(); + panic_set_reason(PANIC_SW_WATCHDOG, 0, 0); #endif /* diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c index 64fd5b8db1..6b81e8c484 100644 --- a/core/cortex-m/panic.c +++ b/core/cortex-m/panic.c @@ -373,28 +373,47 @@ void exception_panic(void) ); } -void software_panic(uint32_t panic_reason, uint32_t panic_info) +#ifdef CONFIG_SOFTWARE_PANIC +void software_panic(uint32_t reason, uint32_t info) { __asm__("mov " STRINGIFY(SOFTWARE_PANIC_INFO_REG) ", %0\n" "mov " STRINGIFY(SOFTWARE_PANIC_REASON_REG) ", %1\n" "bl exception_panic\n" - : : "r"(panic_info), "r"(panic_reason)); + : : "r"(info), "r"(reason)); } -void panic_log_watchdog(void) +void panic_set_reason(uint32_t reason, uint32_t info, uint8_t exception) { uint32_t *lregs = pdata_ptr->cm.regs; - /* Watchdog reset, log panic cause */ + /* Setup panic data structure */ memset(pdata_ptr, 0, sizeof(*pdata_ptr)); pdata_ptr->magic = PANIC_DATA_MAGIC; pdata_ptr->struct_size = sizeof(*pdata_ptr); pdata_ptr->struct_version = 2; pdata_ptr->arch = PANIC_ARCH_CORTEX_M; - lregs[3] = PANIC_SW_WATCHDOG; + /* Log panic cause */ + lregs[1] = exception; + lregs[3] = reason; + lregs[4] = info; } +void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception) +{ + uint32_t *lregs = pdata_ptr->cm.regs; + + if (pdata_ptr->magic == PANIC_DATA_MAGIC && + pdata_ptr->struct_version == 2) { + *exception = lregs[1]; + *reason = lregs[3]; + *info = lregs[4]; + } else { + *exception = *reason = *info = 0; + } +} +#endif + void bus_fault_handler(void) { if (!bus_fault_ignored) diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c index f7fda67374..69b92d5de8 100644 --- a/core/cortex-m/task.c +++ b/core/cortex-m/task.c @@ -226,7 +226,9 @@ void svc_handler(int desched, task_id_t resched) if (*current->stack != STACK_UNUSED_VALUE) { panic_printf("\n\nStack overflow in %s task!\n", task_names[current - tasks]); +#ifdef CONFIG_SOFTWARE_PANIC software_panic(PANIC_SW_STACK_OVERFLOW, current - tasks); +#endif } #endif diff --git a/core/cortex-m0/panic.c b/core/cortex-m0/panic.c index 2b17a1bd73..2ba22c6998 100644 --- a/core/cortex-m0/panic.c +++ b/core/cortex-m0/panic.c @@ -166,28 +166,47 @@ void exception_panic(void) ); } -void software_panic(uint32_t panic_reason, uint32_t panic_info) +#ifdef CONFIG_SOFTWARE_PANIC +void software_panic(uint32_t reason, uint32_t info) { __asm__("mov " STRINGIFY(SOFTWARE_PANIC_INFO_REG) ", %0\n" "mov " STRINGIFY(SOFTWARE_PANIC_REASON_REG) ", %1\n" "bl exception_panic\n" - : : "r"(panic_info), "r"(panic_reason)); + : : "r"(info), "r"(reason)); } -void panic_log_watchdog(void) +void panic_set_reason(uint32_t reason, uint32_t info, uint8_t exception) { uint32_t *lregs = pdata_ptr->cm.regs; - /* Watchdog reset, log panic cause */ + /* Setup panic data structure */ memset(pdata_ptr, 0, sizeof(*pdata_ptr)); pdata_ptr->magic = PANIC_DATA_MAGIC; pdata_ptr->struct_size = sizeof(*pdata_ptr); pdata_ptr->struct_version = 2; pdata_ptr->arch = PANIC_ARCH_CORTEX_M; - lregs[3] = PANIC_SW_WATCHDOG; + /* Log panic cause */ + lregs[1] = exception; + lregs[3] = reason; + lregs[4] = info; } +void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception) +{ + uint32_t *lregs = pdata_ptr->cm.regs; + + if (pdata_ptr->magic == PANIC_DATA_MAGIC && + pdata_ptr->struct_version == 2) { + *exception = lregs[1]; + *reason = lregs[3]; + *info = lregs[4]; + } else { + *exception = *reason = *info = 0; + } +} +#endif + void bus_fault_handler(void) { if (!bus_fault_ignored) diff --git a/core/cortex-m0/task.c b/core/cortex-m0/task.c index 86fb7071d5..ffdbe49595 100644 --- a/core/cortex-m0/task.c +++ b/core/cortex-m0/task.c @@ -210,7 +210,9 @@ task_ *__svc_handler(int desched, task_id_t resched) if (*current->stack != STACK_UNUSED_VALUE) { panic_printf("\n\nStack overflow in %s task!\n", task_names[current - tasks]); +#ifdef CONFIG_SOFTWARE_PANIC software_panic(PANIC_SW_STACK_OVERFLOW, current - tasks); +#endif } #endif diff --git a/include/panic.h b/include/panic.h index 122f0c317c..ea7a40f7b0 100644 --- a/include/panic.h +++ b/include/panic.h @@ -129,13 +129,18 @@ void panic_reboot(void); * Store a panic log and halt the system for a software-related reason, such as * stack overflow or assertion failure. */ -void software_panic(uint32_t panic_reason, uint32_t panic_info); +void software_panic(uint32_t reason, uint32_t info); /** - * Log a watchdog panic in the panic log. Called on the subsequent reboot after - * the watchdog fires. + * Log a panic in the panic log, but don't halt the system. Normally + * called on the subsequent reboot after panic detection. */ -void panic_log_watchdog(void); +void panic_set_reason(uint32_t reason, uint32_t info, uint8_t exception); + +/** + * Retrieve the currently stored panic reason + info. + */ +void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception); #endif /** |