diff --git a/Kconfig b/Kconfig index e2f659e48c..b428f059fc 100644 --- a/Kconfig +++ b/Kconfig @@ -133,7 +133,7 @@ mainmenu "Espressif IoT Development Framework Configuration" CONFIG_APP_BUILD_TYPE_ELF_RAM=y CONFIG_VFS_SUPPORT_TERMIOS= CONFIG_NEWLIB_NANO_FORMAT=y - CONFIG_ESP32_PANIC_PRINT_HALT=y + CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y CONFIG_ESP32_DEBUG_STUBS_ENABLE= CONFIG_ESP_ERR_TO_NAME_LOOKUP= diff --git a/components/bootloader_support/src/esp32/bootloader_esp32.c b/components/bootloader_support/src/esp32/bootloader_esp32.c index 6a06d8cd14..b5d2149768 100644 --- a/components/bootloader_support/src/esp32/bootloader_esp32.c +++ b/components/bootloader_support/src/esp32/bootloader_esp32.c @@ -414,7 +414,7 @@ static void bootloader_check_wdt_reset(void) void abort(void) { -#if !CONFIG_ESP32_PANIC_SILENT_REBOOT +#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT ets_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3); #endif if (esp_cpu_in_ocd_debug_mode()) { diff --git a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c index 2a26524375..972c9bfd24 100644 --- a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c +++ b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c @@ -330,7 +330,7 @@ static void bootloader_check_wdt_reset(void) void abort(void) { -#if !CONFIG_ESP32S2_PANIC_SILENT_REBOOT +#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT ets_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3); #endif if (esp_cpu_in_ocd_debug_mode()) { diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index ed15a774f0..269ca70204 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -18,12 +18,10 @@ else() "cpu_start.c" "crosscore_int.c" "dport_access.c" - "dport_panic_highint_hdl.S" "esp_himem.c" "hw_random.c" "int_wdt.c" "intr_alloc.c" - "panic.c" "pm_esp32.c" "pm_trace.c" "reset_reason.c" diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 3cac1cc543..eb898326d3 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -356,38 +356,6 @@ menu "ESP32-specific" Data is reserved at the beginning of RTC slow memory. - choice ESP32_PANIC - prompt "Panic handler behaviour" - default ESP32_PANIC_PRINT_REBOOT - help - If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is - invoked. Configure the panic handlers action here. - - config ESP32_PANIC_PRINT_HALT - bool "Print registers and halt" - help - Outputs the relevant registers over the serial port and halt the - processor. Needs a manual reset to restart. - - config ESP32_PANIC_PRINT_REBOOT - bool "Print registers and reboot" - help - Outputs the relevant registers over the serial port and immediately - reset the processor. - - config ESP32_PANIC_SILENT_REBOOT - bool "Silent reboot" - help - Just resets the processor without outputting anything - - config ESP32_PANIC_GDBSTUB - bool "Invoke GDBStub" - select ESP_GDBSTUB_ENABLED - help - Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem - of the crash. - endchoice - config ESP32_DEBUG_OCDAWARE bool "Make exception and panic handlers JTAG/OCD aware" default y diff --git a/components/esp32/linker.lf b/components/esp32/linker.lf index db73d2dc9f..cd39081acd 100644 --- a/components/esp32/linker.lf +++ b/components/esp32/linker.lf @@ -1,8 +1,3 @@ -[mapping:esp32] -archive: libesp32.a -entries: - panic (noflash) - [mapping:gcc] archive: libgcc.a entries: diff --git a/components/esp32/panic.c b/components/esp32/panic.c deleted file mode 100644 index cbf7090a30..0000000000 --- a/components/esp32/panic.c +++ /dev/null @@ -1,688 +0,0 @@ -// 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 - -#include - -#include "esp32/rom/rtc.h" -#include "esp32/rom/uart.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/xtensa_api.h" - -#include "soc/uart_periph.h" -#include "soc/gpio_periph.h" -#include "soc/dport_reg.h" -#include "soc/rtc_periph.h" -#include "soc/timer_periph.h" -#include "soc/cpu.h" -#include "soc/rtc.h" -#include "soc/rtc_wdt.h" -#include "soc/soc_memory_layout.h" - -#include "esp_private/gdbstub.h" -#include "esp_debug_helpers.h" -#include "esp_private/panic_reason.h" -#include "esp_attr.h" -#include "esp_err.h" -#include "esp_core_dump.h" -#include "esp_spi_flash.h" -#include "esp32/cache_err_int.h" -#include "esp_app_trace.h" -#include "esp_private/system_internal.h" -#include "sdkconfig.h" -#include "esp_ota_ops.h" -#include "driver/timer.h" -#include "hal/timer_ll.h" -#if CONFIG_SYSVIEW_ENABLE -#include "SEGGER_RTT.h" -#endif - -#if CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO == -1 -#define APPTRACE_ONPANIC_HOST_FLUSH_TMO ESP_APPTRACE_TMO_INFINITE -#else -#define APPTRACE_ONPANIC_HOST_FLUSH_TMO (1000*CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO) -#endif -/* - 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 and abort handler are also 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... -static void panicPutChar(char c) -{ - while (((READ_PERI_REG(UART_STATUS_REG(CONFIG_ESP_CONSOLE_UART_NUM)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT) >= 126) ; - WRITE_PERI_REG(UART_FIFO_REG(CONFIG_ESP_CONSOLE_UART_NUM), c); -} - -static void panicPutStr(const char *c) -{ - int x = 0; - while (c[x] != 0) { - panicPutChar(c[x]); - x++; - } -} - -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; - } -} - -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. -static void panicPutChar(char c) { } -static void panicPutStr(const char *c) { } -static void panicPutHex(int a) { } -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"); - abort(); -} - -/* These two weak stubs for esp_reset_reason_{get,set}_hint are used when - * the application does not call esp_reset_reason() function, and - * reset_reason.c is not linked into the output file. - */ -void __attribute__((weak)) esp_reset_reason_set_hint(esp_reset_reason_t hint) -{ -} - -esp_reset_reason_t __attribute__((weak)) esp_reset_reason_get_hint(void) -{ - return ESP_RST_UNKNOWN; -} - - -static bool abort_called; - -static __attribute__((noreturn)) inline void invoke_abort(void) -{ - abort_called = true; -#if CONFIG_APPTRACE_ENABLE -#if CONFIG_SYSVIEW_ENABLE - SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#endif -#endif - while (1) { - if (esp_cpu_in_ocd_debug_mode()) { - __asm__ ("break 0,0"); - } - *((int *) 0) = 0; - } -} - -void abort(void) -{ -#if !CONFIG_ESP32_PANIC_SILENT_REBOOT - ets_printf("abort() was called at PC 0x%08x on core %d\r\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID()); -#endif - /* Calling code might have set other reset reason hint (such as Task WDT), - * don't overwrite that. - */ - if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) { - esp_reset_reason_set_hint(ESP_RST_PANIC); - } - invoke_abort(); -} - - -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" -}; - -#define NUM_EDESCS (sizeof(edesc) / sizeof(char *)) - -static void commonErrorHandler(XtExcFrame *frame); -static inline void disableAllWdts(void); -static void illegal_instruction_helper(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(void) -{ - esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 ); -} - - -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"); -} - -//When interrupt watchdog happen in one core, both cores will be interrupted. -//The core which doesn't trigger the interrupt watchdog will save the frame and return. -//The core which triggers the interrupt watchdog will use the saved frame, and dump frames for both cores. -#if !CONFIG_FREERTOS_UNICORE -static volatile XtExcFrame * other_core_frame = NULL; -#endif //!CONFIG_FREERTOS_UNICORE - -void panicHandler(XtExcFrame *frame) -{ - int core_id = xPortGetCoreID(); - //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", - "Cache disabled but cached memory region accessed", - }; - const char *reason = reasons[0]; - //The panic reason is stored in the EXCCAUSE register. - if (frame->exccause <= PANIC_RSN_MAX) { - reason = reasons[frame->exccause]; - } - -#if !CONFIG_FREERTOS_UNICORE - //Save frame for other core. - if ((frame->exccause == PANIC_RSN_INTWDT_CPU0 && core_id == 1) || (frame->exccause == PANIC_RSN_INTWDT_CPU1 && core_id == 0)) { - other_core_frame = frame; - while (1); - } - - //The core which triggers the interrupt watchdog will delay 1 us, so the other core can save its frame. - if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || frame->exccause == PANIC_RSN_INTWDT_CPU1) { - ets_delay_us(1); - } - - if (frame->exccause == PANIC_RSN_CACHEERR && esp_cache_err_get_cpuid() != core_id) { - // Cache error interrupt will be handled by the panic handler - // on the other CPU. - while (1); - } -#endif //!CONFIG_FREERTOS_UNICORE - - if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || frame->exccause == PANIC_RSN_INTWDT_CPU1) { - esp_reset_reason_set_hint(ESP_RST_INT_WDT); - } - - haltOtherCore(); - esp_dport_access_int_abort(); - panicPutStr("Guru Meditation Error: Core "); - panicPutDec(core_id); - panicPutStr(" panic'ed ("); - panicPutStr(reason); - panicPutStr(")\r\n"); - if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) { - int debugRsn; - asm("rsr.debugcause %0":"=r"(debugRsn)); - panicPutStr("Debug exception reason: "); - if (debugRsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) { - panicPutStr("SingleStep "); - } - if (debugRsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) { - panicPutStr("HwBreakpoint "); - } - if (debugRsn & XCHAL_DEBUGCAUSE_DBREAK_MASK) { - //Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK - //reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the - //debugcause if the cause is watchdog 1 and clearing it if it's watchdog 0. - if (debugRsn & (1 << 8)) { -#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK - const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core_id)); - panicPutStr("Stack canary watchpoint triggered ("); - panicPutStr(name); - panicPutStr(") "); -#else - panicPutStr("Watchpoint 1 triggered "); -#endif - } else { - panicPutStr("Watchpoint 0 triggered "); - } - } - if (debugRsn & XCHAL_DEBUGCAUSE_BREAK_MASK) { - panicPutStr("BREAK instr "); - } - if (debugRsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) { - panicPutStr("BREAKN instr "); - } - if (debugRsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) { - panicPutStr("DebugIntr "); - } - panicPutStr("\r\n"); - } - - if (esp_cpu_in_ocd_debug_mode()) { - disableAllWdts(); - if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || - frame->exccause == PANIC_RSN_INTWDT_CPU1) { - timer_ll_wdt_clear_intr_status(&TIMERG1); - } -#if CONFIG_APPTRACE_ENABLE -#if CONFIG_SYSVIEW_ENABLE - SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#endif -#endif - setFirstBreakpoint(frame->pc); - return; - } - commonErrorHandler(frame); -} - -void xt_unhandled_exception(XtExcFrame *frame) -{ - haltOtherCore(); - esp_dport_access_int_abort(); - if (!abort_called) { - panicPutStr("Guru Meditation Error: Core "); - panicPutDec(xPortGetCoreID()); - panicPutStr(" panic'ed ("); - int exccause = frame->exccause; - if (exccause < NUM_EDESCS) { - panicPutStr(edesc[exccause]); - } else { - panicPutStr("Unknown"); - } - panicPutStr(")"); - if (esp_cpu_in_ocd_debug_mode()) { - panicPutStr(" at pc="); - panicPutHex(frame->pc); - panicPutStr(". Setting bp and returning..\r\n"); -#if CONFIG_APPTRACE_ENABLE -#if CONFIG_SYSVIEW_ENABLE - SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#endif -#endif - //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(frame->pc); - return; - } - panicPutStr(". Exception was unhandled.\r\n"); - if (exccause == 0 /* IllegalInstruction */) { - illegal_instruction_helper(frame); - } - esp_reset_reason_set_hint(ESP_RST_PANIC); - } - commonErrorHandler(frame); -} - -static void illegal_instruction_helper(XtExcFrame *frame) -{ - /* Print out memory around the instruction word */ - uint32_t epc = frame->pc; - epc = (epc & ~0x3) - 4; - - /* check that the address was sane */ - if (epc < SOC_IROM_MASK_LOW || epc >= SOC_IROM_HIGH) { - return; - } - volatile uint32_t* pepc = (uint32_t*)epc; - - panicPutStr("Memory dump at 0x"); - panicPutHex(epc); - panicPutStr(": "); - - panicPutHex(*pepc); - panicPutStr(" "); - panicPutHex(*(pepc + 1)); - panicPutStr(" "); - panicPutHex(*(pepc + 2)); - panicPutStr("\r\n"); -} - -/* - 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(void) -{ - timer_ll_wdt_set_protect(&TIMERG0, false); - timer_ll_wdt_feed(&TIMERG0); - timer_ll_wdt_init(&TIMERG0); - timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US - //1st stage timeout: reset system - timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_RESET_SYSTEM); - //1 second before reset - timer_ll_wdt_set_timeout(&TIMERG0, 0, 1000*1000/TG0_WDT_TICK_US); - timer_ll_wdt_set_enable(&TIMERG0, true); - timer_ll_wdt_set_protect(&TIMERG0, true); - - //Disable wdt 1 - timer_ll_wdt_set_protect(&TIMERG1, false); - timer_ll_wdt_set_enable(&TIMERG1, false); - timer_ll_wdt_set_protect(&TIMERG1, true); -} - -/* - This disables all the watchdogs for when we call the gdbstub. -*/ -static inline void disableAllWdts(void) -{ - timer_ll_wdt_set_protect(&TIMERG0, false); - timer_ll_wdt_set_enable(&TIMERG0, false); - timer_ll_wdt_set_protect(&TIMERG0, true); - - timer_ll_wdt_set_protect(&TIMERG1, false); - timer_ll_wdt_set_enable(&TIMERG1, false); - timer_ll_wdt_set_protect(&TIMERG1, true); -} - -#if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT -static void esp_panic_dig_reset(void) __attribute__((noreturn)); - -static void esp_panic_dig_reset(void) -{ - // make sure all the panic handler output is sent from UART FIFO - uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); - // switch to XTAL (otherwise we will keep running from the PLL) - rtc_clk_cpu_freq_set_xtal(); - // reset the digital part - esp_cpu_unstall(PRO_CPU_NUM); - SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); - while (true) { - ; - } -} -#endif // CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT - -static void putEntry(uint32_t pc, uint32_t sp) -{ - panicPutStr(" 0x"); - panicPutHex(pc); - panicPutStr(":0x"); - panicPutHex(sp); -} - -static void doBacktrace(XtExcFrame *exc_frame, int depth) -{ - //Initialize stk_frame with first frame of stack - esp_backtrace_frame_t stk_frame = {.pc = exc_frame->pc, .sp = exc_frame->a1, .next_pc = exc_frame->a0}; - panicPutStr("\r\nBacktrace:"); - putEntry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); - - //Check if first frame is valid - bool corrupted = (esp_stack_ptr_is_sane(stk_frame.sp) && - esp_ptr_executable((void*)esp_cpu_process_stack_pc(stk_frame.pc))) ? - false : true; - uint32_t i = ((depth <= 0) ? INT32_MAX : depth) - 1; //Account for stack frame that's already printed - while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) { - if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get next stack frame - corrupted = true; - } - putEntry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); - } - - //Print backtrace termination marker - if (corrupted) { - panicPutStr(" |<-CORRUPTED"); - } else if (stk_frame.next_pc != 0) { //Backtrace continues - panicPutStr(" |<-CONTINUES"); - } - panicPutStr("\r\n"); -} - -/* - * Dump registers and do backtrace. - */ -static void commonErrorHandler_dump(XtExcFrame *frame, int core_id) -{ - 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 " - }; - - /* only dump registers for 'real' crashes, if crashing via abort() - the register window is no longer useful. - */ - if (!abort_called) { - panicPutStr("Core"); - panicPutDec(core_id); - 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"); - } - - if (xPortInterruptedFromISRContext() -#if !CONFIG_FREERTOS_UNICORE - && other_core_frame != frame -#endif //!CONFIG_FREERTOS_UNICORE - ) { - //If the core which triggers the interrupt watchdog was in ISR context, dump the epc registers. - uint32_t __value; - panicPutStr("Core"); - panicPutDec(core_id); - panicPutStr(" was running in ISR context:\r\n"); - - __asm__("rsr.epc1 %0" : "=a"(__value)); - panicPutStr("EPC1 : 0x"); - panicPutHex(__value); - - __asm__("rsr.epc2 %0" : "=a"(__value)); - panicPutStr(" EPC2 : 0x"); - panicPutHex(__value); - - __asm__("rsr.epc3 %0" : "=a"(__value)); - panicPutStr(" EPC3 : 0x"); - panicPutHex(__value); - - __asm__("rsr.epc4 %0" : "=a"(__value)); - panicPutStr(" EPC4 : 0x"); - panicPutHex(__value); - - panicPutStr("\r\n"); - } - - } - - panicPutStr("\r\nELF file SHA256: "); - char sha256_buf[65]; - esp_ota_get_app_elf_sha256(sha256_buf, sizeof(sha256_buf)); - panicPutStr(sha256_buf); - panicPutStr("\r\n"); - - /* With windowed ABI backtracing is easy, let's do it. */ - doBacktrace(frame, 100); - - panicPutStr("\r\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. -*/ -static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame) -{ - - int core_id = xPortGetCoreID(); - // start panic WDT to restart system if we hang in this handler - if (!rtc_wdt_is_on()) { - rtc_wdt_protect_off(); - rtc_wdt_disable(); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM); - // 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data. - // @ 115200 UART speed it will take more than 6 sec to print them out. - rtc_wdt_set_time(RTC_WDT_STAGE0, 7000); - rtc_wdt_enable(); - rtc_wdt_protect_on(); - } - - //Feed the watchdogs, so they will give us time to print out debug info - reconfigureAllWdts(); - - commonErrorHandler_dump(frame, core_id); -#if !CONFIG_FREERTOS_UNICORE - if (other_core_frame != NULL) { - commonErrorHandler_dump((XtExcFrame *)other_core_frame, (core_id ? 0 : 1)); - } -#endif //!CONFIG_FREERTOS_UNICORE - -#if CONFIG_APPTRACE_ENABLE - disableAllWdts(); -#if CONFIG_SYSVIEW_ENABLE - SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#endif - reconfigureAllWdts(); -#endif - -#if !CONFIG_ESP_PANIC_HANDLER_IRAM - // Re-enable CPU cache for current CPU if it was disabled - if (!spi_flash_cache_enabled()) { - spi_flash_enable_cache(core_id); - panicPutStr("Re-enable cpu cache.\r\n"); - } -#endif - -#if CONFIG_ESP32_PANIC_GDBSTUB - disableAllWdts(); - rtc_wdt_disable(); - panicPutStr("Entering gdb stub now.\r\n"); - esp_gdbstub_panic_handler(frame); -#else -#if CONFIG_ESP32_ENABLE_COREDUMP - static bool s_dumping_core; - if (s_dumping_core) { - panicPutStr("Re-entered core dump! Exception happened during core dump!\r\n"); - } else { - disableAllWdts(); - s_dumping_core = true; -#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH - esp_core_dump_to_flash(frame); -#endif -#if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART && !CONFIG_ESP32_PANIC_SILENT_REBOOT - esp_core_dump_to_uart(frame); -#endif - s_dumping_core = false; - reconfigureAllWdts(); - } -#endif /* CONFIG_ESP32_ENABLE_COREDUMP */ - rtc_wdt_disable(); -#if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT - panicPutStr("Rebooting...\r\n"); - if (esp_cache_err_get_cpuid() == -1) { - esp_restart_noos(); - } else { - // The only way to clear invalid cache access interrupt is to reset the digital part - esp_panic_dig_reset(); - } -#else - disableAllWdts(); - panicPutStr("CPU halted.\r\n"); - while (1); -#endif /* CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT */ -#endif /* CONFIG_ESP32_PANIC_GDBSTUB */ -} - - -void esp_set_breakpoint_if_jtag(void *fn) -{ - if (esp_cpu_in_ocd_debug_mode()) { - setFirstBreakpoint((uint32_t)fn); - } -} - -static void esp_error_check_failed_print(const char *msg, esp_err_t rc, const char *file, int line, const char *function, const char *expression) -{ - ets_printf("%s failed: esp_err_t 0x%x", msg, rc); -#ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP - ets_printf(" (%s)", esp_err_to_name(rc)); -#endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP - ets_printf(" at 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3); - if (spi_flash_cache_enabled()) { // strings may be in flash cache - ets_printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression); - } -} - -void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int line, const char *function, const char *expression) -{ - esp_error_check_failed_print("ESP_ERROR_CHECK_WITHOUT_ABORT", rc, file, line, function, expression); -} - -void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) -{ - esp_error_check_failed_print("ESP_ERROR_CHECK", rc, file, line, function, expression); - invoke_abort(); -} diff --git a/components/esp32/system_api_esp32.c b/components/esp32/system_api_esp32.c index 019bb5e0d0..504da1dda5 100644 --- a/components/esp32/system_api_esp32.c +++ b/components/esp32/system_api_esp32.c @@ -34,6 +34,13 @@ #include "hal/timer_ll.h" #include "freertos/xtensa_api.h" +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/cache_err_int.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/cache_err_int.h" +#endif + + /* "inner" restart function for after RTOS, interrupts & anything else on this * core are already stopped. Stalls other core, resets hardware, * triggers restart. @@ -94,10 +101,10 @@ void IRAM_ATTR esp_restart_noos(void) // Reset wifi/bluetooth/ethernet/sdio (bb/mac) DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, - DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | - DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST | - DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | - DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST); + DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST | + DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST | + DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | + DPORT_RW_BTMAC_RST | DPORT_RW_BTLP_RST); DPORT_REG_WRITE(DPORT_CORE_RST_EN_REG, 0); // Reset timer/spi/uart diff --git a/components/esp32s2/CMakeLists.txt b/components/esp32s2/CMakeLists.txt index 940e8d1c9b..ff6d7038c5 100644 --- a/components/esp32s2/CMakeLists.txt +++ b/components/esp32s2/CMakeLists.txt @@ -16,11 +16,9 @@ else() "cpu_start.c" "crosscore_int.c" "dport_access.c" - "dport_panic_highint_hdl.S" "hw_random.c" "int_wdt.c" "intr_alloc.c" - "panic.c" "pm_esp32s2.c" "pm_trace.c" "reset_reason.c" diff --git a/components/esp32s2/Kconfig b/components/esp32s2/Kconfig index abdaef4a8f..d09bd906e9 100644 --- a/components/esp32s2/Kconfig +++ b/components/esp32s2/Kconfig @@ -296,38 +296,6 @@ menu "ESP32S2-specific" Data is reserved at the beginning of RTC slow memory. - choice ESP32S2_PANIC - prompt "Panic handler behaviour" - default ESP32S2_PANIC_PRINT_REBOOT - help - If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is - invoked. Configure the panic handlers action here. - - config ESP32S2_PANIC_PRINT_HALT - bool "Print registers and halt" - help - Outputs the relevant registers over the serial port and halt the - processor. Needs a manual reset to restart. - - config ESP32S2_PANIC_PRINT_REBOOT - bool "Print registers and reboot" - help - Outputs the relevant registers over the serial port and immediately - reset the processor. - - config ESP32S2_PANIC_SILENT_REBOOT - bool "Silent reboot" - help - Just resets the processor without outputting anything - - config ESP32S2_PANIC_GDBSTUB - bool "Invoke GDBStub" - select ESP_GDBSTUB_ENABLED - help - Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem - of the crash. - endchoice - config ESP32S2_DEBUG_OCDAWARE bool "Make exception and panic handlers JTAG/OCD aware" default y diff --git a/components/esp32s2/linker.lf b/components/esp32s2/linker.lf index 80ed1158e0..87e068ccd4 100644 --- a/components/esp32s2/linker.lf +++ b/components/esp32s2/linker.lf @@ -1,8 +1,3 @@ -[mapping:esp32s2] -archive: libesp32s2.a -entries: - panic (noflash) - [mapping:gcc] archive: libgcc.a entries: diff --git a/components/esp32s2/panic.c b/components/esp32s2/panic.c deleted file mode 100644 index b4436397d4..0000000000 --- a/components/esp32s2/panic.c +++ /dev/null @@ -1,678 +0,0 @@ -// 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 - -#include - -#include "esp32s2/rom/rtc.h" -#include "esp32s2/rom/uart.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/extmem_reg.h" -#include "soc/cache_memory.h" -#include "soc/rtc_cntl_reg.h" -#include "soc/timer_group_struct.h" -#include "soc/timer_group_reg.h" -#include "soc/cpu.h" -#include "soc/soc_memory_layout.h" -#include "soc/rtc.h" -#include "soc/rtc_wdt.h" - -#include "esp_private/gdbstub.h" -#include "esp_debug_helpers.h" -#include "esp_private/panic_reason.h" -#include "esp_attr.h" -#include "esp_err.h" -#include "esp_core_dump.h" -#include "esp_spi_flash.h" -#include "esp32s2/cache_err_int.h" -#include "esp_app_trace.h" -#include "esp_private/system_internal.h" -#include "sdkconfig.h" -#if CONFIG_SYSVIEW_ENABLE -#include "SEGGER_RTT.h" -#endif - -#if CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO == -1 -#define APPTRACE_ONPANIC_HOST_FLUSH_TMO ESP_APPTRACE_TMO_INFINITE -#else -#define APPTRACE_ONPANIC_HOST_FLUSH_TMO (1000*CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO) -#endif -/* - 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 and abort handler are also 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_ESP32S2_PANIC_SILENT_REBOOT -//printf may be broken, so we fix our own printing fns... -static void panicPutChar(char c) -{ - while (((READ_PERI_REG(UART_STATUS_REG(CONFIG_ESP_CONSOLE_UART_NUM)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT) >= 126) ; - WRITE_PERI_REG(UART_FIFO_AHB_REG(CONFIG_ESP_CONSOLE_UART_NUM), c); -} - -static void panicPutStr(const char *c) -{ - int x = 0; - while (c[x] != 0) { - panicPutChar(c[x]); - x++; - } -} - -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; - } -} - -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. -static void panicPutChar(char c) { } -static void panicPutStr(const char *c) { } -static void panicPutHex(int a) { } -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"); - abort(); -} - -/* These two weak stubs for esp_reset_reason_{get,set}_hint are used when - * the application does not call esp_reset_reason() function, and - * reset_reason.c is not linked into the output file. - */ -void __attribute__((weak)) esp_reset_reason_set_hint(esp_reset_reason_t hint) -{ -} - -esp_reset_reason_t __attribute__((weak)) esp_reset_reason_get_hint(void) -{ - return ESP_RST_UNKNOWN; -} - - -static bool abort_called; - -static __attribute__((noreturn)) inline void invoke_abort(void) -{ - abort_called = true; -#if CONFIG_APPTRACE_ENABLE -#if CONFIG_SYSVIEW_ENABLE - SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#endif -#endif - while (1) { - if (esp_cpu_in_ocd_debug_mode()) { - __asm__ ("break 0,0"); - } - *((int *) 0) = 0; - } -} - -void abort(void) -{ -#if !CONFIG_ESP32S2_PANIC_SILENT_REBOOT - ets_printf("abort() was called at PC 0x%08x on core %d\r\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID()); -#endif - /* Calling code might have set other reset reason hint (such as Task WDT), - * don't overwrite that. - */ - if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) { - esp_reset_reason_set_hint(ESP_RST_PANIC); - } - invoke_abort(); -} - - -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" -}; - -#define NUM_EDESCS (sizeof(edesc) / sizeof(char *)) - -static void commonErrorHandler(XtExcFrame *frame); -static inline void disableAllWdts(void); - -//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 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 inline void printCacheError(void) -{ - uint32_t vaddr = 0, size = 0; - uint32_t status[2]; - status[0] = REG_READ(EXTMEM_CACHE_DBG_STATUS0_REG); - status[1] = REG_READ(EXTMEM_CACHE_DBG_STATUS1_REG); - for (int i = 0; i < 32; i++) { - switch (status[0] & BIT(i)) { - case EXTMEM_IC_SYNC_SIZE_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC0_REG); - size = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC1_REG); - panicPutStr("Icache sync parameter configuration error, the error address and size is 0x"); - panicPutHex(vaddr); - panicPutStr("(0x"); - panicPutHex(size); - panicPutStr(")\r\n"); - break; - case EXTMEM_IC_PRELOAD_SIZE_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_ADDR_REG); - size = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_SIZE_REG); - panicPutStr("Icache preload parameter configuration error, the error address and size is 0x"); - panicPutHex(vaddr); - panicPutStr("(0x"); - panicPutHex(size); - panicPutStr(")\r\n"); - break; - case EXTMEM_ICACHE_REJECT_ST: - vaddr = REG_READ(EXTMEM_PRO_ICACHE_REJECT_VADDR_REG); - panicPutStr("Icache reject error occurred while accessing the address 0x"); - panicPutHex(vaddr); - - if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) { - panicPutStr(" (invalid mmu entry)"); - } - panicPutStr("\r\n"); - break; - default: - break; - } - switch (status[1] & BIT(i)) { - case EXTMEM_DC_SYNC_SIZE_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC0_REG); - size = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC1_REG); - panicPutStr("Dcache sync parameter configuration error, the error address and size is 0x"); - panicPutHex(vaddr); - panicPutStr("(0x"); - panicPutHex(size); - panicPutStr(")\r\n"); - break; - case EXTMEM_DC_PRELOAD_SIZE_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_ADDR_REG); - size = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_SIZE_REG); - panicPutStr("Dcache preload parameter configuration error, the error address and size is 0x"); - panicPutHex(vaddr); - panicPutStr("(0x"); - panicPutHex(size); - panicPutStr(")\r\n"); - break; - case EXTMEM_DCACHE_WRITE_FLASH_ST: - panicPutStr("Write back error occurred while dcache tries to write back to flash\r\n"); - break; - case EXTMEM_DCACHE_REJECT_ST: - vaddr = REG_READ(EXTMEM_PRO_DCACHE_REJECT_VADDR_REG); - panicPutStr("Dcache reject error occurred while accessing the address 0x"); - panicPutHex(vaddr); - - if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) { - panicPutStr(" (invalid mmu entry)"); - } - panicPutStr("\r\n"); - break; - case EXTMEM_MMU_ENTRY_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_VADDR_REG); - panicPutStr("MMU entry fault error occurred while accessing the address 0x"); - panicPutHex(vaddr); - - if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) { - panicPutStr(" (invalid mmu entry)"); - } - panicPutStr("\r\n"); - break; - default: - break; - } - } - panicPutStr("\r\n"); -} - -void panicHandler(XtExcFrame *frame) -{ - int core_id = xPortGetCoreID(); - //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", - "Cache exception", - }; - const char *reason = reasons[0]; - //The panic reason is stored in the EXCCAUSE register. - if (frame->exccause <= PANIC_RSN_MAX) { - reason = reasons[frame->exccause]; - } - - if (frame->exccause == PANIC_RSN_INTWDT_CPU0) { - esp_reset_reason_set_hint(ESP_RST_INT_WDT); - } - - panicPutStr("Guru Meditation Error: Core "); - panicPutDec(core_id); - panicPutStr(" panic'ed ("); - panicPutStr(reason); - panicPutStr(")\r\n"); - if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) { - int debugRsn; - asm("rsr.debugcause %0":"=r"(debugRsn)); - panicPutStr("Debug exception reason: "); - if (debugRsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) { - panicPutStr("SingleStep "); - } - if (debugRsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) { - panicPutStr("HwBreakpoint "); - } - if (debugRsn & XCHAL_DEBUGCAUSE_DBREAK_MASK) { - //Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK - //reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the - //debugcause if the cause is watchdog 1 and clearing it if it's watchdog 0. - if (debugRsn & (1 << 8)) { -#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK - const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core_id)); - panicPutStr("Stack canary watchpoint triggered ("); - panicPutStr(name); - panicPutStr(") "); -#else - panicPutStr("Watchpoint 1 triggered "); -#endif - } else { - panicPutStr("Watchpoint 0 triggered "); - } - } - if (debugRsn & XCHAL_DEBUGCAUSE_BREAK_MASK) { - panicPutStr("BREAK instr "); - } - if (debugRsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) { - panicPutStr("BREAKN instr "); - } - if (debugRsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) { - panicPutStr("DebugIntr "); - } - panicPutStr("\r\n"); - } else if (frame->exccause == PANIC_RSN_CACHEERR) { - panicPutStr(" ^~~~~~~~~~~~~~~\r\n"); - printCacheError(); - } - - if (esp_cpu_in_ocd_debug_mode()) { - disableAllWdts(); - if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || - frame->exccause == PANIC_RSN_INTWDT_CPU1) { - TIMERG1.int_clr.wdt = 1; - } -#if CONFIG_APPTRACE_ENABLE -#if CONFIG_SYSVIEW_ENABLE - SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#endif -#endif - setFirstBreakpoint(frame->pc); - return; - } - commonErrorHandler(frame); -} - -void xt_unhandled_exception(XtExcFrame *frame) -{ - if (!abort_called) { - panicPutStr("Guru Meditation Error: Core "); - panicPutDec(xPortGetCoreID()); - panicPutStr(" panic'ed ("); - int exccause = frame->exccause; - if (exccause < NUM_EDESCS) { - panicPutStr(edesc[exccause]); - } else { - panicPutStr("Unknown"); - } - panicPutStr(")"); - if (esp_cpu_in_ocd_debug_mode()) { - panicPutStr(" at pc="); - panicPutHex(frame->pc); - panicPutStr(". Setting bp and returning..\r\n"); -#if CONFIG_APPTRACE_ENABLE -#if CONFIG_SYSVIEW_ENABLE - SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#endif -#endif - //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(frame->pc); - return; - } - panicPutStr(". Exception was unhandled.\r\n"); - esp_reset_reason_set_hint(ESP_RST_PANIC); - } - 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(void) -{ - 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; -} - -/* - This disables all the watchdogs for when we call the gdbstub. -*/ -static inline void disableAllWdts(void) -{ - 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; - TIMERG1.wdt_wprotect = 0; -} - -#if CONFIG_ESP32S2_PANIC_PRINT_REBOOT || CONFIG_ESP32S2_PANIC_SILENT_REBOOT - -static void esp_panic_dig_reset(void) __attribute__((noreturn)); - -static void esp_panic_dig_reset(void) -{ - // make sure all the panic handler output is sent from UART FIFO - uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); - // switch to XTAL (otherwise we will keep running from the PLL) - rtc_clk_cpu_freq_set_xtal(); - SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); - while (true) { - ; - } -} - -#endif - -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 doBacktrace(XtExcFrame *frame) -{ - uint32_t i = 0, pc = frame->pc, sp = frame->a1; - panicPutStr("\r\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 (!esp_stack_ptr_is_sane(sp) || i++ > 100) { - break; - } - sp = *((uint32_t *) (sp - 0x10 + 4)); - putEntry(pc - 3, sp); // stack frame addresses are return addresses, so subtract 3 to get the CALL address - pc = *((uint32_t *) (psp - 0x10)); - if (pc < 0x40000000) { - break; - } - } - panicPutStr("\r\n\r\n"); -} - -/* - * Dump registers and do backtrace. - */ -static void commonErrorHandler_dump(XtExcFrame *frame, int core_id) -{ - 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 " - }; - - /* only dump registers for 'real' crashes, if crashing via abort() - the register window is no longer useful. - */ - if (!abort_called) { - panicPutStr("Core"); - panicPutDec(core_id); - 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"); - } - - if (xPortInterruptedFromISRContext()) { - //If the core which triggers the interrupt watchdog was in ISR context, dump the epc registers. - uint32_t __value; - panicPutStr("Core"); - panicPutDec(core_id); - panicPutStr(" was running in ISR context:\r\n"); - - __asm__("rsr.epc1 %0" : "=a"(__value)); - panicPutStr("EPC1 : 0x"); - panicPutHex(__value); - - __asm__("rsr.epc2 %0" : "=a"(__value)); - panicPutStr(" EPC2 : 0x"); - panicPutHex(__value); - - __asm__("rsr.epc3 %0" : "=a"(__value)); - panicPutStr(" EPC3 : 0x"); - panicPutHex(__value); - - __asm__("rsr.epc4 %0" : "=a"(__value)); - panicPutStr(" EPC4 : 0x"); - panicPutHex(__value); - - panicPutStr("\r\n"); - } - - } - - /* With windowed ABI backtracing is easy, let's do it. */ - doBacktrace(frame); - -} - -/* - 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. -*/ -static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame) -{ - - int core_id = xPortGetCoreID(); - // start panic WDT to restart system if we hang in this handler - if (!rtc_wdt_is_on()) { - rtc_wdt_protect_off(); - rtc_wdt_disable(); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us); - rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM); - // 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data. - // @ 115200 UART speed it will take more than 6 sec to print them out. - rtc_wdt_set_time(RTC_WDT_STAGE0, 7000); - rtc_wdt_enable(); - rtc_wdt_protect_on(); - } - - //Feed the watchdogs, so they will give us time to print out debug info - reconfigureAllWdts(); - - commonErrorHandler_dump(frame, core_id); - -#if CONFIG_APPTRACE_ENABLE - disableAllWdts(); -#if CONFIG_SYSVIEW_ENABLE - SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#else - esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, - APPTRACE_ONPANIC_HOST_FLUSH_TMO); -#endif - reconfigureAllWdts(); -#endif - -#if CONFIG_ESP32S2_PANIC_GDBSTUB - disableAllWdts(); - rtc_wdt_disable(); - panicPutStr("Entering gdb stub now.\r\n"); - esp_gdbstub_panic_handler(frame); -#else -#if CONFIG_ESP32_ENABLE_COREDUMP - static bool s_dumping_core; - if (s_dumping_core) { - panicPutStr("Re-entered core dump! Exception happened during core dump!\r\n"); - } else { - disableAllWdts(); - s_dumping_core = true; -#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH - esp_core_dump_to_flash(frame); -#endif -#if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART && !CONFIG_ESP32S2_PANIC_SILENT_REBOOT - esp_core_dump_to_uart(frame); -#endif - s_dumping_core = false; - reconfigureAllWdts(); - } -#endif /* CONFIG_ESP32_ENABLE_COREDUMP */ - rtc_wdt_disable(); -#if CONFIG_ESP32S2_PANIC_PRINT_REBOOT || CONFIG_ESP32S2_PANIC_SILENT_REBOOT - panicPutStr("Rebooting...\r\n"); - if (frame->exccause != PANIC_RSN_CACHEERR) { - esp_restart_noos(); - } else { - // The only way to clear invalid cache access interrupt is to reset the digital part - esp_panic_dig_reset(); - } -#else - disableAllWdts(); - panicPutStr("CPU halted.\r\n"); - while (1); -#endif /* CONFIG_ESP32S2_PANIC_PRINT_REBOOT || CONFIG_ESP32S2_PANIC_SILENT_REBOOT */ -#endif /* CONFIG_ESP32S2_PANIC_GDBSTUB */ -} - - -void esp_set_breakpoint_if_jtag(void *fn) -{ - if (esp_cpu_in_ocd_debug_mode()) { - setFirstBreakpoint((uint32_t)fn); - } -} - -void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) -{ - ets_printf("ESP_ERROR_CHECK failed: esp_err_t 0x%x", rc); -#ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP - ets_printf(" (%s)", esp_err_to_name(rc)); -#endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP - ets_printf(" at 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3); - if (spi_flash_cache_enabled()) { // strings may be in flash cache - ets_printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression); - } - invoke_abort(); -} diff --git a/components/esp_common/CMakeLists.txt b/components/esp_common/CMakeLists.txt index 185d8f7e69..98b178af6e 100644 --- a/components/esp_common/CMakeLists.txt +++ b/components/esp_common/CMakeLists.txt @@ -12,8 +12,7 @@ else() "src/freertos_hooks.c" "src/mac_addr.c" "src/pm_locks.c" - "src/stack_check.c" - "src/system_api.c") + "src/stack_check.c") # IPC framework is not applicable if freertos unicore config is selected if(NOT CONFIG_FREERTOS_UNICORE) @@ -22,8 +21,9 @@ else() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS include - REQUIRES ${target} esp_timer - PRIV_REQUIRES soc) + REQUIRES ${target} espcoredump esp_timer + PRIV_REQUIRES soc + LDFRAGMENTS "linker.lf") set_source_files_properties( "src/stack_check.c" diff --git a/components/esp_common/Kconfig b/components/esp_common/Kconfig index d394393b87..c72079024b 100644 --- a/components/esp_common/Kconfig +++ b/components/esp_common/Kconfig @@ -227,4 +227,4 @@ menu "Common ESP-related" config ESP_MAC_ADDR_UNIVERSE_ETH bool -endmenu # Common ESP-related +endmenu # Common ESP-related \ No newline at end of file diff --git a/components/esp_common/sdkconfig.rename b/components/esp_common/sdkconfig.rename index 2241ecf334..c7f23dde57 100644 --- a/components/esp_common/sdkconfig.rename +++ b/components/esp_common/sdkconfig.rename @@ -25,4 +25,4 @@ CONFIG_TASK_WDT_PANIC CONFIG_ESP_TASK_WDT_PANI CONFIG_TASK_WDT_TIMEOUT_S CONFIG_ESP_TASK_WDT_TIMEOUT_S CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 -CONFIG_ESP32_DEBUG_STUBS_ENABLE CONFIG_ESP_DEBUG_STUBS_ENABLE +CONFIG_ESP32_DEBUG_STUBS_ENABLE CONFIG_ESP_DEBUG_STUBS_ENABLE \ No newline at end of file diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt new file mode 100644 index 0000000000..a1439ea79b --- /dev/null +++ b/components/esp_system/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register(SRCS "abort.c" "panic.c" "reset_reason.c" "system_api.c" + INCLUDE_DIRS include + PRIV_INCLUDE_DIRS private_include + PRIV_REQUIRES spi_flash app_update + LDFRAGMENTS "linker.lf") + +add_subdirectory(port) diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig new file mode 100644 index 0000000000..73b54ad48d --- /dev/null +++ b/components/esp_system/Kconfig @@ -0,0 +1,35 @@ +menu "ESP System Settings" + + choice ESP_SYSTEM_PANIC + prompt "Panic handler behaviour" + default ESP_SYSTEM_PANIC_PRINT_REBOOT + help + If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is + invoked. Configure the panic handler's action here. + + config ESP_SYSTEM_PANIC_PRINT_HALT + bool "Print registers and halt" + help + Outputs the relevant registers over the serial port and halt the + processor. Needs a manual reset to restart. + + config ESP_SYSTEM_PANIC_PRINT_REBOOT + bool "Print registers and reboot" + help + Outputs the relevant registers over the serial port and immediately + reset the processor. + + config ESP_SYSTEM_PANIC_SILENT_REBOOT + bool "Silent reboot" + help + Just resets the processor without outputting anything + + config ESP_SYSTEM_PANIC_GDBSTUB + bool "Invoke GDBStub" + select ESP_GDBSTUB_ENABLED + help + Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem + of the crash. + endchoice + +endmenu # ESP System Settings diff --git a/components/esp_system/abort.c b/components/esp_system/abort.c new file mode 100644 index 0000000000..5933b4a354 --- /dev/null +++ b/components/esp_system/abort.c @@ -0,0 +1,81 @@ +// 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 +#include + +#include "esp_err.h" +#include "esp_spi_flash.h" +#include "esp_system.h" + +#include "esp_private/system_internal.h" + +#include "soc/cpu.h" +#include "soc/soc_caps.h" +#include "hal/cpu_hal.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/ets_sys.h" +#else +#include "esp32s2/rom/ets_sys.h" +#endif + +#include "panic.h" + +void __attribute__((noreturn)) abort(void) +{ + char buf[47] = { 0 }; + + _Static_assert(UINTPTR_MAX == 0xffffffff, "abort() assumes 32-bit addresses"); + _Static_assert(SOC_CPU_CORES_NUM < 10, "abort() assumes number of cores is [1..9]"); + + char addr_buf[9] = { 0 }; + char core_buf[2] = { 0 }; + + itoa((uint32_t)(__builtin_return_address(0) - 3), addr_buf, 16); + itoa(cpu_ll_get_core_id(), core_buf, 10); + + const char *str[4] = { "abort() was called at PC 0x", addr_buf, " on core ", core_buf }; + for (int i = 0, k = 0; i < 4; i++) { + for (int j = 0; str[i][j] != '\0'; j++) { + buf[k] = str[i][j]; + k++; + } + } + + esp_system_abort(buf); +} + +static void esp_error_check_failed_print(const char *msg, esp_err_t rc, const char *file, int line, const char *function, const char *expression) +{ + ets_printf("%s failed: esp_err_t 0x%x", msg, rc); +#ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP + ets_printf(" (%s)", esp_err_to_name(rc)); +#endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP + ets_printf(" at 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3); + if (spi_flash_cache_enabled()) { // strings may be in flash cache + ets_printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression); + } +} + +void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int line, const char *function, const char *expression) +{ + esp_error_check_failed_print("ESP_ERROR_CHECK_WITHOUT_ABORT", rc, file, line, function, expression); +} + +void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) +{ + esp_error_check_failed_print("ESP_ERROR_CHECK", rc, file, line, function, expression); + abort(); +} \ No newline at end of file diff --git a/components/esp_system/component.mk b/components/esp_system/component.mk new file mode 100644 index 0000000000..e7f5eb293b --- /dev/null +++ b/components/esp_system/component.mk @@ -0,0 +1,8 @@ +SOC_NAME := $(IDF_TARGET) + +COMPONENT_SRCDIRS := . +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := private_include +COMPONENT_ADD_LDFRAGMENTS += linker.lf + +-include $(COMPONENT_PATH)/port/$(SOC_NAME)/component.mk \ No newline at end of file diff --git a/components/esp_common/include/esp_system.h b/components/esp_system/include/esp_system.h similarity index 97% rename from components/esp_common/include/esp_system.h rename to components/esp_system/include/esp_system.h index 5947773d4f..9b0abf4314 100644 --- a/components/esp_common/include/esp_system.h +++ b/components/esp_system/include/esp_system.h @@ -223,7 +223,7 @@ esp_err_t esp_efuse_mac_get_default(uint8_t *mac); esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type); /** - * @brief Derive local MAC address from universal MAC address. + * @brief Derive local MAC address from universal MAC address. * * This function derives a local MAC address from an universal MAC address. * A `definition of local vs universal MAC address can be found on Wikipedia @@ -238,6 +238,13 @@ esp_err_t esp_read_mac(uint8_t* mac, esp_mac_type_t type); */ esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac); +/** + * @brief Trigger a software abort + * + * @param details Details that will be displayed during panic handling. + */ +void __attribute__((noreturn)) esp_system_abort(const char* details); + /** * @brief Chip models */ diff --git a/components/esp_system/linker.lf b/components/esp_system/linker.lf new file mode 100644 index 0000000000..8ae6c7c70c --- /dev/null +++ b/components/esp_system/linker.lf @@ -0,0 +1,7 @@ +[mapping:esp_system] +archive: libesp_system.a +entries: + panic (noflash) + panic_handler (noflash) + reset_reason (noflash) + system_api:esp_system_abort (noflash) \ No newline at end of file diff --git a/components/esp_system/panic.c b/components/esp_system/panic.c new file mode 100644 index 0000000000..87d5797860 --- /dev/null +++ b/components/esp_system/panic.c @@ -0,0 +1,336 @@ +// 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 + +#include "esp_err.h" +#include "esp_attr.h" + +#include "esp_spi_flash.h" +#include "esp_private/system_internal.h" +#include "esp_private/gdbstub.h" +#include "esp_ota_ops.h" + +#if CONFIG_APPTRACE_ENABLE +#include "esp_app_trace.h" +#if CONFIG_SYSVIEW_ENABLE +#include "SEGGER_RTT.h" +#endif +#endif // CONFIG_APPTRACE_ENABLE + +#include "esp_core_dump.h" + +#include "soc/rtc_wdt.h" +#include "soc/cpu.h" +#include "hal/timer_hal.h" +#include "hal/cpu_hal.h" + +#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT +#include +#include "hal/uart_hal.h" +#endif + +#include "panic_internal.h" + +#include "sdkconfig.h" + +#if CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO == -1 +#define APPTRACE_ONPANIC_HOST_FLUSH_TMO ESP_APPTRACE_TMO_INFINITE +#else +#define APPTRACE_ONPANIC_HOST_FLUSH_TMO (1000*CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO) +#endif + +static bool s_abort = false; +static char *s_abort_details = NULL; + +#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT + +static uart_hal_context_t s_panic_uart = { .dev = CONFIG_ESP_CONSOLE_UART_NUM == 0 ? &UART0 : &UART1 }; + +void panic_print_char(const char c) +{ + uint32_t sz = 0; + while(!uart_hal_get_txfifo_len(&s_panic_uart)); + uart_hal_write_txfifo(&s_panic_uart, (uint8_t*) &c, 1, &sz); +} + +void panic_print_str(const char *str) +{ + for(int i = 0; str[i] != 0; i++) { + panic_print_char(str[i]); + } +} + +void panic_print_hex(int h) +{ + int x; + int c; + // Does not print '0x', only the digits (8 digits to print) + for (x = 0; x < 8; x++) { + c = (h >> 28) & 0xf; // extract the leftmost byte + if (c < 10) { + panic_print_char('0' + c); + } else { + panic_print_char('a' + c - 10); + } + h <<= 4; // move the 2nd leftmost byte to the left, to be extracted next + } +} + +void panic_print_dec(int d) +{ + // can print at most 2 digits! + int n1, n2; + n1 = d % 10; // extract ones digit + n2 = d / 10; // extract tens digit + if (n2 == 0) { + panic_print_char(' '); + } else { + panic_print_char(n2 + '0'); + } + panic_print_char(n1 + '0'); +} +#endif // CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT + +/* + 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 reconfigure_all_wdts(void) +{ + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_init(&TIMERG0); + timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US + //1st stage timeout: reset system + timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_RESET_SYSTEM); + //1 second before reset + timer_ll_wdt_set_timeout(&TIMERG0, 0, 1000*1000/TG0_WDT_TICK_US); + timer_ll_wdt_set_enable(&TIMERG0, true); + timer_ll_wdt_set_protect(&TIMERG0, true); + + //Disable wdt 1 + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_set_enable(&TIMERG1, false); + timer_ll_wdt_set_protect(&TIMERG1, true); +} + +/* + This disables all the watchdogs for when we call the gdbstub. +*/ +static inline void disable_all_wdts(void) +{ + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_set_enable(&TIMERG0, false); + timer_ll_wdt_set_protect(&TIMERG0, true); + + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_set_enable(&TIMERG1, false); + timer_ll_wdt_set_protect(&TIMERG1, true); +} + +static void print_abort_details(const void *f) +{ + panic_print_str(s_abort_details); +} + +// Control arrives from chip-specific panic handler, environment prepared for +// the 'main' logic of panic handling. This means that chip-specific stuff have +// already been done, and panic_info_t has been filled. +void esp_panic_handler(panic_info_t *info) +{ + // If the exception was due to an abort, override some of the panic info + if (s_abort) { + info->description = NULL; + info->details = s_abort_details ? print_abort_details : NULL; + info->state = NULL; // do not display state, since it is not a 'real' crash + info->reason = "SoftwareAbort"; + info->exception = PANIC_EXCEPTION_ABORT; + } + + /* + * For any supported chip, the panic handler prints the contents of panic_info_t in the following format: + * + * + * Guru Meditation Error: Core (). + *
+ * + * + * + * + * + * + * ---------------------------------------------------------------------------------------- + * core - core where exception was triggered + * exception - what kind of exception occured + * description - a short description regarding the exception that occured + * details - more details about the exception + * state - processor state like register contents, and backtrace + * elf_info - details about the image currently running + * + * NULL fields in panic_info_t are not printed. + * + * */ + panic_print_str("Guru Meditation Error: Core "); + panic_print_dec(info->core); + panic_print_str(" panic'ed ("); + panic_print_str(info->reason); + panic_print_str("). "); + + if (info->description) { + panic_print_str(info->description); + } + + panic_print_str("\r\n"); + + PANIC_INFO_DUMP(info, details); + + panic_print_str("\r\n"); + + // If on-chip-debugger is attached, and system is configured to be aware of this, + // then only print up to details. Users should be able to probe for the other information + // in debug mode. + if (esp_cpu_in_ocd_debug_mode()) { + panic_print_str("Setting breakpoint at 0x"); + panic_print_hex((uint32_t)info->addr); + panic_print_str(" and returning...\r\n"); + disable_all_wdts(); +#if CONFIG_APPTRACE_ENABLE +#if CONFIG_SYSVIEW_ENABLE + SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); +#else + esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, + APPTRACE_ONPANIC_HOST_FLUSH_TMO); +#endif +#endif + + cpu_hal_set_breakpoint(0, info->addr); // use breakpoint 0 + return; + } + + // start panic WDT to restart system if we hang in this handler + if (!rtc_wdt_is_on()) { + rtc_wdt_protect_off(); + rtc_wdt_disable(); + rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us); + rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us); + rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_SYSTEM); + // 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data. + // @ 115200 UART speed it will take more than 6 sec to print them out. + rtc_wdt_set_time(RTC_WDT_STAGE0, 7000); + rtc_wdt_enable(); + rtc_wdt_protect_on(); + } + + //Feed the watchdogs, so they will give us time to print out debug info + reconfigure_all_wdts(); + + PANIC_INFO_DUMP(info, state); + panic_print_str("\r\n"); + + panic_print_str("\r\nELF file SHA256: "); + char sha256_buf[65]; + esp_ota_get_app_elf_sha256(sha256_buf, sizeof(sha256_buf)); + panic_print_str(sha256_buf); + panic_print_str("\r\n"); + + panic_print_str("\r\n"); + +#if CONFIG_APPTRACE_ENABLE + disable_all_wdts(); +#if CONFIG_SYSVIEW_ENABLE + SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); +#else + esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, + APPTRACE_ONPANIC_HOST_FLUSH_TMO); +#endif + reconfigure_all_wdts(); +#endif + +#if CONFIG_ESP_SYSTEM_PANIC_GDBSTUB + disable_all_wdts(); + rtc_wdt_disable(); + panic_print_str("Entering gdb stub now.\r\n"); + esp_gdbstub_panic_handler((XtExcFrame*) info->frame); +#else +#if CONFIG_ESP32_ENABLE_COREDUMP + static bool s_dumping_core; + if (s_dumping_core) { + panic_print_str("Re-entered core dump! Exception happened during core dump!\r\n"); + } else { + disable_all_wdts(); + s_dumping_core = true; +#if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH + esp_core_dump_to_flash((XtExcFrame*) info->frame); +#endif +#if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART && !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT + esp_core_dump_to_uart((XtExcFrame*) info->frame); +#endif + s_dumping_core = false; + reconfigure_all_wdts(); + } +#endif /* CONFIG_ESP32_ENABLE_COREDUMP */ + rtc_wdt_disable(); +#if CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT + + if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) { + switch (info->exception) + { + case PANIC_EXCEPTION_IWDT: + esp_reset_reason_set_hint(ESP_RST_INT_WDT); + break; + case PANIC_EXCEPTION_TWDT: + esp_reset_reason_set_hint(ESP_RST_TASK_WDT); + break; + case PANIC_EXCEPTION_ABORT: + case PANIC_EXCEPTION_FAULT: + default: + esp_reset_reason_set_hint(ESP_RST_PANIC); + break; // do not touch the previously set reset reason hint + } + } + + panic_print_str("Rebooting...\r\n"); + esp_restart_noos(); +#else + disable_all_wdts(); + panic_print_str("CPU halted.\r\n"); + while (1); +#endif /* CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT */ +#endif /* CONFIG_ESP_SYSTEM_PANIC_GDBSTUB */ +} + +void __attribute__((noreturn)) panic_abort(const char *details) +{ + s_abort = true; + s_abort_details = (char*) details; + +#if CONFIG_APPTRACE_ENABLE +#if CONFIG_SYSVIEW_ENABLE + SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO); +#else + esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, + APPTRACE_ONPANIC_HOST_FLUSH_TMO); +#endif +#endif + + while (1) { + if (esp_cpu_in_ocd_debug_mode()) { + cpu_hal_break(); + } + *((int *) 0) = 0; // should be an invalid operation on targets + } +} \ No newline at end of file diff --git a/components/esp_system/port/CMakeLists.txt b/components/esp_system/port/CMakeLists.txt new file mode 100644 index 0000000000..75def881d3 --- /dev/null +++ b/components/esp_system/port/CMakeLists.txt @@ -0,0 +1,9 @@ +target_include_directories(${COMPONENT_LIB} PRIVATE include) + +set(srcs "panic_handler.c" "panic_handler_asm.S") +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) + +target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) + +idf_build_get_property(target IDF_TARGET) +add_subdirectory(${target}) diff --git a/components/esp_system/port/esp32/CMakeLists.txt b/components/esp_system/port/esp32/CMakeLists.txt new file mode 100644 index 0000000000..ed1a5652d4 --- /dev/null +++ b/components/esp_system/port/esp32/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/dport_panic_highint_hdl.S") \ No newline at end of file diff --git a/components/esp_system/port/esp32/component.mk b/components/esp_system/port/esp32/component.mk new file mode 100644 index 0000000000..442effc300 --- /dev/null +++ b/components/esp_system/port/esp32/component.mk @@ -0,0 +1 @@ +COMPONENT_SRCDIRS += port port/esp32 diff --git a/components/esp32/dport_panic_highint_hdl.S b/components/esp_system/port/esp32/dport_panic_highint_hdl.S similarity index 100% rename from components/esp32/dport_panic_highint_hdl.S rename to components/esp_system/port/esp32/dport_panic_highint_hdl.S diff --git a/components/esp_system/port/esp32s2/CMakeLists.txt b/components/esp_system/port/esp32s2/CMakeLists.txt new file mode 100644 index 0000000000..ed1a5652d4 --- /dev/null +++ b/components/esp_system/port/esp32s2/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/dport_panic_highint_hdl.S") \ No newline at end of file diff --git a/components/esp32s2/dport_panic_highint_hdl.S b/components/esp_system/port/esp32s2/dport_panic_highint_hdl.S similarity index 100% rename from components/esp32s2/dport_panic_highint_hdl.S rename to components/esp_system/port/esp32s2/dport_panic_highint_hdl.S diff --git a/components/esp_system/port/include/port/panic_funcs.h b/components/esp_system/port/include/port/panic_funcs.h new file mode 100644 index 0000000000..28ab5ba24a --- /dev/null +++ b/components/esp_system/port/include/port/panic_funcs.h @@ -0,0 +1,15 @@ +// Copyright 2020 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. + +void __attribute__((noreturn)) panic_restart(void); \ No newline at end of file diff --git a/components/esp_system/port/panic_handler.c b/components/esp_system/port/panic_handler.c new file mode 100644 index 0000000000..b0423c368b --- /dev/null +++ b/components/esp_system/port/panic_handler.c @@ -0,0 +1,529 @@ +// 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 + +#include "freertos/xtensa_context.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_spi_flash.h" + +#include "esp_private/panic_reason.h" +#include "esp_private/system_internal.h" +#include "esp_debug_helpers.h" + +#include "soc/soc_memory_layout.h" +#include "soc/cpu.h" +#include "soc/soc_caps.h" +#include "soc/rtc.h" + +#include "hal/soc_hal.h" +#include "hal/cpu_hal.h" +#include "hal/timer_hal.h" + +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/cache_err_int.h" +#include "esp32/dport_access.h" +#include "esp32/rom/uart.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/cache_err_int.h" +#include "esp32s2/rom/uart.h" +#include "soc/extmem_reg.h" +#include "soc/cache_memory.h" +#include "soc/rtc_cntl_reg.h" +#endif + +#include "panic_internal.h" + +extern void esp_panic_handler(panic_info_t*); + +static XtExcFrame* xt_exc_frames[SOC_CPU_CORES_NUM] = {NULL}; + +/* + 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 and abort handler are also in here. +*/ + +/* + Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled. +*/ +static void print_illegal_instruction_details(const void* f) +{ + XtExcFrame* frame = (XtExcFrame*) f; + /* Print out memory around the instruction word */ + uint32_t epc = frame->pc; + epc = (epc & ~0x3) - 4; + + /* check that the address was sane */ + if (epc < SOC_IROM_MASK_LOW || epc >= SOC_IROM_HIGH) { + return; + } + volatile uint32_t* pepc = (uint32_t*)epc; + + panic_print_str("Memory dump at 0x"); + panic_print_hex(epc); + panic_print_str(": "); + + panic_print_hex(*pepc); + panic_print_str(" "); + panic_print_hex(*(pepc + 1)); + panic_print_str(" "); + panic_print_hex(*(pepc + 2)); +} + +static void print_debug_exception_details(const void* f) +{ + int debug_rsn; + asm("rsr.debugcause %0":"=r"(debug_rsn)); + panic_print_str("Debug exception reason: "); + if (debug_rsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) { + panic_print_str("SingleStep "); + } + if (debug_rsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) { + panic_print_str("HwBreakpoint "); + } + if (debug_rsn & XCHAL_DEBUGCAUSE_DBREAK_MASK) { + //Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK + //reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the + //debugcause if the cause is watchpoint 1 and clearing it if it's watchpoint 0. + if (debug_rsn & (1 << 8)) { +#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK + int core = 0; + +#if !CONFIG_FREERTOS_UNICORE + if (f == xt_exc_frames[1]) { + core = 1; + } +#endif + + const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core)); + panic_print_str("Stack canary watchpoint triggered ("); + panic_print_str(name); + panic_print_str(") "); +#else + panic_print_str("Watchpoint 1 triggered "); +#endif + } else { + panic_print_str("Watchpoint 0 triggered "); + } + } + if (debug_rsn & XCHAL_DEBUGCAUSE_BREAK_MASK) { + panic_print_str("BREAK instr "); + } + if (debug_rsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) { + panic_print_str("BREAKN instr "); + } + if (debug_rsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) { + panic_print_str("DebugIntr "); + } +} + +static void print_backtrace_entry(uint32_t pc, uint32_t sp) +{ + panic_print_str("0x"); + panic_print_hex(pc); + panic_print_str(":0x"); + panic_print_hex(sp); +} + +static void print_backtrace(const void* f, int core) +{ + XtExcFrame *frame = (XtExcFrame*) f; + int depth = 100; + //Initialize stk_frame with first frame of stack + esp_backtrace_frame_t stk_frame = {.pc = frame->pc, .sp = frame->a1, .next_pc = frame->a0}; + panic_print_str("\r\nBacktrace: "); + print_backtrace_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + + //Check if first frame is valid + bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) && + esp_ptr_executable((void*)esp_cpu_process_stack_pc(stk_frame.pc))); + + uint32_t i = ((depth <= 0) ? INT32_MAX : depth) - 1; //Account for stack frame that's already printed + while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) { + if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get next stack frame + corrupted = true; + } + panic_print_str(" "); + print_backtrace_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp); + } + + //Print backtrace termination marker + if (corrupted) { + panic_print_str(" |<-CORRUPTED"); + } else if (stk_frame.next_pc != 0) { //Backtrace continues + panic_print_str(" |<-CONTINUES"); + } +} + +static void print_registers(const void *f, int core) +{ + XtExcFrame* frame = (XtExcFrame*) f; + 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 " + }; + + /* only dump registers for 'real' crashes, if crashing via abort() + the register window is no longer useful. + */ + panic_print_str("Core "); + panic_print_dec(core); + panic_print_str(" register dump:"); + + for (x = 0; x < 24; x += 4) { + panic_print_str("\r\n"); + for (y = 0; y < 4; y++) { + if (sdesc[x + y][0] != 0) { + panic_print_str(sdesc[x + y]); + panic_print_str(": 0x"); + panic_print_hex(regs[x + y + 1]); + panic_print_str(" "); + } + } + } + + // If the core which triggers the interrupt watchpoint was in ISR context, dump the epc registers. + if (xPortInterruptedFromISRContext() +#if !CONFIG_FREERTOS_UNICORE + && ((core == 0 && frame->exccause == PANIC_RSN_INTWDT_CPU0) || + (core == 1 && frame->exccause == PANIC_RSN_INTWDT_CPU1)) +#endif //!CONFIG_FREERTOS_UNICORE + ) { + + panic_print_str("\r\n"); + + uint32_t __value; + panic_print_str("Core "); + panic_print_dec(core); + panic_print_str(" was running in ISR context:\r\n"); + + __asm__("rsr.epc1 %0" : "=a"(__value)); + panic_print_str("EPC1 : 0x"); + panic_print_hex(__value); + + __asm__("rsr.epc2 %0" : "=a"(__value)); + panic_print_str(" EPC2 : 0x"); + panic_print_hex(__value); + + __asm__("rsr.epc3 %0" : "=a"(__value)); + panic_print_str(" EPC3 : 0x"); + panic_print_hex(__value); + + __asm__("rsr.epc4 %0" : "=a"(__value)); + panic_print_str(" EPC4 : 0x"); + panic_print_hex(__value); + } +} + +static void print_state(const void* f) +{ +#if !CONFIG_FREERTOS_UNICORE + int err_core = f == xt_exc_frames[0] ? 0 : 1; +#else + int err_core = 0; +#endif + + print_registers(f, err_core); + panic_print_str("\r\n"); + print_backtrace(f, err_core); + panic_print_str("\r\n"); + +#if !CONFIG_FREERTOS_UNICORE + // If there are other frame info, print them as well + for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { + // `f` is the frame for the offending core, see note above. + if (err_core != i && xt_exc_frames[i] != NULL) { + panic_print_str("\r\n"); + print_registers(xt_exc_frames[i], i); + panic_print_str("\r\n"); + print_backtrace(xt_exc_frames[i], i); + } + } +#endif +} + +#if CONFIG_IDF_TARGET_ESP32S2 +static inline void print_cache_err_details(const void* f) +{ + uint32_t vaddr = 0, size = 0; + uint32_t status[2]; + status[0] = REG_READ(EXTMEM_CACHE_DBG_STATUS0_REG); + status[1] = REG_READ(EXTMEM_CACHE_DBG_STATUS1_REG); + for (int i = 0; i < 32; i++) { + switch (status[0] & BIT(i)) { + case EXTMEM_IC_SYNC_SIZE_FAULT_ST: + vaddr = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC0_REG); + size = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC1_REG); + panic_print_str("Icache sync parameter configuration error, the error address and size is 0x"); + panic_print_hex(vaddr); + panic_print_str("(0x"); + panic_print_hex(size); + panic_print_str(")\r\n"); + break; + case EXTMEM_IC_PRELOAD_SIZE_FAULT_ST: + vaddr = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_ADDR_REG); + size = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_SIZE_REG); + panic_print_str("Icache preload parameter configuration error, the error address and size is 0x"); + panic_print_hex(vaddr); + panic_print_str("(0x"); + panic_print_hex(size); + panic_print_str(")\r\n"); + break; + case EXTMEM_ICACHE_REJECT_ST: + vaddr = REG_READ(EXTMEM_PRO_ICACHE_REJECT_VADDR_REG); + panic_print_str("Icache reject error occurred while accessing the address 0x"); + panic_print_hex(vaddr); + + if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) { + panic_print_str(" (invalid mmu entry)"); + } + panic_print_str("\r\n"); + break; + default: + break; + } + switch (status[1] & BIT(i)) { + case EXTMEM_DC_SYNC_SIZE_FAULT_ST: + vaddr = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC0_REG); + size = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC1_REG); + panic_print_str("Dcache sync parameter configuration error, the error address and size is 0x"); + panic_print_hex(vaddr); + panic_print_str("(0x"); + panic_print_hex(size); + panic_print_str(")\r\n"); + break; + case EXTMEM_DC_PRELOAD_SIZE_FAULT_ST: + vaddr = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_ADDR_REG); + size = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_SIZE_REG); + panic_print_str("Dcache preload parameter configuration error, the error address and size is 0x"); + panic_print_hex(vaddr); + panic_print_str("(0x"); + panic_print_hex(size); + panic_print_str(")\r\n"); + break; + case EXTMEM_DCACHE_WRITE_FLASH_ST: + panic_print_str("Write back error occurred while dcache tries to write back to flash\r\n"); + break; + case EXTMEM_DCACHE_REJECT_ST: + vaddr = REG_READ(EXTMEM_PRO_DCACHE_REJECT_VADDR_REG); + panic_print_str("Dcache reject error occurred while accessing the address 0x"); + panic_print_hex(vaddr); + + if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) { + panic_print_str(" (invalid mmu entry)"); + } + panic_print_str("\r\n"); + break; + case EXTMEM_MMU_ENTRY_FAULT_ST: + vaddr = REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_VADDR_REG); + panic_print_str("MMU entry fault error occurred while accessing the address 0x"); + panic_print_hex(vaddr); + + if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) { + panic_print_str(" (invalid mmu entry)"); + } + panic_print_str("\r\n"); + break; + default: + break; + } + } +} +#endif + +static void frame_to_panic_info(XtExcFrame *frame, panic_info_t* info, bool pseudo_excause) +{ + info->core = cpu_hal_get_core_id(); + info->exception = PANIC_EXCEPTION_FAULT; + info->details = NULL; + + if (pseudo_excause) { + if (frame->exccause == PANIC_RSN_INTWDT_CPU0) { + info->core = 0; + info->exception = PANIC_EXCEPTION_IWDT; + } else if (frame->exccause == PANIC_RSN_INTWDT_CPU1) { + info->core = 1; + info->exception = PANIC_EXCEPTION_IWDT; + } else if (frame->exccause == PANIC_RSN_CACHEERR) { + info->core = esp_cache_err_get_cpuid(); + } else {} + + //Please keep in sync with PANIC_RSN_* defines + static const char *pseudo_reason[] = { + "Unknown reason", + "Unhandled debug exception", + "Double exception", + "Unhandled kernel exception", + "Coprocessor exception", + "Interrupt wdt timeout on CPU0", + "Interrupt wdt timeout on CPU1", +#if CONFIG_IDF_TARGET_ESP32 + "Cache disabled but cached memory region accessed", +#elif CONFIG_IDF_TARGET_ESP32S2 + "Cache exception", +#endif + }; + + info->reason = pseudo_reason[0]; + info->description = NULL; + + if (frame->exccause <= PANIC_RSN_MAX) { + info->reason = pseudo_reason[frame->exccause]; + } + + if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) { + info->details = print_debug_exception_details; + info->exception = PANIC_EXCEPTION_DEBUG; + } + +#if CONFIG_IDF_TARGET_ESP32S2 + if(frame->exccause == PANIC_RSN_CACHEERR) { + info->details = print_cache_err_details; + } +#endif + } else { + static const char *reason[] = { + "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" + }; + + if (frame->exccause < (sizeof(reason) / sizeof(char *))) { + info->reason = (reason[frame->exccause]); + } else { + info->reason = "Unknown"; + } + + info->description = "Exception was unhandled."; + + if (info->reason == reason[0]) { + info->details = print_illegal_instruction_details; + } + } + + info->state = print_state; + info->addr = ((void*) ((XtExcFrame*) frame)->pc); + info->frame = frame; +} + +static void panic_handler(XtExcFrame *frame, bool pseudo_excause) +{ + /* + * Setup environment and perform necessary architecture/chip specific + * steps here prior to the system panic handler. + * */ + int core_id = cpu_hal_get_core_id(); + + // If multiple cores arrive at panic handler, save frames for all of them + xt_exc_frames[core_id] = frame; + +#if !CONFIG_FREERTOS_UNICORE + // These are cases where both CPUs both go into panic handler. The following code ensures + // only one core proceeds to the system panic handler. + if (pseudo_excause) { + #define BUSY_WAIT_IF_TRUE(b) { if (b) while(1); } + // For WDT expiry, pause the non-offending core - offending core handles panic + BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_INTWDT_CPU0 && core_id == 1); + BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_INTWDT_CPU1 && core_id == 0); + + // For cache error, pause the non-offending core - offending core handles panic + BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_CACHEERR && core_id != esp_cache_err_get_cpuid()); + } + + ets_delay_us(1); + SOC_HAL_STALL_OTHER_CORES(); +#endif + +#if CONFIG_IDF_TARGET_ESP32 + esp_dport_access_int_abort(); +#endif + +#if !CONFIG_ESP_PANIC_HANDLER_IRAM + // Re-enable CPU cache for current CPU if it was disabled + if (!spi_flash_cache_enabled()) { + spi_flash_enable_cache(core_id); + panic_print_str("Re-enable cpu cache.\r\n"); + } +#endif + + if (esp_cpu_in_ocd_debug_mode()) { + if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || + frame->exccause == PANIC_RSN_INTWDT_CPU1) { + timer_ll_wdt_clear_intr_status(&TIMERG1); + } + } + + // Convert architecture exception frame into abstracted panic info + panic_info_t info; + frame_to_panic_info(frame, &info, pseudo_excause); + + // Call the system panic handler + esp_panic_handler(&info); +} + +void panicHandler(XtExcFrame *frame) +{ + // This panic handler gets called for when the double exception vector, + // kernel exception vector gets used; as well as handling interrupt-based + // faults cache error, wdt expiry. EXCAUSE register gets written with + // one of PANIC_RSN_* values. + panic_handler(frame, true); +} + +void xt_unhandled_exception(XtExcFrame *frame) +{ + panic_handler(frame, false); +} + +static __attribute__((noreturn)) void esp_digital_reset(void) +{ + // make sure all the panic handler output is sent from UART FIFO + uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + // switch to XTAL (otherwise we will keep running from the PLL) + + rtc_clk_cpu_freq_set_xtal(); + +#if CONFIG_IDF_TARGET_ESP32 + esp_cpu_unstall(PRO_CPU_NUM); +#endif + // reset the digital part + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST); + while (true) { + ; + } +} + +void __attribute__((noreturn)) panic_restart(void) +{ + // If resetting because of a cache error, reset the digital part + if (esp_cache_err_get_cpuid() != -1) { + esp_digital_reset(); + } else { + esp_restart_noos(); + } +} \ No newline at end of file diff --git a/components/esp_system/port/panic_handler_asm.S b/components/esp_system/port/panic_handler_asm.S new file mode 100644 index 0000000000..cb6efe8b5a --- /dev/null +++ b/components/esp_system/port/panic_handler_asm.S @@ -0,0 +1,64 @@ +#include "freertos/xtensa_rtos.h" +#include "esp_private/panic_reason.h" +#include "soc/soc.h" + +#include "sdkconfig.h" + + + +/* +-------------------------------------------------------------------------------- + Panic handler. + Should be reached by call0 (preferable) or jump only. If call0, a0 says where + from. If on simulator, display panic message and abort, else loop indefinitely. +-------------------------------------------------------------------------------- +*/ + + .section .iram1,"ax" + .global panicHandler + + .global _xt_panic + .type _xt_panic,@function + .align 4 + .literal_position + .align 4 + +_xt_panic: + /* Allocate exception frame and save minimal context. */ + mov a0, sp + addi sp, sp, -XT_STK_FRMSZ + s32i a0, sp, XT_STK_A1 + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -12 /* for debug backtrace */ + #endif + rsr a0, PS /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_1 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -16 /* for debug backtrace */ + #endif + s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ + s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ + call0 _xt_context_save + + /* Save exc cause and vaddr into exception frame */ + rsr a0, EXCCAUSE + s32i a0, sp, XT_STK_EXCCAUSE + rsr a0, EXCVADDR + s32i a0, sp, XT_STK_EXCVADDR + + /* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */ + rsr a0, EXCSAVE_1 /* save interruptee's a0 */ + + s32i a0, sp, XT_STK_A0 + + /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */ + movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE + wsr a0, PS + + //Call panic handler + mov a6,sp + call4 panicHandler + + ret \ No newline at end of file diff --git a/components/esp_system/private_include/panic_internal.h b/components/esp_system/private_include/panic_internal.h new file mode 100644 index 0000000000..5656ac4879 --- /dev/null +++ b/components/esp_system/private_include/panic_internal.h @@ -0,0 +1,66 @@ +// 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. + +#pragma once + +#include + +#include "sdkconfig.h" + +// Function to print longer amounts of information such as the details +// and backtrace field of panic_info_t. These functions should limit themselves +// to printing to the console and should do other more involved processing, +// and must be aware that the main logic in panic.c has a watchdog timer active. +typedef void (*panic_info_dump_fn_t)(const void* frame); + +// Non architecture specific exceptions (generally valid for all targets). +// Can be used to convey to the main logic what exception is being +// dealt with to perform some actions, without knowing the underlying +// architecture/chip-specific exception. +typedef enum { + PANIC_EXCEPTION_DEBUG, + PANIC_EXCEPTION_IWDT, + PANIC_EXCEPTION_TWDT, + PANIC_EXCEPTION_ABORT, + PANIC_EXCEPTION_FAULT, // catch-all for all types of faults +} panic_exception_t; + +typedef struct { + int core; // core which triggered panic + panic_exception_t exception; // non-architecture-specific exception code + const char* reason; // exception string + const char* description; // short description of the exception + panic_info_dump_fn_t details; // more details on the exception + panic_info_dump_fn_t state; // processor state, usually the contents of the registers + const void* addr; // instruction address that triggered the exception + const void* frame; // reference to the frame +} panic_info_t; + +#define PANIC_INFO_DUMP(info, dump_fn) {if ((info)->dump_fn) (*(info)->dump_fn)((info->frame));} + +// Create own print functions, since printf might be broken, and can be silenced +// when CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT +#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT +void panic_print_char(char c); +void panic_print_str(const char *str); +void panic_print_dec(int d); +void panic_print_hex(int h); +#else +#define panic_print_char(c) +#define panic_print_str(str) +#define panic_print_dec(d) +#define panic_print_hex(h) +#endif + +void __attribute__((noreturn)) panic_abort(const char *details); \ No newline at end of file diff --git a/components/esp_system/reset_reason.c b/components/esp_system/reset_reason.c new file mode 100644 index 0000000000..a4bebbfb91 --- /dev/null +++ b/components/esp_system/reset_reason.c @@ -0,0 +1,30 @@ +// 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 "esp_private/system_internal.h" + +/* These two weak stubs for esp_reset_reason_{get,set}_hint are used when + * the application does not call esp_reset_reason() function, and + * reset_reason.c is not linked into the output file. + */ +void __attribute__((weak)) esp_reset_reason_set_hint(esp_reset_reason_t hint) +{ +} + +esp_reset_reason_t __attribute__((weak)) esp_reset_reason_get_hint(void) +{ + return ESP_RST_UNKNOWN; +} + diff --git a/components/esp_system/sdkconfig.rename b/components/esp_system/sdkconfig.rename new file mode 100644 index 0000000000..87310ef6de --- /dev/null +++ b/components/esp_system/sdkconfig.rename @@ -0,0 +1,13 @@ +# sdkconfig replacement configurations for deprecated options formatted as +# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION +CONFIG_ESP32_PANIC CONFIG_ESP_SYSTEM_PANIC +CONFIG_ESP32_PANIC_PRINT_HALT CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT +CONFIG_ESP32_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT +CONFIG_ESP32_PANIC_SILENT_REBOOT CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT +CONFIG_ESP32_PANIC_GDBSTUB CONFIG_ESP_SYSTEM_PANIC_GDBSTUB +CONFIG_ESP32S2_PANIC CONFIG_ESP_SYSTEM_PANIC +CONFIG_ESP32S2_PANIC_PRINT_HALT CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT +CONFIG_ESP32S2_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT +CONFIG_ESP32S2_PANIC_SILENT_REBOOT CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT +CONFIG_ESP32S2_PANIC_GDBSTUB CONFIG_ESP_SYSTEM_PANIC_GDBSTUB + diff --git a/components/esp_common/src/system_api.c b/components/esp_system/system_api.c similarity index 90% rename from components/esp_common/src/system_api.c rename to components/esp_system/system_api.c index 2c30a45d68..7b4ed130f9 100644 --- a/components/esp_common/src/system_api.c +++ b/components/esp_system/system_api.c @@ -4,6 +4,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_system.h" +#include "panic_internal.h" #define SHUTDOWN_HANDLERS_NO 2 static shutdown_handler_t shutdown_handlers[SHUTDOWN_HANDLERS_NO]; @@ -61,3 +63,7 @@ const char* esp_get_idf_version(void) return IDF_VER; } +void __attribute__((noreturn)) esp_system_abort(const char* details) +{ + panic_abort(details); +} \ No newline at end of file diff --git a/components/freertos/xtensa/port.c b/components/freertos/xtensa/port.c index 487d260e22..dbf0824bed 100644 --- a/components/freertos/xtensa/port.c +++ b/components/freertos/xtensa/port.c @@ -420,3 +420,18 @@ void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux) } } } + +void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ) +{ + #define ERR_STR1 "***ERROR*** A stack overflow in task " + #define ERR_STR2 " has been detected." + const char *str[] = {ERR_STR1, pcTaskName, ERR_STR2}; + + char buf[sizeof(ERR_STR1) + CONFIG_FREERTOS_MAX_TASK_NAME_LEN + sizeof(ERR_STR2) + 1 /* null char */] = { 0 }; + + char *dest = buf; + for (int i = 0 ; i < sizeof(str)/ sizeof(str[0]); i++) { + dest = strcat(dest, str[i]); + } + esp_system_abort(buf); +} \ No newline at end of file diff --git a/components/freertos/xtensa/xtensa_vectors.S b/components/freertos/xtensa/xtensa_vectors.S index 760fc51346..b7ddedbad1 100644 --- a/components/freertos/xtensa/xtensa_vectors.S +++ b/components/freertos/xtensa/xtensa_vectors.S @@ -361,96 +361,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .endm -/* --------------------------------------------------------------------------------- - Panic handler. - Should be reached by call0 (preferable) or jump only. If call0, a0 says where - from. If on simulator, display panic message and abort, else loop indefinitely. --------------------------------------------------------------------------------- -*/ - - .section .iram1,"ax" - .global panicHandler - - .global _xt_panic - .type _xt_panic,@function - .align 4 - .literal_position - .align 4 - -_xt_panic: - /* Allocate exception frame and save minimal context. */ - mov a0, sp - addi sp, sp, -XT_STK_FRMSZ - s32i a0, sp, XT_STK_A1 - #if XCHAL_HAVE_WINDOWED - s32e a0, sp, -12 /* for debug backtrace */ - #endif - rsr a0, PS /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_1 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - #if XCHAL_HAVE_WINDOWED - s32e a0, sp, -16 /* for debug backtrace */ - #endif - s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ - s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ - call0 _xt_context_save - - /* Save exc cause and vaddr into exception frame */ - rsr a0, EXCCAUSE - s32i a0, sp, XT_STK_EXCCAUSE - rsr a0, EXCVADDR - s32i a0, sp, XT_STK_EXCVADDR - - /* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */ - rsr a0, EXCSAVE_1 /* save interruptee's a0 */ - - s32i a0, sp, XT_STK_A0 - - /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */ - movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE - wsr a0, PS - - //Call panic handler - mov a6,sp - call4 panicHandler - - - .align 4 -//Call using call0. Prints the hex char in a2. Kills a3, a4, a5 -panic_print_hex: - movi a3,0x60000000 - movi a4,8 -panic_print_hex_loop: - l32i a5, a3, 0x1c - extui a5, a5, 16, 8 - bgei a5,64,panic_print_hex_loop - - srli a5,a2,28 - bgei a5,10,panic_print_hex_a - addi a5,a5,'0' - j panic_print_hex_ok -panic_print_hex_a: - addi a5,a5,'A'-10 -panic_print_hex_ok: - s32i a5,a3,0 - slli a2,a2,4 - - addi a4,a4,-1 - bnei a4,0,panic_print_hex_loop - movi a5,' ' - s32i a5,a3,0 - - ret - - - .section .rodata, "a" .align 4 - - /* -------------------------------------------------------------------------------- Hooks to dynamically install handlers for exceptions and interrupts. diff --git a/components/soc/src/cpu_util.c b/components/soc/src/cpu_util.c index eadeb2f526..1f0713d22a 100644 --- a/components/soc/src/cpu_util.c +++ b/components/soc/src/cpu_util.c @@ -84,3 +84,9 @@ bool IRAM_ATTR esp_cpu_in_ocd_debug_mode(void) #endif } +void IRAM_ATTR esp_set_breakpoint_if_jtag(void *fn) +{ + if (esp_cpu_in_ocd_debug_mode()) { + cpu_hal_set_breakpoint(0, fn); + } +} \ No newline at end of file diff --git a/examples/get-started/hello_world/sdkconfig.ci b/examples/get-started/hello_world/sdkconfig.ci index f180aef23e..fbc92b16d5 100644 --- a/examples/get-started/hello_world/sdkconfig.ci +++ b/examples/get-started/hello_world/sdkconfig.ci @@ -1,6 +1,6 @@ CONFIG_APP_BUILD_TYPE_ELF_RAM=y CONFIG_VFS_SUPPORT_TERMIOS=n CONFIG_NEWLIB_NANO_FORMAT=y -CONFIG_ESP32_PANIC_PRINT_HALT=y +CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y CONFIG_ESP32_DEBUG_STUBS_ENABLE=n CONFIG_ESP_ERR_TO_NAME_LOOKUP=n diff --git a/tools/cmake/build.cmake b/tools/cmake/build.cmake index e010a4401a..e6984b76e0 100644 --- a/tools/cmake/build.cmake +++ b/tools/cmake/build.cmake @@ -154,7 +154,7 @@ function(__build_init idf_path) # Set components required by all other components in the build # # - lwip is here so that #include works without any special provisions - set(requires_common cxx newlib freertos heap log lwip soc esp_rom esp_common xtensa) + set(requires_common cxx newlib freertos heap log lwip soc esp_rom esp_common esp_system xtensa) idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${requires_common}") __build_get_idf_git_revision() diff --git a/tools/ldgen/samples/sdkconfig b/tools/ldgen/samples/sdkconfig index a113356930..34bef9f38f 100644 --- a/tools/ldgen/samples/sdkconfig +++ b/tools/ldgen/samples/sdkconfig @@ -165,10 +165,10 @@ CONFIG_ESP_CONSOLE_UART_NUM=0 CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 CONFIG_ESP32_ULP_COPROC_ENABLED= CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0 -CONFIG_ESP32_PANIC_PRINT_HALT= -CONFIG_ESP32_PANIC_PRINT_REBOOT=y -CONFIG_ESP32_PANIC_SILENT_REBOOT= -CONFIG_ESP32_PANIC_GDBSTUB= +CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT= +CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y +CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT= +CONFIG_ESP_SYSTEM_PANIC_GDBSTUB= CONFIG_ESP32_DEBUG_OCDAWARE=y CONFIG_ESP_INT_WDT=y CONFIG_ESP_INT_WDT_TIMEOUT_MS=300