summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Nematbakhsh <shawnn@chromium.org>2015-02-13 15:29:33 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-02-18 04:53:51 +0000
commitd00847782480e492401ba3bc5a8a8e6f026b08ba (patch)
tree01c42b77ba518cf57e7512affcb833f0df61056f
parent9cb03971f6852fa03df3290e44a8451e01774755 (diff)
downloadchrome-ec-d00847782480e492401ba3bc5a8a8e6f026b08ba.tar.gz
cortex-m*: Save panicinfo on non-exception panics
Make non-exception "software" panics such as stack overflow and assert failure save a panic log. Log the panic type in r4, and misc. panic data in r5 so that panic reasons can be distinguished. BUG=chrome-os-partner:36744 TEST=Manual on samus_pd. Run 'crash divzero' then 'panicinfo' after reboot. Verify that panic info is printed with "r4 :dead6660". Trigger stack overflow, verify that panic info is printed with "r4 :dead6661". BRANCH=Samus Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> Change-Id: I5f7a8eb0a5c2ac5799d29bb241deb24fabf38f68 Reviewed-on: https://chromium-review.googlesource.com/249912 Tested-by: Alec Berg <alecaberg@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org>
-rw-r--r--common/panic_output.c66
-rw-r--r--core/cortex-m/config_core.h2
-rw-r--r--core/cortex-m/panic.c22
-rw-r--r--core/cortex-m/task.c35
-rw-r--r--core/cortex-m/uldivmod.S4
-rw-r--r--core/cortex-m0/config_core.h1
-rw-r--r--core/cortex-m0/div.S4
-rw-r--r--core/cortex-m0/panic.c22
-rw-r--r--core/cortex-m0/task.c35
-rw-r--r--core/cortex-m0/uldivmod.S4
-rw-r--r--include/config.h6
-rw-r--r--include/panic.h16
-rw-r--r--include/software_panic.h23
13 files changed, 163 insertions, 77 deletions
diff --git a/common/panic_output.c b/common/panic_output.c
index 4f0f22d00d..af98c5953d 100644
--- a/common/panic_output.c
+++ b/common/panic_output.c
@@ -6,6 +6,7 @@
#include "common.h"
#include "console.h"
#include "cpu.h"
+#include "hooks.h"
#include "host_command.h"
#include "panic.h"
#include "printf.h"
@@ -82,8 +83,11 @@ void panic_reboot(void)
void panic_assert_fail(const char *fname, int linenum)
{
panic_printf("\nASSERTION FAILURE at %s:%d\n", fname, linenum);
-
+#ifdef CONFIG_SOFTWARE_PANIC
+ software_panic(PANIC_SW_ASSERT, linenum);
+#else
panic_reboot();
+#endif
}
#else
void panic_assert_fail(const char *msg, const char *func, const char *fname,
@@ -91,8 +95,11 @@ 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);
+#else
panic_reboot();
+#endif
}
#endif
#endif
@@ -108,6 +115,37 @@ struct panic_data *panic_get_data(void)
return pdata_ptr->magic == PANIC_DATA_MAGIC ? pdata_ptr : NULL;
}
+#ifdef CONFIG_SOFTWARE_PANIC
+static void panic_init(void)
+{
+ /* Log panic cause if watchdog caused reset */
+ if (system_get_reset_flags() & RESET_FLAG_WATCHDOG)
+ panic_log_watchdog();
+}
+DECLARE_HOOK(HOOK_INIT, panic_init, HOOK_PRIO_DEFAULT);
+#endif
+
+#ifdef CONFIG_CMD_STACKOVERFLOW
+static void stack_overflow_recurse(int n)
+{
+ ccprintf("+%d", n);
+
+ /*
+ * Force task context switch, since that's where we do stack overflow
+ * checking.
+ */
+ msleep(10);
+
+ stack_overflow_recurse(n+1);
+
+ /*
+ * Do work after the recursion, or else the compiler uses tail-chaining
+ * and we don't actually consume additional stack.
+ */
+ ccprintf("-%d", n);
+}
+#endif /* CONFIG_CMD_STACKOVERFLOW */
+
/*****************************************************************************/
/* Console commands */
@@ -116,14 +154,26 @@ 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;
+ if (!strcasecmp(argv[1], "assert")) {
+ ASSERT(0);
+ } else if (!strcasecmp(argv[1], "divzero")) {
+ int zero = 0;
cflush();
- ccprintf("%08x", a / b);
+ if (argc >= 3 && !strcasecmp(argv[2], "unsigned"))
+ ccprintf("%08x", (unsigned long)1 / zero);
+ else
+ ccprintf("%08x", (long)1 / zero);
+#ifdef CONFIG_CMD_STACKOVERFLOW
+ } else if (!strcasecmp(argv[1], "stack")) {
+ stack_overflow_recurse(1);
+#endif
} else if (!strcasecmp(argv[1], "unaligned")) {
cflush();
ccprintf("%08x", *(int *)0xcdef);
+ } else if (!strcasecmp(argv[1], "watchdog")) {
+ while (1)
+ ;
} else {
return EC_ERROR_PARAM1;
}
@@ -132,9 +182,9 @@ static int command_crash(int argc, char **argv)
return EC_ERROR_UNKNOWN;
}
DECLARE_CONSOLE_COMMAND(crash, command_crash,
- "[divzero | unaligned]",
- "Crash the system (for testing)",
- NULL);
+ "[assert | divzero | stack | unaligned | watchdog] [options]",
+ "Crash the system (for testing)",
+ NULL);
static int command_panicinfo(int argc, char **argv)
{
diff --git a/core/cortex-m/config_core.h b/core/cortex-m/config_core.h
index 7f3d253427..e72f4e58bb 100644
--- a/core/cortex-m/config_core.h
+++ b/core/cortex-m/config_core.h
@@ -10,4 +10,6 @@
#define BFD_ARCH arm
#define BFD_FORMAT "elf32-littlearm"
+#define CONFIG_SOFTWARE_PANIC
+
#endif /* __CONFIG_CORE_H */
diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c
index d63a5e3d9a..64fd5b8db1 100644
--- a/core/cortex-m/panic.c
+++ b/core/cortex-m/panic.c
@@ -373,6 +373,28 @@ void exception_panic(void)
);
}
+void software_panic(uint32_t panic_reason, uint32_t panic_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));
+}
+
+void panic_log_watchdog(void)
+{
+ uint32_t *lregs = pdata_ptr->cm.regs;
+
+ /* Watchdog reset, log panic cause */
+ 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;
+}
+
void bus_fault_handler(void)
{
if (!bus_fault_ignored)
diff --git a/core/cortex-m/task.c b/core/cortex-m/task.c
index 69e93457cb..f7fda67374 100644
--- a/core/cortex-m/task.c
+++ b/core/cortex-m/task.c
@@ -10,6 +10,7 @@
#include "console.h"
#include "cpu.h"
#include "link_defs.h"
+#include "panic.h"
#include "task.h"
#include "timer.h"
#include "uart.h"
@@ -225,7 +226,7 @@ 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]);
- panic_reboot();
+ software_panic(PANIC_SW_STACK_OVERFLOW, current - tasks);
}
#endif
@@ -590,38 +591,6 @@ DECLARE_CONSOLE_COMMAND(taskready, command_task_ready,
NULL);
#endif
-#ifdef CONFIG_CMD_STACKOVERFLOW
-static void stack_overflow_recurse(int n)
-{
- ccprintf("+%d", n);
-
- /*
- * Force task context switch, since that's where we do stack overflow
- * checking.
- */
- msleep(10);
-
- stack_overflow_recurse(n+1);
-
- /*
- * Do work after the recursion, or else the compiler uses tail-chaining
- * and we don't actually consume additional stack.
- */
- ccprintf("-%d", n);
-}
-
-static int command_stackoverflow(int argc, char **argv)
-{
- ccprintf("Recursing 0,");
- stack_overflow_recurse(1);
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(stackoverflow, command_stackoverflow,
- NULL,
- "Recurse until stack overflow",
- NULL);
-#endif /* CONFIG_CMD_STACKOVERFLOW */
-
void task_pre_init(void)
{
uint32_t *stack_next = (uint32_t *)task_stacks;
diff --git a/core/cortex-m/uldivmod.S b/core/cortex-m/uldivmod.S
index a14bdb203f..256023e9cc 100644
--- a/core/cortex-m/uldivmod.S
+++ b/core/cortex-m/uldivmod.S
@@ -16,6 +16,7 @@
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "software_panic.h"
.syntax unified
@@ -174,4 +175,5 @@ L_dont_sub4:
pop {r4, r5, r6, r7, pc}
__aeabi_ldiv0:
- bl panic_reboot
+ ldr SOFTWARE_PANIC_REASON_REG, =PANIC_SW_DIV_ZERO
+ bl exception_panic
diff --git a/core/cortex-m0/config_core.h b/core/cortex-m0/config_core.h
index 11c209c66a..9c04d467e3 100644
--- a/core/cortex-m0/config_core.h
+++ b/core/cortex-m0/config_core.h
@@ -12,5 +12,6 @@
/* Emulate the CLZ instruction since the CPU core is lacking support */
#define CONFIG_SOFTWARE_CLZ
+#define CONFIG_SOFTWARE_PANIC
#endif /* __CONFIG_CORE_H */
diff --git a/core/cortex-m0/div.S b/core/cortex-m0/div.S
index 833465a59e..898ecafe83 100644
--- a/core/cortex-m0/div.S
+++ b/core/cortex-m0/div.S
@@ -18,6 +18,7 @@
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "software_panic.h"
.syntax unified
@@ -161,4 +162,5 @@ L_dont_sub0:
bx lr
__aeabi_idiv0:
- bl panic_reboot
+ ldr SOFTWARE_PANIC_REASON_REG, =PANIC_SW_DIV_ZERO
+ bl exception_panic
diff --git a/core/cortex-m0/panic.c b/core/cortex-m0/panic.c
index 7857fb55dd..2b17a1bd73 100644
--- a/core/cortex-m0/panic.c
+++ b/core/cortex-m0/panic.c
@@ -166,6 +166,28 @@ void exception_panic(void)
);
}
+void software_panic(uint32_t panic_reason, uint32_t panic_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));
+}
+
+void panic_log_watchdog(void)
+{
+ uint32_t *lregs = pdata_ptr->cm.regs;
+
+ /* Watchdog reset, log panic cause */
+ 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;
+}
+
void bus_fault_handler(void)
{
if (!bus_fault_ignored)
diff --git a/core/cortex-m0/task.c b/core/cortex-m0/task.c
index e51621b41e..86fb7071d5 100644
--- a/core/cortex-m0/task.c
+++ b/core/cortex-m0/task.c
@@ -10,6 +10,7 @@
#include "console.h"
#include "cpu.h"
#include "link_defs.h"
+#include "panic.h"
#include "task.h"
#include "timer.h"
#include "uart.h"
@@ -209,7 +210,7 @@ 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]);
- panic_reboot();
+ software_panic(PANIC_SW_STACK_OVERFLOW, current - tasks);
}
#endif
@@ -574,38 +575,6 @@ DECLARE_CONSOLE_COMMAND(taskready, command_task_ready,
NULL);
#endif
-#ifdef CONFIG_CMD_STACKOVERFLOW
-static void stack_overflow_recurse(int n)
-{
- ccprintf("+%d", n);
-
- /*
- * Force task context switch, since that's where we do stack overflow
- * checking.
- */
- msleep(10);
-
- stack_overflow_recurse(n+1);
-
- /*
- * Do work after the recursion, or else the compiler uses tail-chaining
- * and we don't actually consume additional stack.
- */
- ccprintf("-%d", n);
-}
-
-static int command_stackoverflow(int argc, char **argv)
-{
- ccprintf("Recursing 0,");
- stack_overflow_recurse(1);
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(stackoverflow, command_stackoverflow,
- NULL,
- "Recurse until stack overflow",
- NULL);
-#endif /* CONFIG_CMD_STACKOVERFLOW */
-
void task_pre_init(void)
{
uint32_t *stack_next = (uint32_t *)task_stacks;
diff --git a/core/cortex-m0/uldivmod.S b/core/cortex-m0/uldivmod.S
index b8855023ad..6909c6f242 100644
--- a/core/cortex-m0/uldivmod.S
+++ b/core/cortex-m0/uldivmod.S
@@ -16,6 +16,7 @@
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "software_panic.h"
.syntax unified
@@ -172,4 +173,5 @@ L_dont_sub4:
pop {r4, r5, r6, r7, pc}
__aeabi_ldiv0:
- bl panic_reboot
+ ldr SOFTWARE_PANIC_REASON_REG, =DIV_ZERO_PANIC
+ bl exception_panic
diff --git a/include/config.h b/include/config.h
index 9fb9508644..5f30ba31f3 100644
--- a/include/config.h
+++ b/include/config.h
@@ -379,6 +379,12 @@
#define CONFIG_COMMON_PANIC_OUTPUT
/*
+ * Store a panic log and halt the system for a software-related reasons, such as
+ * stack overflow or assertion failure.
+ */
+#undef CONFIG_SOFTWARE_PANIC
+
+/*
* Provide the default GPIO abstraction layer.
* You want this unless you are doing a really tiny firmware.
*/
diff --git a/include/panic.h b/include/panic.h
index 74376554b6..1097029002 100644
--- a/include/panic.h
+++ b/include/panic.h
@@ -9,6 +9,8 @@
#ifndef __CROS_EC_PANIC_H
#define __CROS_EC_PANIC_H
+#include "software_panic.h"
+
#include <stdarg.h>
/* ARM Cortex-Mx registers saved on panic */
@@ -120,6 +122,20 @@ void panic(const char *msg);
*/
void panic_reboot(void);
+#ifdef CONFIG_SOFTWARE_PANIC
+/**
+ * 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);
+
+/**
+ * Log a watchdog panic in the panic log. Called on the subsequent reboot after
+ * the watchdog fires.
+ */
+void panic_log_watchdog(void);
+#endif
+
/**
* Enable/disable bus fault handler
*
diff --git a/include/software_panic.h b/include/software_panic.h
new file mode 100644
index 0000000000..9dc6d5a394
--- /dev/null
+++ b/include/software_panic.h
@@ -0,0 +1,23 @@
+/* Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Software panic constants. This file must be parsable by the assembler.
+ */
+
+#ifndef __CROS_EC_SOFTWARE_PANIC_H
+#define __CROS_EC_SOFTWARE_PANIC_H
+
+/* Holds software panic reason PANIC_SW_* */
+#define SOFTWARE_PANIC_REASON_REG r4
+#define SOFTWARE_PANIC_INFO_REG r5
+
+#define PANIC_SW_BASE 0xDEAD6660
+
+/* Software panic reasons */
+#define PANIC_SW_DIV_ZERO (PANIC_SW_BASE + 0)
+#define PANIC_SW_STACK_OVERFLOW (PANIC_SW_BASE + 1)
+#define PANIC_SW_ASSERT (PANIC_SW_BASE + 3)
+#define PANIC_SW_WATCHDOG (PANIC_SW_BASE + 4)
+
+#endif /* __CROS_EC_SOFTWARE_PANIC_H */