| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include <stdlib.h>
- #include <xtensa/config/core.h>
- #include "rom/rtc.h"
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "freertos/xtensa_api.h"
- #include "soc/uart_reg.h"
- #include "soc/io_mux_reg.h"
- #include "soc/dport_reg.h"
- #include "soc/rtc_cntl_reg.h"
- #include "soc/timer_group_struct.h"
- #include "soc/timer_group_reg.h"
- #include "soc/cpu.h"
- #include "esp_gdbstub.h"
- #include "esp_panic.h"
- #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.
- */
- /*
- 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 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;
- panicPutchar(' ');
- 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;
- panicPutchar(' ');
- if (n2==0) panicPutchar(' '); else panicPutchar(n2+'0');
- panicPutchar(n1+'0');
- }
- #else
- //No printing wanted. Stub out these functions.
- inline static void panicPutchar(char c) { }
- inline static void panicPutStr(const char *c) { }
- inline static void panicPutHex(int a) { }
- inline static void panicPutDec(int a) { }
- #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);
- }
- 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);
- //The fact that we've panic'ed probably means the other CPU is now running wild, possibly
- //messing up the serial output, so we stall it here.
- static void haltOtherCore()
- {
- esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 );
- }
- //Returns true when a debugger is attached using JTAG.
- 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);
- #else
- 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);
- }
- 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);
- }
- /*
- 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;
- }
- #if CONFIG_ESP32_PANIC_GDBSTUB || CONFIG_ESP32_PANIC_PRINT_HALT
- /*
- 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;
- }
- #endif
- /*
- 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(": ");
- panicPutHex(regs[x+y+1]);
- panicPutStr(" ");
- }
- }
- panicPutStr("\r\n");
- }
- #if CONFIG_ESP32_PANIC_GDBSTUB
- 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();
- #else
- disableAllWdts();
- panicPutStr("CPU halted.\r\n");
- while(1);
- #endif
- }
- void esp_set_breakpoint_if_jtag(void *fn) {
- if (!inOCDMode()) return;
- setFirstBreakpoint((uint32_t)fn);
- }
|