nds32: fix panic

Support saving panic data for nds32 core.

Signed-off-by: Dino Li <dino.li@ite.com.tw>

BRANCH=none
BUG=none
TEST=1. console commands 'crash' and 'panicinfo'.
     2. ectool command 'panicinfo'

crash assert

ASSERTION FAILURE '0' in command_crash() at common/panic_output.c:162
=== EXCEP: ITYPE=1 ===
R0  00000000 R1  000000a2 R2  00000060 R3  00000000
R4  00080c40 R5  00000000 R6  dead6663 R7  000000a2
R8  00000002 R9  00000000 R10 00081960 R15 00000000
FP  00000000 GP  000818d8 LP  0000079a SP  00080c60
IPC 000007a2 IPSW   70009
SWID of ITYPE: 0
Software panic reason PANIC_SW_ASSERT
Software panic info 0xa2

Rebooting...

panicinfo
Saved panic data: (NEW)
=== EXCEP: ITYPE=1 ===
R0  00000000 R1  000000a2 R2  00000060 R3  00000000
R4  00080c40 R5  00000000 R6  dead6663 R7  000000a2
R8  00000002 R9  00000000 R10 00081960 R15 00000000
FP  00000000 GP  000818d8 LP  0000079a SP  00080c60
IPC 000007a2 IPSW   70009
SWID of ITYPE: 0
Software panic reason PANIC_SW_ASSERT
Software panic info 0xa2

> crash divzero
=== EXCEP: ITYPE=10003 ===
R0  00000000 R1  00f02705 R2  00000060 R3  00081a09
R4  00000000 R5  00000000 R6  00000001 R7  00080cc0
R8  00000002 R9  00000000 R10 00081961 R15 00000000
FP  00000000 GP  000818d8 LP  00009bce SP  00080c90
IPC 00009bee IPSW   70009
SWID of ITYPE: 1
Exception type: General exception [Arithmetic]
Exception is caused by a data memory access

Rebooting...

panicinfo
Saved panic data: (NEW)
=== EXCEP: ITYPE=10003 ===
R0  00000000 R1  00f02705 R2  00000060 R3  00081a09
R4  00000000 R5  00000000 R6  00000001 R7  00080cc0
R8  00000002 R9  00000000 R10 00081961 R15 00000000
FP  00000000 GP  000818d8 LP  00009bce SP  00080c90
IPC 00009bee IPSW   70009
SWID of ITYPE: 1
Exception type: General exception [Arithmetic]
Exception is caused by a data memory access

> crash stack
+1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17

Stack overflow in CONSOLE task!
=== EXCEP: ITYPE=8 ===
R0  00000002 R1  00000002 R2  00000060 R3  00080458
R4  0000ebdd R5  00000000 R6  dead6661 R7  00000002
R8  00000bc8 R9  00000002 R10 00000000 R15 00000000
FP  00000000 GP  000818d8 LP  0000079a SP  00080448
IPC 00000a92 IPSW   70009
SWID of ITYPE: 0
Software panic reason PANIC_SW_STACK_OVERFLOW
Software panic info 0x2

Rebooting...

panicinfo
Saved panic data: (NEW)
=== EXCEP: ITYPE=8 ===
R0  00000002 R1  00000002 R2  00000060 R3  00080458
R4  0000ebdd R5  00000000 R6  dead6661 R7  00000002
R8  00000bc8 R9  00000002 R10 00000000 R15 00000000
FP  00000000 GP  000818d8 LP  0000079a SP  00080448
IPC 00000a92 IPSW   70009
SWID of ITYPE: 0
Software panic reason PANIC_SW_STACK_OVERFLOW
Software panic info 0x2

> crash watchdog
Pre-watchdog warning! IPC: 00009c6c

panicinfo
Saved panic data: (NEW)
=== EXCEP: ITYPE=0 ===
R0  00000000 R1  00000000 R2  00000000 R3  00000000
R4  00000000 R5  00000000 R6  dead6664 R7  00000000
R8  00000000 R9  00000000 R10 00000000 R15 00000000
FP  00000000 GP  00000000 LP  00000000 SP  00000000
IPC 00009c6c IPSW   00000
SWID of ITYPE: 0
Software panic reason PANIC_SW_WATCHDOG
Software panic info 0x0
>

Change-Id: I3d491ecd0789335db4633f9bf2ca09cf85503ed9
Reviewed-on: https://chromium-review.googlesource.com/303286
Commit-Ready: Dino Li <dino.li@ite.com.tw>
Tested-by: Dino Li <dino.li@ite.com.tw>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Dino Li
2015-10-07 14:49:40 +08:00
committed by chrome-bot
parent f769f9837c
commit 4bb7c3e2f1
6 changed files with 277 additions and 35 deletions

View File

@@ -14,6 +14,9 @@
#include "task.h"
#include "watchdog.h"
/* Panic data goes at the end of RAM. */
static struct panic_data * const pdata_ptr = PANIC_DATA_PTR;
/*
* We use WDT_EXT_TIMER to trigger an interrupt just before the watchdog timer
* will fire so that we can capture important state information before
@@ -25,6 +28,9 @@
void watchdog_warning_irq(void)
{
#ifdef CONFIG_SOFTWARE_PANIC
pdata_ptr->nds_n8.ipc = get_ipc();
#endif
/* clear interrupt status */
task_clear_pending_irq(et_ctrl_regs[WDT_EXT_TIMER].irq);

View File

@@ -10,6 +10,8 @@
#define BFD_ARCH nds32
#define BFD_FORMAT "elf32-nds32le"
#define CONFIG_SOFTWARE_PANIC
/*
* The Andestar v3m architecture has no CLZ instruction (contrary to v3),
* so let's use the software implementation.

View File

@@ -13,7 +13,134 @@
#include "timer.h"
#include "util.h"
void report_panic(uint32_t *regs, uint32_t itype)
/* General purpose register (r6) for saving software panic reason */
#define SOFT_PANIC_GPR_REASON 6
/* General purpose register (r7) for saving software panic information */
#define SOFT_PANIC_GPR_INFO 7
/* Panic data goes at the end of RAM. */
static struct panic_data * const pdata_ptr = PANIC_DATA_PTR;
#ifdef CONFIG_DEBUG_EXCEPTIONS
/**
* bit[4] @ ITYPE, Indicates if an exception is caused by an instruction fetch
* or a data memory access for the following exceptions:
* -TLB fill
* -TLB VLPT miss
* -TLB read protection
* -TLB write protection
* -TLB non-executable page
* -TLB page modified
* -TLB Access bit
* -PTE not present (all)
* -Reserved PTE Attribute
* -Alignment check
* -Branch target alignment
* -Machine error
* -Precise bus error
* -Imprecise bus error
* -Nonexistent local memory address
* -MPZIU Control
* -Cache locking error
* -TLB locking error
* -TLB multiple hit
* -Parity/ECC error
* All other exceptions not in the abovetable should have the INST field of
* the ITYPE register set to 0.
*/
static const char * const itype_inst[2] = {
"a data memory access",
"an instruction fetch access",
};
/**
* bit[3-0] @ ITYPE, general exception type information.
*/
static const char * const itype_exc_type[16] = {
"Alignment check",
"Reserved instruction",
"Trap",
"Arithmetic",
"Precise bus error",
"Imprecise bus error",
"Coprocessor",
"Privileged instruction",
"Reserved value",
"Nonexistent local memory address",
"MPZIU Control",
NULL,
NULL,
NULL,
NULL,
NULL,
};
#endif /* CONFIG_DEBUG_EXCEPTIONS */
#ifdef CONFIG_SOFTWARE_PANIC
/* Software panic reasons */
static const char * const panic_sw_reasons[8] = {
"PANIC_SW_DIV_ZERO",
"PANIC_SW_STACK_OVERFLOW",
"PANIC_SW_PD_CRASH",
"PANIC_SW_ASSERT",
"PANIC_SW_WATCHDOG",
NULL,
NULL,
NULL,
};
void software_panic(uint32_t reason, uint32_t info)
{
asm volatile ("mov55 $r6, %0" : : "r"(reason));
asm volatile ("mov55 $r7, %0" : : "r"(info));
if (in_interrupt_context())
asm("j excep_handler");
else
asm("trap 0");
}
void panic_set_reason(uint32_t reason, uint32_t info, uint8_t exception)
{
uint32_t *regs = pdata_ptr->nds_n8.regs;
uint32_t warning_ipc;
/* Setup panic data structure */
if (reason != PANIC_SW_WATCHDOG) {
memset(pdata_ptr, 0, sizeof(*pdata_ptr));
} else {
warning_ipc = pdata_ptr->nds_n8.ipc;
memset(pdata_ptr, 0, sizeof(*pdata_ptr));
pdata_ptr->nds_n8.ipc = warning_ipc;
}
pdata_ptr->magic = PANIC_DATA_MAGIC;
pdata_ptr->struct_size = sizeof(*pdata_ptr);
pdata_ptr->struct_version = 2;
pdata_ptr->arch = PANIC_ARCH_NDS32_N8;
/* Log panic cause */
pdata_ptr->nds_n8.itype = exception;
regs[SOFT_PANIC_GPR_REASON] = reason;
regs[SOFT_PANIC_GPR_INFO] = info;
}
void panic_get_reason(uint32_t *reason, uint32_t *info, uint8_t *exception)
{
uint32_t *regs = pdata_ptr->nds_n8.regs;
if (pdata_ptr->magic == PANIC_DATA_MAGIC &&
pdata_ptr->struct_version == 2) {
*exception = pdata_ptr->nds_n8.itype;
*reason = regs[SOFT_PANIC_GPR_REASON];
*info = regs[SOFT_PANIC_GPR_INFO];
} else {
*exception = *reason = *info = 0;
}
}
#endif /* CONFIG_SOFTWARE_PANIC */
static void print_panic_information(uint32_t *regs, uint32_t itype,
uint32_t ipc, uint32_t ipsw)
{
panic_printf("=== EXCEP: ITYPE=%x ===\n", itype);
panic_printf("R0 %08x R1 %08x R2 %08x R3 %08x\n",
@@ -24,8 +151,8 @@ void report_panic(uint32_t *regs, uint32_t itype)
regs[8], regs[9], regs[10], regs[11]);
panic_printf("FP %08x GP %08x LP %08x SP %08x\n",
regs[12], regs[13], regs[14], regs[15]);
panic_printf("IPC %08x IPSW %05x\n", regs[16], regs[17]);
if ((regs[17] & PSW_INTL_MASK) == (2 << PSW_INTL_SHIFT)) {
panic_printf("IPC %08x IPSW %05x\n", ipc, ipsw);
if ((ipsw & PSW_INTL_MASK) == (2 << PSW_INTL_SHIFT)) {
/* 2nd level exception */
uint32_t oipc;
@@ -33,9 +160,53 @@ void report_panic(uint32_t *regs, uint32_t itype)
panic_printf("OIPC %08x\n", oipc);
}
#ifdef CONFIG_DEBUG_EXCEPTIONS
panic_printf("SWID of ITYPE: %x\n", ((itype >> 16) & 0x7fff));
if ((regs[SOFT_PANIC_GPR_REASON] & 0xfffffff0) == PANIC_SW_BASE) {
#ifdef CONFIG_SOFTWARE_PANIC
panic_printf("Software panic reason %s\n",
panic_sw_reasons[(regs[SOFT_PANIC_GPR_REASON] & 0x7)]);
panic_printf("Software panic info 0x%x\n",
regs[SOFT_PANIC_GPR_INFO]);
#endif
} else {
panic_printf("Exception type: General exception [%s]\n",
itype_exc_type[(itype & 0xf)]);
panic_printf("Exception is caused by %s\n",
itype_inst[(itype & (1 << 4))]);
}
#endif
}
void report_panic(uint32_t *regs, uint32_t itype)
{
int i;
struct panic_data *pdata = pdata_ptr;
pdata->magic = PANIC_DATA_MAGIC;
pdata->struct_size = sizeof(*pdata);
pdata->struct_version = 2;
pdata->arch = PANIC_ARCH_NDS32_N8;
pdata->flags = 0;
pdata->reserved = 0;
pdata->nds_n8.itype = itype;
for (i = 0; i < 16; i++)
pdata->nds_n8.regs[i] = regs[i];
pdata->nds_n8.ipc = regs[16];
pdata->nds_n8.ipsw = regs[17];
print_panic_information(regs, itype, regs[16], regs[17]);
panic_reboot();
}
void panic_data_print(const struct panic_data *pdata)
{
uint32_t itype, *regs, ipc, ipsw;
itype = pdata->nds_n8.itype;
regs = (uint32_t *)pdata->nds_n8.regs;
ipc = pdata->nds_n8.ipc;
ipsw = pdata->nds_n8.ipsw;
print_panic_information(regs, itype, ipc, ipsw);
}

View File

@@ -304,12 +304,27 @@ task_ *next_sched_task(void)
#ifdef CONFIG_TASK_PROFILING
if (current_task != new_task) {
current_task->runtime +=
(exc_start_time - exc_end_time - exc_sub_time);
if ((current_task - tasks) < TASK_ID_COUNT) {
current_task->runtime +=
(exc_start_time - exc_end_time - exc_sub_time);
}
task_will_switch = 1;
}
#endif
#ifdef CONFIG_DEBUG_STACK_OVERFLOW
if (*current_task->stack != STACK_UNUSED_VALUE) {
int i = task_get_current();
if (i < TASK_ID_COUNT) {
panic_printf("\n\nStack overflow in %s task!\n",
task_names[i]);
#ifdef CONFIG_SOFTWARE_PANIC
software_panic(PANIC_SW_STACK_OVERFLOW, i);
#endif
}
}
#endif
return new_task;
}

View File

@@ -29,6 +29,14 @@ struct cortex_panic_data {
uint32_t dfsr;
};
/* NDS32 N8 registers saved on panic */
struct nds32_n8_panic_data {
uint32_t itype;
uint32_t regs[16]; /* r0-r10, r15, fp, gp, lp, sp */
uint32_t ipc;
uint32_t ipsw;
};
/* Data saved across reboots */
struct panic_data {
uint8_t arch; /* Architecture (PANIC_ARCH_*) */
@@ -38,7 +46,8 @@ struct panic_data {
/* core specific panic data */
union {
struct cortex_panic_data cm; /* Cortex-Mx registers */
struct cortex_panic_data cm; /* Cortex-Mx registers */
struct nds32_n8_panic_data nds_n8; /* NDS32 N8 registers */
};
/*
@@ -50,7 +59,10 @@ struct panic_data {
};
#define PANIC_DATA_MAGIC 0x21636e50 /* "Pnc!" */
#define PANIC_ARCH_CORTEX_M 1 /* Cortex-M architecture */
enum panic_arch {
PANIC_ARCH_CORTEX_M = 1, /* Cortex-M architecture */
PANIC_ARCH_NDS32_N8 = 2, /* NDS32 N8 architecture */
};
/*
* Panic data goes at the end of RAM. This is safe because we don't context

View File

@@ -4204,10 +4204,8 @@ static void print_panic_reg(int regnum, const uint32_t *regs, int index)
printf((regnum & 3) == 3 ? "\n" : " ");
}
int cmd_panic_info(int argc, char *argv[])
int cmd_panic_info_cm(int argc, char *argv[])
{
int rv;
struct panic_data *pdata = (struct panic_data *)ec_inbuf;
const uint32_t *lregs = pdata->cm.regs;
const uint32_t *sregs = NULL;
@@ -4219,31 +4217,6 @@ int cmd_panic_info(int argc, char *argv[])
int i;
const char *panic_origins[3] = {"", "PROCESS", "HANDLER"};
rv = ec_command(EC_CMD_GET_PANIC_INFO, 0, NULL, 0,
ec_inbuf, ec_max_insize);
if (rv < 0)
return rv;
if (rv == 0) {
printf("No panic data.\n");
return 0;
}
/*
* We only understand panic data with version <= 2. Warn the user
* of higher versions.
*/
if (pdata->struct_version > 2)
fprintf(stderr,
"Unknown panic data version (%d). "
"Following data may be incorrect!\n",
pdata->struct_version);
if (pdata->arch != PANIC_ARCH_CORTEX_M)
fprintf(stderr, "Unknown architecture (%d). "
"CPU specific data will be incorrect!\n",
pdata->arch);
printf("Saved panic data:%s\n",
(pdata->flags & PANIC_DATA_FLAG_OLD_HOSTCMD ? "" : " (NEW)"));
@@ -4277,6 +4250,69 @@ int cmd_panic_info(int argc, char *argv[])
return 0;
}
int cmd_panic_info_nds32(int argc, char *argv[])
{
struct panic_data *pdata = (struct panic_data *)ec_inbuf;
const uint32_t *regs = pdata->nds_n8.regs;
uint32_t itype = pdata->nds_n8.itype;
uint32_t ipc = pdata->nds_n8.ipc;
uint32_t ipsw = pdata->nds_n8.ipsw;
printf("Saved panic data:%s\n",
(pdata->flags & PANIC_DATA_FLAG_OLD_HOSTCMD ? "" : " (NEW)"));
printf("=== EXCEP: ITYPE=%x ===\n", itype);
printf("R0 %08x R1 %08x R2 %08x R3 %08x\n",
regs[0], regs[1], regs[2], regs[3]);
printf("R4 %08x R5 %08x R6 %08x R7 %08x\n",
regs[4], regs[5], regs[6], regs[7]);
printf("R8 %08x R9 %08x R10 %08x R15 %08x\n",
regs[8], regs[9], regs[10], regs[11]);
printf("FP %08x GP %08x LP %08x SP %08x\n",
regs[12], regs[13], regs[14], regs[15]);
printf("IPC %08x IPSW %05x\n", ipc, ipsw);
printf("SWID of ITYPE: %x\n", ((itype >> 16) & 0x7fff));
return 0;
}
int cmd_panic_info(int argc, char *argv[])
{
int rv;
struct panic_data *pdata = (struct panic_data *)ec_inbuf;
rv = ec_command(EC_CMD_GET_PANIC_INFO, 0, NULL, 0,
ec_inbuf, ec_max_insize);
if (rv < 0)
return rv;
if (rv == 0) {
printf("No panic data.\n");
return 0;
}
/*
* We only understand panic data with version <= 2. Warn the user
* of higher versions.
*/
if (pdata->struct_version > 2)
fprintf(stderr,
"Unknown panic data version (%d). "
"Following data may be incorrect!\n",
pdata->struct_version);
switch (pdata->arch) {
case PANIC_ARCH_CORTEX_M:
return cmd_panic_info_cm(argc, argv);
case PANIC_ARCH_NDS32_N8:
return cmd_panic_info_nds32(argc, argv);
default:
fprintf(stderr, "Unknown architecture (%d).\n", pdata->arch);
break;
}
return -1;
}
int cmd_power_info(int argc, char *argv[])
{