panic: Improve panic reporting to include DSP regs and stack dump

Improve the output from panic to include DSP registers and stack dump.
Export panic codes to UAPI for host driver logging.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
This commit is contained in:
Liam Girdwood 2018-02-21 15:36:25 +00:00
parent f09ce2a6a0
commit e52ce68347
14 changed files with 252 additions and 138 deletions

View File

@ -33,9 +33,41 @@
#define __INCLUDE_ARCH_REEF__
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <execinfo.h>
/* architecture specific stack frames to dump */
#define ARCH_STACK_DUMP_FRAMES 32
#define arch_memcpy(dest, src, size) \
memcpy(dest, src, size)
static inline void *arch_get_stack_ptr(void)
{
void *frames[ARCH_STACK_DUMP_FRAMES];
size_t frame_count;
size_t i;
char **symbols;
frame_count = backtrace(frames, ARCH_STACK_DUMP_FRAMES);
symbols = backtrace_symbols(frames, frame_count);
fprintf(stderr, "Dumping %zd stack frames.\n", frame_count);
for (i = 0; i < frame_count; i++)
fprintf(stderr, "\t%s\n", symbols[i]);
free(symbols);
return NULL;
}
static inline void *arch_dump_regs(void)
{
return NULL;
}
#endif

View File

@ -190,7 +190,7 @@ void boot_pri_core(void)
platform_trace_point(TRACE_BOOT_LDR_HPSRAM);
result = hp_sram_init();
if (result < 0) {
platform_panic(PANIC_MEM);
platform_panic(SOF_IPC_PANIC_MEM);
return;
}

View File

@ -34,15 +34,20 @@
#include <stdint.h>
#include <stddef.h>
#include <reef/mailbox.h>
#include <uapi/ipc.h>
/* architecture specific stack frames to dump */
#define ARCH_STACK_DUMP_FRAMES 32
void *xthal_memcpy(void *dst, const void *src, size_t len);
#define arch_memcpy(dest, src, size) \
xthal_memcpy(dest, src, size)
static inline size_t arch_get_stack_ptr(void)
static inline void *arch_get_stack_ptr(void)
{
size_t ptr;
void *ptr;
/* stack pointer is in a1 */
__asm__ __volatile__ ("mov %0, a1"
@ -52,4 +57,58 @@ static inline size_t arch_get_stack_ptr(void)
return ptr;
}
static inline void *arch_dump_regs(void)
{
struct sof_ipc_dsp_oops_xtensa *x =
(struct sof_ipc_dsp_oops_xtensa *) mailbox_get_exception_base();
/* Exception Vector number - 0x0 */
__asm__ __volatile__ ("rsr %0, EXCCAUSE" : "=a" (x->exccause) : : "memory");
/* Exception Vector address - 0x4 */
__asm__ __volatile__ ("rsr %0, EXCVADDR" : "=a" (x->excvaddr) : : "memory");
/* Exception Processor State - 0x8 */
__asm__ __volatile__ ("rsr %0, PS" : "=a" (x->ps) : : "memory");
/* Level 1 Exception PC - 0xc */
__asm__ __volatile__ ("rsr %0, EPC1" : "=a" (x->epc1) : : "memory");
/* Level 2 Exception PC - 0x10 */
__asm__ __volatile__ ("rsr %0, EPC2" : "=a" (x->epc2) : : "memory");
/* Level 3 Exception PC - 0x14 */
__asm__ __volatile__ ("rsr %0, EPC3" : "=a" (x->epc3) : : "memory");
/* Level 4 Exception PC - 0x18 */
__asm__ __volatile__ ("rsr %0, EPC4" : "=a" (x->epc4) : : "memory");
/* Level 5 Exception PC - 0x1c */
__asm__ __volatile__ ("rsr %0, EPC5" : "=a" (x->epc5) : : "memory");
/* Level 6 Exception PC - 0x20 */
__asm__ __volatile__ ("rsr %0, EPC6" : "=a" (x->epc6) : : "memory");
/* Level 7 Exception PC - 0x24 */
__asm__ __volatile__ ("rsr %0, EPC7" : "=a" (x->epc7) : : "memory");
/* Level 2 Exception PS - 0x28 */
__asm__ __volatile__ ("rsr %0, EPS2" : "=a" (x->eps2) : : "memory");
/* Level 3 Exception PS - 0x2c */
__asm__ __volatile__ ("rsr %0, EPS3" : "=a" (x->eps3) : : "memory");
/* Level 4 Exception PS - 0x30 */
__asm__ __volatile__ ("rsr %0, EPS4" : "=a" (x->eps4) : : "memory");
/* Level 5 Exception PS - 0x34 */
__asm__ __volatile__ ("rsr %0, EPS5" : "=a" (x->eps5) : : "memory");
/* Level 6 Exception PS - 0x38 */
__asm__ __volatile__ ("rsr %0, EPS6" : "=a" (x->eps6) : : "memory");
/* Level 7 Exception PS - 0x3c */
__asm__ __volatile__ ("rsr %0, EPS7" : "=a" (x->eps7) : : "memory");
/* Double Exception program counter - 0x40 */
__asm__ __volatile__ ("rsr %0, DEPC" : "=a" (x->depc) : : "memory");
/* Interrupts Enabled - 0x44 */
__asm__ __volatile__ ("rsr %0, INTENABLE" : "=a" (x->intenable) : : "memory");
/* Interrupts Status - 0x48 */
__asm__ __volatile__ ("rsr %0, INTERRUPT" : "=a" (x->interrupt) : : "memory");
/* Shift register - 0x4c */
__asm__ __volatile__ ("rsr %0, SAR" : "=a" (x->sar) : : "memory");
/* Register A1 (stack) - 0x50 */
__asm__ __volatile__ ("mov %0, a1" : "=a" (x->stack) : : "memory");
dcache_writeback_region((void *)x, sizeof(*x));
/* tell caller extended data can be placed hereafter */
return (void *)(x + 1);
}
#endif

View File

@ -35,7 +35,7 @@
#include <platform/interrupt.h>
#include <reef/mailbox.h>
#include <arch/task.h>
#include <reef/debug.h>
#include <reef/panic.h>
#include <reef/init.h>
#include <reef/lock.h>
#include <stdint.h>
@ -45,92 +45,11 @@ uint32_t lock_dbg_atomic = 0;
uint32_t lock_dbg_user[DBG_LOCK_USERS] = {0};
#endif
/* TODO: this should be fixed by rotating the register Window on the stack and
* dumping the saved registers.
* TODO: we should also have different handlers for each type where we can take
* advantage of dumping further information. i.e. call stack and avoid
* clobbering some registers dumped below are clobbered */
static void exception(void)
{
volatile uint32_t *dump = (uint32_t*) mailbox_get_exception_base();
/* Exception Vector number - 0x0 */
__asm__ __volatile__ ("rsr %0, EXCCAUSE" : "=a" (dump[0]) : : "memory");
/* Exception Vector address - 0x4 */
__asm__ __volatile__ ("rsr %0, EXCVADDR" : "=a" (dump[1]) : : "memory");
/* Exception Processor State - 0x8 */
__asm__ __volatile__ ("rsr %0, PS" : "=a" (dump[2]) : : "memory");
/* Level 1 Exception PC - 0xc */
__asm__ __volatile__ ("rsr %0, EPC1" : "=a" (dump[3]) : : "memory");
/* Level 2 Exception PC - 0x10 */
__asm__ __volatile__ ("rsr %0, EPC2" : "=a" (dump[4]) : : "memory");
/* Level 3 Exception PC - 0x14 */
__asm__ __volatile__ ("rsr %0, EPC3" : "=a" (dump[5]) : : "memory");
/* Level 4 Exception PC - 0x18 */
__asm__ __volatile__ ("rsr %0, EPC4" : "=a" (dump[6]) : : "memory");
/* Level 5 Exception PC - 0x1c */
__asm__ __volatile__ ("rsr %0, EPC5" : "=a" (dump[7]) : : "memory");
/* Level 6 Exception PC - 0x20 */
__asm__ __volatile__ ("rsr %0, EPC6" : "=a" (dump[8]) : : "memory");
/* Level 7 Exception PC - 0x24 */
__asm__ __volatile__ ("rsr %0, EPC7" : "=a" (dump[9]) : : "memory");
/* Level 2 Exception PS - 0x28 */
__asm__ __volatile__ ("rsr %0, EPS2" : "=a" (dump[10]) : : "memory");
/* Level 3 Exception PS - 0x2c */
__asm__ __volatile__ ("rsr %0, EPS3" : "=a" (dump[11]) : : "memory");
/* Level 4 Exception PS - 0x30 */
__asm__ __volatile__ ("rsr %0, EPS4" : "=a" (dump[12]) : : "memory");
/* Level 5 Exception PS - 0x34 */
__asm__ __volatile__ ("rsr %0, EPS5" : "=a" (dump[13]) : : "memory");
/* Level 6 Exception PS - 0x38 */
__asm__ __volatile__ ("rsr %0, EPS6" : "=a" (dump[14]) : : "memory");
/* Level 7 Exception PS - 0x3c */
__asm__ __volatile__ ("rsr %0, EPS7" : "=a" (dump[15]) : : "memory");
/* Double Exception program counter - 0x40 */
__asm__ __volatile__ ("rsr %0, DEPC" : "=a" (dump[16]) : : "memory");
/* Register A0 - 0x44 */
__asm__ __volatile__ ("mov %0, a0" : "=a" (dump[17]) : : "memory");
/* Register A1 - 0x48 */
__asm__ __volatile__ ("mov %0, a1" : "=a" (dump[18]) : : "memory");
/* Register A2 - 0x4c */
__asm__ __volatile__ ("mov %0, a2" : "=a" (dump[19]) : : "memory");
/* Register A3 - 0x50 */
__asm__ __volatile__ ("mov %0, a3" : "=a" (dump[20]) : : "memory");
/* Register A4 - 0x54 */
__asm__ __volatile__ ("mov %0, a4" : "=a" (dump[21]) : : "memory");
/* Register A5 - 0x58 */
__asm__ __volatile__ ("mov %0, a5" : "=a" (dump[22]) : : "memory");
/* Register A6 - 0x5c */
__asm__ __volatile__ ("mov %0, a6" : "=a" (dump[23]) : : "memory");
/* Register A7 - 0x60 */
__asm__ __volatile__ ("mov %0, a7" : "=a" (dump[24]) : : "memory");
/* Register A8 - 0x64 */
__asm__ __volatile__ ("mov %0, a8" : "=a" (dump[25]) : : "memory");
/* Register A9 - 0x68 */
__asm__ __volatile__ ("mov %0, a9" : "=a" (dump[26]) : : "memory");
/* Register A10 - 0x6c */
__asm__ __volatile__ ("mov %0, a10" : "=a" (dump[27]) : : "memory");
/* Register A11 - 0x70 */
__asm__ __volatile__ ("mov %0, a11" : "=a" (dump[28]) : : "memory");
/* Register A12 - 0x74 */
__asm__ __volatile__ ("mov %0, a12" : "=a" (dump[29]) : : "memory");
/* Register A13 - 0x78 */
__asm__ __volatile__ ("mov %0, a13" : "=a" (dump[30]) : : "memory");
/* Register A14 - 0x7c */
__asm__ __volatile__ ("mov %0, a14" : "=a" (dump[31]) : : "memory");
/* Register A15 - 0x80 */
__asm__ __volatile__ ("mov %0, a15" : "=a" (dump[32]) : : "memory");
/* Interrupts Enabled - 0x84 */
__asm__ __volatile__ ("rsr %0, INTENABLE" : "=a" (dump[33]) : : "memory");
/* Interrupts Status - 0x88 */
__asm__ __volatile__ ("rsr %0, INTERRUPT" : "=a" (dump[34]) : : "memory");
/* Shift register - 0x8c */
__asm__ __volatile__ ("rsr %0, SAR" : "=a" (dump[35]) : : "memory");
/* atm we loop forever */
/* TODO: we should probably stall/HALT at this point or recover */
panic(PANIC_EXCEPTION);
/* now panic and rewind 8 stack frames. */
/* TODO: we could invoke a GDB stub here */
panic_rewind(SOF_IPC_PANIC_EXCEPTION, 8 * sizeof(uint32_t));
}
static void register_exceptions(void)

View File

@ -23,6 +23,7 @@ include_HEADERS = \
lock.h \
mailbox.h \
notifier.h \
panic.h \
reef.h \
schedule.h \
ssp.h \

View File

@ -32,22 +32,13 @@
#ifndef __INCLUDE_DEBUG__
#define __INCLUDE_DEBUG__
#include <reef/reef.h>
#include <reef/mailbox.h>
#include <uapi/ipc.h>
#include <platform/platform.h>
#include <stdint.h>
#include <stdlib.h>
/* panic reasons */
#define PANIC_MEM 0
#define PANIC_WORK 1
#define PANIC_IPC 2
#define PANIC_ARCH 3
#define PANIC_PLATFORM 4
#define PANIC_TASK 5
#define PANIC_EXCEPTION 6
#define PANIC_DEADLOCK 7
#define PANIC_STACK 8
#define PANIC_IDLE 9
#define DEBUG
@ -136,38 +127,31 @@
#define dump_object_ptr(__o)
#endif
/* panic and stop executing any more code */
#define panic(_p) \
do { \
interrupt_global_disable(); \
dbg_val(0xdead0000 | _p) \
platform_panic(_p); \
while(1) {}; \
} while (0);
/* dump stack as part of panic */
#define panic_dump_stack(_p) \
do { \
extern uint32_t __stack; \
extern uint32_t _stack_sentry; \
uint32_t _stack_bottom = (uint32_t)&__stack; \
uint32_t _stack_limit = (uint32_t)&_stack_sentry; \
uint32_t _stack_top = arch_get_stack_ptr(); \
uint32_t _size = _stack_bottom - _stack_top; \
uint32_t _panic = _p; \
dbg_val(0xdead0000 | _p) \
dbg_val_at(_stack_top, 1) \
dbg_val_at(_stack_bottom, 2) \
/* is stack smashed ? */\
if (_stack_bottom <= _stack_limit) { \
dbg_val_at(0x51ac0000 | _p, 3); \
_stack_bottom = _stack_limit; \
_panic = PANIC_STACK; \
} \
platform_panic(_panic); \
dump_at(_stack_top, (_size - sizeof(uint32_t)) >> 2, 4) \
\
while(1) {}; \
} while (0);
static inline void dump_stack(uint32_t p, void *addr, size_t offset,
size_t limit)
{
extern void *__stack;
extern void *_stack_sentry;
void *stack_bottom = (void *)&__stack;
void *stack_limit = (void *)&_stack_sentry;
void *stack_top = arch_get_stack_ptr() + offset;
size_t size = stack_bottom - stack_top;
/* is stack smashed ? */
if (stack_top - offset <= stack_limit) {
stack_bottom = stack_limit;
p = SOF_IPC_PANIC_STACK;
platform_panic(p);
}
/* make sure stack size won't overflow dump area */
if (size > limit)
size = limit;
/* copy stack contents and writeback */
rmemcpy(addr, stack_top, size - sizeof(void *));
dcache_writeback_region(addr, size - sizeof(void *));
}
#endif

View File

@ -116,7 +116,7 @@ extern uint32_t lock_dbg_user[DBG_LOCK_USERS];
trace_lock_error("DED"); \
trace_lock_value(__LINE__); \
trace_lock_value((lock)->user); \
panic(PANIC_DEADLOCK); /* lock not acquired */ \
panic(SOF_IPC_PANIC_DEADLOCK); /* lock not acquired */ \
} \
} while (0);

69
src/include/reef/panic.h Normal file
View File

@ -0,0 +1,69 @@
/*
* Copyright (c) 2018, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Intel Corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
*/
#ifndef __INCLUDE_SOF_IPC_PANIC__
#define __INCLUDE_SOF_IPC_PANIC__
#include <reef/reef.h>
#include <reef/mailbox.h>
#include <reef/interrupt.h>
#include <platform/platform.h>
#include <uapi/ipc.h>
#include <stdint.h>
#include <stdlib.h>
/* panic and rewind stack */
static inline void panic_rewind(uint32_t p, uint32_t stack_rewind_frames)
{
void *ext_offset;
/* disable all IRQs */
interrupt_global_disable();
/* dump DSP core registers */
ext_offset = arch_dump_regs();
/* dump stack frames */
dump_stack(SOF_IPC_PANIC_EXCEPTION, ext_offset, stack_rewind_frames,
ARCH_STACK_DUMP_FRAMES * sizeof(uint32_t));
/* TODO: send IPC oops message to host */
/* panic and loop forever */
platform_panic(p);
while (1) {};
}
static inline void panic(uint32_t p)
{
panic_rewind(p, 0);
}
#endif

View File

@ -126,6 +126,23 @@
/* maximum message size for mailbox Tx/Tx */
#define SOF_IPC_MSG_MAX_SIZE 128
/*
* SOF panic codes
*/
#define SOF_IPC_PANIC_MAGIC 0x0dead000
#define SOF_IPC_PANIC_MAGIC_MASK 0x0ffff000
#define SOF_IPC_PANIC_CODE_MASK 0x00000fff
#define SOF_IPC_PANIC_MEM (SOF_IPC_PANIC_MAGIC | 0)
#define SOF_IPC_PANIC_WORK (SOF_IPC_PANIC_MAGIC | 1)
#define SOF_IPC_PANIC_IPC (SOF_IPC_PANIC_MAGIC | 2)
#define SOF_IPC_PANIC_ARCH (SOF_IPC_PANIC_MAGIC | 3)
#define SOF_IPC_PANIC_PLATFORM (SOF_IPC_PANIC_MAGIC | 4)
#define SOF_IPC_PANIC_TASK (SOF_IPC_PANIC_MAGIC | 5)
#define SOF_IPC_PANIC_EXCEPTION (SOF_IPC_PANIC_MAGIC | 6)
#define SOF_IPC_PANIC_DEADLOCK (SOF_IPC_PANIC_MAGIC | 7)
#define SOF_IPC_PANIC_STACK (SOF_IPC_PANIC_MAGIC | 8)
#define SOF_IPC_PANIC_IDLE (SOF_IPC_PANIC_MAGIC | 9)
/*
* Command Header - Header for all IPC. Identifies IPC message.
* The size can be greater than the structure size and that means there is
@ -820,4 +837,33 @@ struct sof_ipc_dma_trace_posn {
uint32_t messages; /* total trace messages */
} __attribute__((packed));
/*
* Architecture specific debug
*/
/* Xtensa Firmware Oops data */
struct sof_ipc_dsp_oops_xtensa {
uint32_t exccause;
uint32_t excvaddr;
uint32_t ps;
uint32_t epc1;
uint32_t epc2;
uint32_t epc3;
uint32_t epc4;
uint32_t epc5;
uint32_t epc6;
uint32_t epc7;
uint32_t eps2;
uint32_t eps3;
uint32_t eps4;
uint32_t eps5;
uint32_t eps6;
uint32_t eps7;
uint32_t depc;
uint32_t intenable;
uint32_t interrupt;
uint32_t sar;
uint32_t stack;
} __attribute__((packed));
#endif

View File

@ -35,6 +35,7 @@
#include <reef/init.h>
#include <reef/task.h>
#include <reef/debug.h>
#include <reef/panic.h>
#include <reef/alloc.h>
#include <reef/notifier.h>
#include <reef/work.h>
@ -59,7 +60,7 @@ int main(int argc, char *argv[])
trace_point(TRACE_BOOT_ARCH);
err = arch_init(&reef);
if (err < 0)
panic(PANIC_ARCH);
panic(SOF_IPC_PANIC_ARCH);
/* initialise system services */
trace_point(TRACE_BOOT_SYS_HEAP);
@ -76,7 +77,7 @@ int main(int argc, char *argv[])
/* init the platform */
err = platform_init(&reef);
if (err < 0)
panic(PANIC_PLATFORM);
panic(SOF_IPC_PANIC_PLATFORM);
trace_point(TRACE_BOOT_PLATFORM);
@ -84,6 +85,6 @@ int main(int argc, char *argv[])
err = do_task(&reef);
/* should never get here */
panic_dump_stack(PANIC_TASK);
panic(SOF_IPC_PANIC_TASK);
return err;
}

View File

@ -37,6 +37,7 @@
#include <reef/reef.h>
#include <reef/agent.h>
#include <reef/debug.h>
#include <reef/panic.h>
#include <reef/alloc.h>
#include <reef/clock.h>
#include <reef/trace.h>
@ -70,7 +71,7 @@ static uint64_t validate(void *data, uint64_t delay)
if (delta > sa->ticks) {
trace_sa("tim");
trace_sa_value(delta);
panic_dump_stack(PANIC_IDLE);
panic(SOF_IPC_PANIC_IDLE);
}
return PLATFORM_IDLE_TIME;

View File

@ -32,6 +32,7 @@
#include <reef/alloc.h>
#include <reef/reef.h>
#include <reef/debug.h>
#include <reef/panic.h>
#include <reef/trace.h>
#include <reef/lock.h>
#include <platform/memory.h>
@ -216,7 +217,7 @@ static void *rmalloc_sys(size_t bytes)
memmap.system.heap += bytes;
if (memmap.system.heap >= HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) {
trace_mem_error("eMd");
panic(PANIC_MEM);
panic(SOF_IPC_PANIC_MEM);
}
#if DEBUG_BLOCK_ALLOC

View File

@ -50,5 +50,6 @@
/* IPC page data copy timeout */
#define PLATFORM_IPC_DMA_TIMEOUT 2000
static inline void platform_panic(uint32_t p) {}
#endif

View File

@ -73,7 +73,7 @@ int do_task(struct reef *reef)
/* init static pipeline */
pdata.p = init_static_pipeline();
if (pdata.p == NULL)
panic(PANIC_TASK);
panic(SOF_IPC_PANIC_TASK);
#endif
/* let host know DSP boot is complete */
platform_boot_complete(0);