summaryrefslogtreecommitdiff
path: root/core/cortex-m/panic.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/cortex-m/panic.c')
-rw-r--r--core/cortex-m/panic.c172
1 files changed, 120 insertions, 52 deletions
diff --git a/core/cortex-m/panic.c b/core/cortex-m/panic.c
index 7daedbf7ab..c4954ec000 100644
--- a/core/cortex-m/panic.c
+++ b/core/cortex-m/panic.c
@@ -77,44 +77,28 @@ static int32_t is_frame_in_handler_stack(const uint32_t exc_return)
}
#ifdef CONFIG_DEBUG_EXCEPTIONS
-/* Names for each of the bits in the mmfs register, starting at bit 0 */
-static const char * const mmfs_name[32] = {
- "Instruction access violation",
- "Data access violation",
- NULL,
- "Unstack from exception violation",
- "Stack from exception violation",
- NULL,
- NULL,
- NULL,
-
- "Instruction bus error",
- "Precise data bus error",
- "Imprecise data bus error",
- "Unstack from exception bus fault",
- "Stack from exception bus fault",
- NULL,
- NULL,
- NULL,
-
- "Undefined instructions",
- "Invalid state",
- "Invalid PC",
- "No coprocessor",
- NULL,
- NULL,
- NULL,
- NULL,
-
- "Unaligned",
- "Divide by 0",
- NULL,
- NULL,
-
- NULL,
- NULL,
- NULL,
- NULL,
+/* Names for each of the bits in the cfs register, starting at bit 0 */
+static const char * const cfsr_name[32] = {
+ /* MMFSR */
+ [0] = "Instruction access violation",
+ [1] = "Data access violation",
+ [3] = "Unstack from exception violation",
+ [4] = "Stack from exception violation",
+
+ /* BFSR */
+ [8] = "Instruction bus error",
+ [9] = "Precise data bus error",
+ [10] = "Imprecise data bus error",
+ [11] = "Unstack from exception bus fault",
+ [12] = "Stack from exception bus fault",
+
+ /* UFSR */
+ [16] = "Undefined instructions",
+ [17] = "Invalid state",
+ [18] = "Invalid PC",
+ [19] = "No coprocessor",
+ [24] = "Unaligned",
+ [25] = "Divide by 0",
};
/* Names for the first 5 bits in the DFSR */
@@ -146,19 +130,19 @@ static void do_separate(int *count)
*
* A list of detected faults is shown, with no trailing newline.
*
- * @param mmfs Value of Memory Manage Fault Status
+ * @param cfsr Value of Configurable Fault Status
* @param hfsr Value of Hard Fault Status
* @param dfsr Value of Debug Fault Status
*/
-static void show_fault(uint32_t mmfs, uint32_t hfsr, uint32_t dfsr)
+static void show_fault(uint32_t cfsr, uint32_t hfsr, uint32_t dfsr)
{
unsigned int upto;
int count = 0;
for (upto = 0; upto < 32; upto++) {
- if ((mmfs & (1 << upto)) && mmfs_name[upto]) {
+ if ((cfsr & (1 << upto)) && cfsr_name[upto]) {
do_separate(&count);
- panic_puts(mmfs_name[upto]);
+ panic_puts(cfsr_name[upto]);
}
}
@@ -235,15 +219,16 @@ static uint32_t get_process_stack_position(const struct panic_data *pdata)
*/
static void panic_show_extra(const struct panic_data *pdata)
{
- show_fault(pdata->cm.mmfs, pdata->cm.hfsr, pdata->cm.dfsr);
- if (pdata->cm.mmfs & CPU_NVIC_MMFS_BFARVALID)
+ show_fault(pdata->cm.cfsr, pdata->cm.hfsr, pdata->cm.dfsr);
+ if (pdata->cm.cfsr & CPU_NVIC_CFSR_BFARVALID)
panic_printf(", bfar = %x", pdata->cm.bfar);
- if (pdata->cm.mmfs & CPU_NVIC_MMFS_MFARVALID)
+ if (pdata->cm.cfsr & CPU_NVIC_CFSR_MFARVALID)
panic_printf(", mfar = %x", pdata->cm.mfar);
- panic_printf("\nmmfs = %x, ", pdata->cm.mmfs);
+ panic_printf("\ncfsr = %x, ", pdata->cm.cfsr);
panic_printf("shcsr = %x, ", pdata->cm.shcsr);
panic_printf("hfsr = %x, ", pdata->cm.hfsr);
- panic_printf("dfsr = %x\n", pdata->cm.dfsr);
+ panic_printf("dfsr = %x, ", pdata->cm.dfsr);
+ panic_printf("ipsr = %x\n", pdata->cm.regs[1]);
}
/*
@@ -284,9 +269,18 @@ void panic_data_print(const struct panic_data *pdata)
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);
+ if (((pdata->cm.hfsr >> 26) & 0xf) == HFSR_FLAG_WATCHDOG) {
+ panic_printf("\n### WATCHDOG PC=%08x / LR=%08x / task=%d\n",
+ lregs[4], lregs[1], (pdata->cm.hfsr >> 2) & 0xff);
+ } else if (((pdata->cm.hfsr >> 26) & 0xf) == HFSR_FLAG_ASSERT) {
+ panic_printf("\nASSERTION FAILURE in %s() at %s:%d\n",
+ lregs[3], lregs[4],
+ (pdata->cm.hfsr >> 10) & 0xffff);
+ } else {
+ 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++)
@@ -324,19 +318,36 @@ void __keep report_panic(void)
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++)
+
+ /* Skip r0-r3 and r12 registers if necessary */
+ for (i = CORTEX_PANIC_FRAME_REGISTER_R0;
+ i <= CORTEX_PANIC_FRAME_REGISTER_R12; i++)
+ if (IS_ENABLED(CONFIG_PANIC_STRIP_GPR))
+ pdata->cm.frame[i] = 0;
+ else
+ pdata->cm.frame[i] = sregs[i];
+
+ for (i = CORTEX_PANIC_FRAME_REGISTER_LR;
+ i < NUM_CORTEX_PANIC_FRAME_REGISTERS; i++)
pdata->cm.frame[i] = sregs[i];
+
pdata->flags |= PANIC_DATA_FLAG_FRAME_VALID;
}
/* Save extra information */
- pdata->cm.mmfs = CPU_NVIC_MMFS;
+ pdata->cm.cfsr = CPU_NVIC_CFSR;
pdata->cm.bfar = CPU_NVIC_BFAR;
pdata->cm.mfar = CPU_NVIC_MFAR;
pdata->cm.shcsr = CPU_NVIC_SHCSR;
pdata->cm.hfsr = CPU_NVIC_HFSR;
pdata->cm.dfsr = CPU_NVIC_DFSR;
+ /* Store LR & PC in cm.regs to make them survive a PMIC reset. */
+ if (pdata->flags & PANIC_DATA_FLAG_FRAME_VALID) {
+ pdata->cm.regs[3] = pdata->cm.frame[5]; /* LR */
+ pdata->cm.regs[4] = pdata->cm.frame[6]; /* PC */
+ }
+
#ifdef CONFIG_UART_PAD_SWITCH
uart_reset_default_pad_panic();
#endif
@@ -364,6 +375,33 @@ void exception_panic(void)
"mrs r1, psp\n"
"mrs r2, ipsr\n"
"mov r3, sp\n"
+#ifdef CONFIG_PANIC_STRIP_GPR
+ /*
+ * Check if we are in exception. This is similar to
+ * in_interrupt_context(). Exception bits are 9 LSB, so
+ * we can perform left shift for 23 bits and check if result
+ * is 0 (lsls instruction is setting appropriate flags).
+ */
+ "lsls r6, r2, #23\n"
+ /*
+ * If this is software panic (shift result == 0) then register
+ * r4 and r5 contain additional info about panic.
+ * Clear r6-r11 always and r4, r5 only if this is exception
+ * panic. To clear r4 and r5, 'movne' conditional instruction
+ * is used. It works only when flags contain information that
+ * result was != 0. Itt is pseudo instruction which is used
+ * to make sure we are using correct conditional instructions.
+ */
+ "itt ne\n"
+ "movne r4, #0\n"
+ "movne r5, #0\n"
+ "mov r6, #0\n"
+ "mov r7, #0\n"
+ "mov r8, #0\n"
+ "mov r9, #0\n"
+ "mov r10, #0\n"
+ "mov r11, #0\n"
+#endif
"stmia r0, {r1-r11, lr}\n"
"mov sp, %[pstack]\n"
"bl report_panic\n" : :
@@ -418,6 +456,36 @@ void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception)
}
#endif
+void panic_assert(const char *func, const char *file, uint16_t line)
+{
+ struct panic_data *pdata = pdata_ptr;
+
+ 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;
+
+ /*
+ * Panic data is cleared by PMIC reset on Nami. HFSR is used because
+ * it's saved to BBRAM by the released RO (before PMIC reset). Bit
+ * assignments are as follows:
+ *
+ * ([31:30] Used for DEBUGEVT and FORCED)
+ * [29:26] Flags
+ * [25:10] Line #
+ * [9:2] Task #
+ * ([1:0] Used for VECTTBLE and reserved)
+ */
+ pdata->cm.hfsr = HFSR_FLAG_ASSERT << 26 | line << 10
+ | (task_get_current() & 0xff) << 2;
+ pdata->cm.regs[3] = (uint32_t)func;
+ pdata->cm.regs[4] = (uint32_t)file;
+
+ panic_reboot();
+}
+
void bus_fault_handler(void)
{
if (!bus_fault_ignored)