summaryrefslogtreecommitdiff
path: root/core/cortex-m0/panic.c
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2014-03-01 10:20:47 -0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-03-11 05:52:41 +0000
commit0f73a129b42acfcad843203b602fbbcc8894c614 (patch)
tree9531fae7a8d9c3290973fe5b5ee47e57cd485546 /core/cortex-m0/panic.c
parent7aab81edce830e15134b52256ad3186e08951b10 (diff)
downloadchrome-ec-0f73a129b42acfcad843203b602fbbcc8894c614.tar.gz
Add Cortex-M0 core support
The Cortex-M0 core is based on ARMv6-M instruction set rather than ARMv7-M as Cortex-M3 and M4. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=none TEST=run console on STM32F072, and pass all available unit-tests on target. Change-Id: I9bdf6637132ba4a3e739d388580a72b4c84e930e Reviewed-on: https://chromium-review.googlesource.com/188982 Reviewed-by: Vincent Palatin <vpalatin@chromium.org> Commit-Queue: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'core/cortex-m0/panic.c')
-rw-r--r--core/cortex-m0/panic.c178
1 files changed, 178 insertions, 0 deletions
diff --git a/core/cortex-m0/panic.c b/core/cortex-m0/panic.c
new file mode 100644
index 0000000000..7857fb55dd
--- /dev/null
+++ b/core/cortex-m0/panic.c
@@ -0,0 +1,178 @@
+/* Copyright (c) 2014 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.
+ */
+
+#include "common.h"
+#include "console.h"
+#include "cpu.h"
+#include "host_command.h"
+#include "panic.h"
+#include "printf.h"
+#include "system.h"
+#include "task.h"
+#include "timer.h"
+#include "uart.h"
+#include "util.h"
+#include "watchdog.h"
+
+/* Whether bus fault is ignored */
+static int bus_fault_ignored;
+
+
+/* Panic data goes at the end of RAM. */
+static struct panic_data * const pdata_ptr = PANIC_DATA_PTR;
+
+/* 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;
+
+/**
+ * Print the name and value of a register
+ *
+ * This is a convenient helper function for displaying a register value.
+ * It shows the register name in a 3 character field, followed by a colon.
+ * The register value is regs[index], and this is shown in hex. If regs is
+ * NULL, then we display spaces instead.
+ *
+ * After displaying the value, either a space or \n is displayed depending
+ * on the register number, so that (assuming the caller passes all 16
+ * registers in sequence) we put 4 values per line like this
+ *
+ * r0 :0000000b r1 :00000047 r2 :60000000 r3 :200012b5
+ * r4 :00000000 r5 :08004e64 r6 :08004e1c r7 :200012a8
+ * r8 :08004e64 r9 :00000002 r10:00000000 r11:00000000
+ * r12:0000003f sp :200009a0 lr :0800270d pc :0800351a
+ *
+ * @param regnum Register number to display (0-15)
+ * @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, const uint32_t *regs, int index)
+{
+ static const char regname[] = "r10r11r12sp lr pc ";
+ static char rname[3] = "r ";
+ const char *name;
+
+ rname[1] = '0' + regnum;
+ name = regnum < 10 ? rname : &regname[(regnum - 10) * 3];
+ panic_printf("%c%c%c:", name[0], name[1], name[2]);
+ if (regs)
+ panic_printf("%08x", regs[index]);
+ else
+ panic_puts(" ");
+ panic_puts((regnum & 3) == 3 ? "\n" : " ");
+}
+
+/*
+ * Returns non-zero if the exception frame was created on the main stack, or
+ * zero if it's on the process stack.
+ *
+ * See B1.5.8 "Exception return behavior" of ARM DDI 0403D for details.
+ */
+static int32_t is_frame_in_handler_stack(const uint32_t exc_return)
+{
+ return (exc_return & 0xf) == 1 || (exc_return & 0xf) == 9;
+}
+
+/*
+ * Print panic data
+ */
+void panic_data_print(const struct panic_data *pdata)
+{
+ const uint32_t *lregs = pdata->cm.regs;
+ const uint32_t *sregs = NULL;
+ const int32_t in_handler =
+ is_frame_in_handler_stack(pdata->cm.regs[11]);
+ int i;
+
+ if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID)
+ sregs = pdata->cm.frame;
+
+ panic_printf("\n=== %s EXCEPTION: %02x ====== xPSR: %08x ===\n",
+ in_handler ? "HANDLER" : "PROCESS",
+ lregs[1] & 0xff, 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, in_handler ? 2 : 0);
+ print_reg(14, sregs, 5);
+ print_reg(15, sregs, 6);
+}
+
+void report_panic(void)
+{
+ struct panic_data *pdata = pdata_ptr;
+ uint32_t sp;
+
+ pdata->magic = PANIC_DATA_MAGIC;
+ pdata->struct_size = sizeof(*pdata);
+ pdata->struct_version = 2;
+ pdata->arch = PANIC_ARCH_CORTEX_M;
+ pdata->flags = 0;
+ pdata->reserved = 0;
+
+ /* Choose the right sp (psp or msp) based on EXC_RETURN value */
+ sp = is_frame_in_handler_stack(pdata->cm.regs[11])
+ ? pdata->cm.regs[2] : pdata->cm.regs[0];
+ /* If stack is valid, copy exception frame to pdata */
+ if ((sp & 3) == 0 &&
+ sp >= CONFIG_RAM_BASE &&
+ sp <= CONFIG_RAM_BASE + CONFIG_RAM_SIZE - 8 * sizeof(uint32_t)) {
+ const uint32_t *sregs = (const uint32_t *)sp;
+ int i;
+ for (i = 0; i < 8; i++)
+ pdata->cm.frame[i] = sregs[i];
+ pdata->flags |= PANIC_DATA_FLAG_FRAME_VALID;
+ }
+
+ panic_data_print(pdata);
+ panic_reboot();
+}
+
+/**
+ * Default exception handler, which reports a panic.
+ *
+ * Declare this as a naked call so we can extract raw LR and IPSR values.
+ */
+void exception_panic(void) __attribute__((naked));
+void exception_panic(void)
+{
+ /* Save registers and branch directly to panic handler */
+ asm volatile(
+ "mov r0, %[pregs]\n"
+ "mrs r1, psp\n"
+ "mrs r2, ipsr\n"
+ "mov r3, sp\n"
+ "stmia r0!, {r1-r7}\n"
+ "mov r1, r8\n"
+ "mov r2, r9\n"
+ "mov r3, r10\n"
+ "mov r4, r11\n"
+ "mov r5, lr\n"
+ "stmia r0!, {r1-r5}\n"
+ "mov sp, %[pstack]\n"
+ "b report_panic\n" : :
+ [pregs] "r" (pdata_ptr->cm.regs),
+ [pstack] "r" (pstack_addr) :
+ /* Constraints protecting these from being clobbered.
+ * Gcc should be using r0 & r12 for pregs and pstack. */
+ "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
+ "r10", "r11", "cc", "memory"
+ );
+}
+
+void bus_fault_handler(void)
+{
+ if (!bus_fault_ignored)
+ exception_panic();
+}
+
+void ignore_bus_fault(int ignored)
+{
+ bus_fault_ignored = ignored;
+}