summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Nematbakhsh <shawnn@chromium.org>2015-03-04 10:35:25 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-03-14 03:22:37 +0000
commit90ef8b700629381ac62aae4f87612ef84b32cb35 (patch)
treef708bd83c0ac30b46f2bf3a5d79991cb4d80c64d
parent911da8c150d9d38b9a9f14453098bd1e0f838b49 (diff)
downloadchrome-ec-90ef8b700629381ac62aae4f87612ef84b32cb35.tar.gz
lm4: stm32: Store panic data in backup registers on hard reset
On hard reset / hibernate, RAM will be erased and panic data will normally be lost. When software panic data saving is enabled, try to save this data just before hard reset and restore it when we come back up. BUG=chrome-os-partner:37380 TEST=Manual on Samus with WP + SW sync enabled. Boot AP, then run "crash divzero" on console. After hard reset, verify that "panicinfo" dumps data and shows divzero exception code. BRANCH=Samus Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> Change-Id: I9516dd4b6db12ef35e512cc4710f9b97d7e663cb Reviewed-on: https://chromium-review.googlesource.com/255912 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--chip/lm4/system.c40
-rw-r--r--chip/stm32/system.c39
-rw-r--r--common/system.c2
-rw-r--r--core/cortex-m/panic.c29
-rw-r--r--core/cortex-m/task.c2
-rw-r--r--core/cortex-m0/panic.c29
-rw-r--r--core/cortex-m0/task.c2
-rw-r--r--include/panic.h13
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
/**