diff --git a/chip/it83xx/watchdog.c b/chip/it83xx/watchdog.c index e6941b1de5..6c15afc60a 100644 --- a/chip/it83xx/watchdog.c +++ b/chip/it83xx/watchdog.c @@ -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); diff --git a/core/nds32/config_core.h b/core/nds32/config_core.h index 0bf6595611..fae914f7eb 100644 --- a/core/nds32/config_core.h +++ b/core/nds32/config_core.h @@ -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. diff --git a/core/nds32/panic.c b/core/nds32/panic.c index 79cd065321..e1bd4e5c29 100644 --- a/core/nds32/panic.c +++ b/core/nds32/panic.c @@ -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); } diff --git a/core/nds32/task.c b/core/nds32/task.c index df7743ed82..7edad8b6e4 100644 --- a/core/nds32/task.c +++ b/core/nds32/task.c @@ -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; } diff --git a/include/panic.h b/include/panic.h index ea7a40f7b0..a4fbf24b92 100644 --- a/include/panic.h +++ b/include/panic.h @@ -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 diff --git a/util/ectool.c b/util/ectool.c index 722ba32cb5..1c409846e0 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -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[]) {