#include "esp_attr.h"
/*
-Panic handlers; these get called when an unhandled exception occurs or the assembly-level
-task switching / interrupt code runs into an unrecoverable error. The default task stack
-overflow handler also is in here.
+ Panic handlers; these get called when an unhandled exception occurs or the assembly-level
+ task switching / interrupt code runs into an unrecoverable error. The default task stack
+ overflow handler also is in here.
*/
/*
-Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
+ Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
*/
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
//printf may be broken, so we fix our own printing fns...
-inline static void panicPutChar(char c) {
- while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
- WRITE_PERI_REG(UART_FIFO_REG(0), c);
+inline static void panicPutChar(char c)
+{
+ while (((READ_PERI_REG(UART_STATUS_REG(0)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT) >= 126) ;
+ WRITE_PERI_REG(UART_FIFO_REG(0), c);
}
-inline static void panicPutStr(const char *c) {
- int x=0;
- while (c[x]!=0) {
- panicPutChar(c[x]);
- x++;
- }
+inline static void panicPutStr(const char *c)
+{
+ int x = 0;
+ while (c[x] != 0) {
+ panicPutChar(c[x]);
+ x++;
+ }
}
-inline static void panicPutHex(int a) {
- int x;
- int c;
- for (x=0; x<8; x++) {
- c=(a>>28)&0xf;
- if (c<10) panicPutChar('0'+c); else panicPutChar('a'+c-10);
- a<<=4;
- }
+inline static void panicPutHex(int a)
+{
+ int x;
+ int c;
+ for (x = 0; x < 8; x++) {
+ c = (a >> 28) & 0xf;
+ if (c < 10) {
+ panicPutChar('0' + c);
+ } else {
+ panicPutChar('a' + c - 10);
+ }
+ a <<= 4;
+ }
}
-inline static void panicPutDec(int a) {
- int n1, n2;
- n1=a%10;
- n2=a/10;
- if (n2==0) panicPutChar(' '); else panicPutChar(n2+'0');
- panicPutChar(n1+'0');
+inline static void panicPutDec(int a)
+{
+ int n1, n2;
+ n1 = a % 10;
+ n2 = a / 10;
+ if (n2 == 0) {
+ panicPutChar(' ');
+ } else {
+ panicPutChar(n2 + '0');
+ }
+ panicPutChar(n1 + '0');
}
#else
//No printing wanted. Stub out these functions.
#endif
-void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) {
- panicPutStr("***ERROR*** A stack overflow in task ");
- panicPutStr((char*)pcTaskName);
- panicPutStr(" has been detected.\r\n");
- configASSERT(0);
+void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
+{
+ panicPutStr("***ERROR*** A stack overflow in task ");
+ panicPutStr((char *)pcTaskName);
+ panicPutStr(" has been detected.\r\n");
+ configASSERT(0);
}
-static const char *edesc[]={
- "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
- "Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
- "Privileged", "LoadStoreAlignment", "res", "res",
- "InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
- "InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
- "InstrFetchProhibited", "res", "res", "res",
- "LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
- "LoadProhibited", "StoreProhibited", "res", "res",
- "Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
- "Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
- };
+static const char *edesc[] = {
+ "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
+ "Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
+ "Privileged", "LoadStoreAlignment", "res", "res",
+ "InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
+ "InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
+ "InstrFetchProhibited", "res", "res", "res",
+ "LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
+ "LoadProhibited", "StoreProhibited", "res", "res",
+ "Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
+ "Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
+};
void commonErrorHandler(XtExcFrame *frame);
}
//Returns true when a debugger is attached using JTAG.
-static int inOCDMode() {
+static int inOCDMode()
+{
#if CONFIG_ESP32_DEBUG_OCDAWARE
- int dcr;
- int reg=0x10200C; //DSRSET register
- asm("rer %0,%1":"=r"(dcr):"r"(reg));
- return (dcr&0x1);
+ int dcr;
+ int reg = 0x10200C; //DSRSET register
+ asm("rer %0,%1":"=r"(dcr):"r"(reg));
+ return (dcr & 0x1);
#else
- return 0; //Always return no debugger is attached.
+ return 0; //Always return no debugger is attached.
#endif
}
-void panicHandler(XtExcFrame *frame) {
- int *regs=(int*)frame;
- //Please keep in sync with PANIC_RSN_* defines
- const char *reasons[]={
- "Unknown reason",
- "Unhandled debug exception",
- "Double exception",
- "Unhandled kernel exception",
- "Coprocessor exception",
- "Interrupt wdt timeout on CPU0",
- "Interrupt wdt timeout on CPU1",
- };
- const char *reason=reasons[0];
- //The panic reason is stored in the EXCCAUSE register.
- if (regs[20]<=PANIC_RSN_MAX) reason=reasons[regs[20]];
- haltOtherCore();
- panicPutStr("Guru Meditation Error: Core ");
- panicPutDec(xPortGetCoreID());
- panicPutStr(" panic'ed (");
- panicPutStr(reason);
- panicPutStr(")\r\n");
-
- if (inOCDMode()) {
- asm("break.n 1");
- }
- commonErrorHandler(frame);
+void panicHandler(XtExcFrame *frame)
+{
+ int *regs = (int *)frame;
+ //Please keep in sync with PANIC_RSN_* defines
+ const char *reasons[] = {
+ "Unknown reason",
+ "Unhandled debug exception",
+ "Double exception",
+ "Unhandled kernel exception",
+ "Coprocessor exception",
+ "Interrupt wdt timeout on CPU0",
+ "Interrupt wdt timeout on CPU1",
+ };
+ const char *reason = reasons[0];
+ //The panic reason is stored in the EXCCAUSE register.
+ if (regs[20] <= PANIC_RSN_MAX) {
+ reason = reasons[regs[20]];
+ }
+ haltOtherCore();
+ panicPutStr("Guru Meditation Error: Core ");
+ panicPutDec(xPortGetCoreID());
+ panicPutStr(" panic'ed (");
+ panicPutStr(reason);
+ panicPutStr(")\r\n");
+
+ if (inOCDMode()) {
+ asm("break.n 1");
+ }
+ commonErrorHandler(frame);
}
-static void setFirstBreakpoint(uint32_t pc) {
- asm(
- "wsr.ibreaka0 %0\n" \
- "rsr.ibreakenable a3\n" \
- "movi a4,1\n" \
- "or a4, a4, a3\n" \
- "wsr.ibreakenable a4\n" \
- ::"r"(pc):"a3","a4");
+static void setFirstBreakpoint(uint32_t pc)
+{
+ asm(
+ "wsr.ibreaka0 %0\n" \
+ "rsr.ibreakenable a3\n" \
+ "movi a4,1\n" \
+ "or a4, a4, a3\n" \
+ "wsr.ibreakenable a4\n" \
+ ::"r"(pc):"a3", "a4");
}
-void xt_unhandled_exception(XtExcFrame *frame) {
- int *regs=(int*)frame;
- int x;
-
- haltOtherCore();
- panicPutStr("Guru Meditation Error of type ");
- x=regs[20];
- if (x<40) panicPutStr(edesc[x]); else panicPutStr("Unknown");
- panicPutStr(" occurred on core ");
- panicPutDec(xPortGetCoreID());
- if (inOCDMode()) {
- panicPutStr(" at pc=");
- panicPutHex(regs[1]);
- panicPutStr(". Setting bp and returning..\r\n");
- //Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger
- //will kick in exactly at the context the error happened.
- setFirstBreakpoint(regs[1]);
- return;
- }
- panicPutStr(". Exception was unhandled.\r\n");
- commonErrorHandler(frame);
+void xt_unhandled_exception(XtExcFrame *frame)
+{
+ int *regs = (int *)frame;
+ int x;
+
+ haltOtherCore();
+ panicPutStr("Guru Meditation Error of type ");
+ x = regs[20];
+ if (x < 40) {
+ panicPutStr(edesc[x]);
+ } else {
+ panicPutStr("Unknown");
+ }
+ panicPutStr(" occurred on core ");
+ panicPutDec(xPortGetCoreID());
+ if (inOCDMode()) {
+ panicPutStr(" at pc=");
+ panicPutHex(regs[1]);
+ panicPutStr(". Setting bp and returning..\r\n");
+ //Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger
+ //will kick in exactly at the context the error happened.
+ setFirstBreakpoint(regs[1]);
+ return;
+ }
+ panicPutStr(". Exception was unhandled.\r\n");
+ commonErrorHandler(frame);
}
/*
-If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
-an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
-the risk of somehow halting in the panic handler and not resetting. That is why this routine kills
-all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
-one second.
+ If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
+ an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
+ the risk of somehow halting in the panic handler and not resetting. That is why this routine kills
+ all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
+ one second.
*/
-static void reconfigureAllWdts() {
- TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
- TIMERG0.wdt_feed=1;
- TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
- TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS
- TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system
- TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
- TIMERG0.wdt_config2=2000; //1 second before reset
- TIMERG0.wdt_config0.en=1;
- TIMERG0.wdt_wprotect=0;
- //Disable wdt 1
- TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
- TIMERG1.wdt_config0.en=0;
- TIMERG1.wdt_wprotect=0;
+static void reconfigureAllWdts()
+{
+ TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
+ TIMERG0.wdt_feed = 1;
+ TIMERG0.wdt_config0.sys_reset_length = 7; //3.2uS
+ TIMERG0.wdt_config0.cpu_reset_length = 7; //3.2uS
+ TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system
+ TIMERG0.wdt_config1.clk_prescale = 80 * 500; //Prescaler: wdt counts in ticks of 0.5mS
+ TIMERG0.wdt_config2 = 2000; //1 second before reset
+ TIMERG0.wdt_config0.en = 1;
+ TIMERG0.wdt_wprotect = 0;
+ //Disable wdt 1
+ TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
+ TIMERG1.wdt_config0.en = 0;
+ TIMERG1.wdt_wprotect = 0;
}
#if CONFIG_ESP32_PANIC_GDBSTUB || CONFIG_ESP32_PANIC_PRINT_HALT
/*
-This disables all the watchdogs for when we call the gdbstub.
+ This disables all the watchdogs for when we call the gdbstub.
*/
-static void disableAllWdts() {
- TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
- TIMERG0.wdt_config0.en=0;
- TIMERG0.wdt_wprotect=0;
- TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
- TIMERG1.wdt_config0.en=0;
- TIMERG0.wdt_wprotect=0;
+static void disableAllWdts()
+{
+ TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
+ TIMERG0.wdt_config0.en = 0;
+ TIMERG0.wdt_wprotect = 0;
+ TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
+ TIMERG1.wdt_config0.en = 0;
+ TIMERG0.wdt_wprotect = 0;
}
#endif
-static inline bool stackPointerIsSane(uint32_t sp) {
- return !(sp < 0x3ffae010 || sp > 0x3ffffff0 || ((sp & 0xf) != 0));
+static inline bool stackPointerIsSane(uint32_t sp)
+{
+ return !(sp < 0x3ffae010 || sp > 0x3ffffff0 || ((sp & 0xf) != 0));
}
-static void putEntry(uint32_t pc, uint32_t sp) {
- if (pc & 0x80000000) pc = (pc & 0x3fffffff) | 0x40000000;
- panicPutStr(" 0x");
- panicPutHex(pc);
- panicPutStr(":0x");
- panicPutHex(sp);
+static void putEntry(uint32_t pc, uint32_t sp)
+{
+ if (pc & 0x80000000) {
+ pc = (pc & 0x3fffffff) | 0x40000000;
+ }
+ panicPutStr(" 0x");
+ panicPutHex(pc);
+ panicPutStr(":0x");
+ panicPutHex(sp);
}
-void doBacktrace(XtExcFrame *frame) {
- uint32_t i = 0, pc = frame->pc, sp = frame->a1;
- panicPutStr("\nBacktrace:");
- /* Do not check sanity on first entry, PC could be smashed. */
- putEntry(pc, sp);
- pc = frame->a0;
- while (i++ < 100) {
- uint32_t psp = sp;
- if (!stackPointerIsSane(sp) || i++ > 100) break;
- sp = *((uint32_t *) (sp - 0x10 + 4));
- putEntry(pc, sp);
- pc = *((uint32_t *) (psp - 0x10));
- if (pc < 0x40000000) break;
- }
- panicPutStr("\n\n");
+void doBacktrace(XtExcFrame *frame)
+{
+ uint32_t i = 0, pc = frame->pc, sp = frame->a1;
+ panicPutStr("\nBacktrace:");
+ /* Do not check sanity on first entry, PC could be smashed. */
+ putEntry(pc, sp);
+ pc = frame->a0;
+ while (i++ < 100) {
+ uint32_t psp = sp;
+ if (!stackPointerIsSane(sp) || i++ > 100) {
+ break;
+ }
+ sp = *((uint32_t *) (sp - 0x10 + 4));
+ putEntry(pc, sp);
+ pc = *((uint32_t *) (psp - 0x10));
+ if (pc < 0x40000000) {
+ break;
+ }
+ }
+ panicPutStr("\n\n");
}
/*
-We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
-serial port and either jump to the gdb stub, halt the CPU or reboot.
+ We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
+ serial port and either jump to the gdb stub, halt the CPU or reboot.
*/
-void commonErrorHandler(XtExcFrame *frame) {
- int *regs=(int*)frame;
- int x, y;
- const char *sdesc[]={
- "PC ","PS ","A0 ","A1 ","A2 ","A3 ","A4 ","A5 ",
- "A6 ","A7 ","A8 ","A9 ","A10 ","A11 ","A12 ","A13 ",
- "A14 ","A15 ","SAR ","EXCCAUSE","EXCVADDR","LBEG ","LEND ","LCOUNT "};
-
- //Feed the watchdogs, so they will give us time to print out debug info
- reconfigureAllWdts();
-
- panicPutStr("Register dump:\r\n");
-
- for (x=0; x<24; x+=4) {
- for (y=0; y<4; y++) {
- if (sdesc[x+y][0]!=0) {
- panicPutStr(sdesc[x+y]);
- panicPutStr(": 0x");
- panicPutHex(regs[x+y+1]);
- panicPutStr(" ");
- }
- }
- panicPutStr("\r\n");
- }
- /* With windowed ABI backtracing is easy, let's do it. */
- doBacktrace(frame);
+void commonErrorHandler(XtExcFrame *frame)
+{
+ int *regs = (int *)frame;
+ int x, y;
+ const char *sdesc[] = {
+ "PC ", "PS ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ",
+ "A6 ", "A7 ", "A8 ", "A9 ", "A10 ", "A11 ", "A12 ", "A13 ",
+ "A14 ", "A15 ", "SAR ", "EXCCAUSE", "EXCVADDR", "LBEG ", "LEND ", "LCOUNT "
+ };
+
+ //Feed the watchdogs, so they will give us time to print out debug info
+ reconfigureAllWdts();
+
+ panicPutStr("Register dump:\r\n");
+
+ for (x = 0; x < 24; x += 4) {
+ for (y = 0; y < 4; y++) {
+ if (sdesc[x + y][0] != 0) {
+ panicPutStr(sdesc[x + y]);
+ panicPutStr(": 0x");
+ panicPutHex(regs[x + y + 1]);
+ panicPutStr(" ");
+ }
+ }
+ panicPutStr("\r\n");
+ }
+ /* With windowed ABI backtracing is easy, let's do it. */
+ doBacktrace(frame);
#if CONFIG_ESP32_PANIC_GDBSTUB
- disableAllWdts();
- panicPutStr("Entering gdb stub now.\r\n");
- esp_gdbstub_panic_handler(frame);
+ disableAllWdts();
+ panicPutStr("Entering gdb stub now.\r\n");
+ esp_gdbstub_panic_handler(frame);
#elif CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
- panicPutStr("Rebooting...\r\n");
- for (x=0; x<100; x++) ets_delay_us(1000);
- software_reset();
+ panicPutStr("Rebooting...\r\n");
+ for (x = 0; x < 100; x++) {
+ ets_delay_us(1000);
+ }
+ software_reset();
#else
- disableAllWdts();
- panicPutStr("CPU halted.\r\n");
- while(1);
+ disableAllWdts();
+ panicPutStr("CPU halted.\r\n");
+ while (1);
#endif
}
-void esp_set_breakpoint_if_jtag(void *fn) {
- if (!inOCDMode()) return;
- setFirstBreakpoint((uint32_t)fn);
+void esp_set_breakpoint_if_jtag(void *fn)
+{
+ if (!inOCDMode()) {
+ return;
+ }
+ setFirstBreakpoint((uint32_t)fn);
}