mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-28 02:35:28 +00:00
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>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
9cb03971f6
commit
d008477824
@@ -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)
|
||||
{
|
||||
|
||||
@@ -10,4 +10,6 @@
|
||||
#define BFD_ARCH arm
|
||||
#define BFD_FORMAT "elf32-littlearm"
|
||||
|
||||
#define CONFIG_SOFTWARE_PANIC
|
||||
|
||||
#endif /* __CONFIG_CORE_H */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -378,6 +378,12 @@
|
||||
/* Provide common core code to output panic information without interrupts. */
|
||||
#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.
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
23
include/software_panic.h
Normal file
23
include/software_panic.h
Normal file
@@ -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 */
|
||||
Reference in New Issue
Block a user