diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index 5c892aaa50..56f07a05e1 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -394,10 +394,10 @@ menu "ESP System Settings" automatically re-enable flash cache before running GDB Stub or Core Dump. This adds some minor risk, if the flash cache status is also corrupted during the crash. - If this option is enabled, the panic handler code is placed in IRAM. This allows the panic - handler to run without needing to re-enable cache first. This may be necessary to debug some - complex issues with crashes while flash cache is disabled (for example, when writing to - SPI flash.) + If this option is enabled, the panic handler code (including required UART functions) is placed + in IRAM. This may be necessary to debug some complex issues with crashes while flash cache is + disabled (for example, when writing to SPI flash) or when flash cache is corrupted when an exception + is triggered. config ESP_DEBUG_STUBS_ENABLE bool diff --git a/components/esp_system/linker.lf b/components/esp_system/linker.lf index b5bf7c49df..a458ccbadc 100644 --- a/components/esp_system/linker.lf +++ b/components/esp_system/linker.lf @@ -1,10 +1,11 @@ [mapping:esp_system] archive: libesp_system.a entries: - panic (noflash) - panic_handler (noflash) - panic_arch (noflash) - reset_reason (noflash) + if ESP_PANIC_HANDLER_IRAM = y: + panic (noflash) + panic_handler (noflash) + panic_arch (noflash) + esp_err (noflash) esp_system:esp_system_abort (noflash) diff --git a/components/esp_system/port/panic_handler.c b/components/esp_system/port/panic_handler.c index deacb4dcf2..0d321ce323 100644 --- a/components/esp_system/port/panic_handler.c +++ b/components/esp_system/port/panic_handler.c @@ -162,14 +162,6 @@ static void panic_handler(void *frame, bool pseudo_excause) 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 __XTENSA__ if (!(esp_ptr_executable(cpu_ll_pc_to_ptr(panic_get_address(frame))) && (panic_get_address(frame) & 0xC0000000U))) { @@ -198,8 +190,25 @@ static void panic_handler(void *frame, bool pseudo_excause) esp_panic_handler(&info); } -void panicHandler(void *frame) +/** + * This function must always be in IRAM as it is required to + * re-enable the flash cache. + */ +static void IRAM_ATTR panic_enable_cache(void) { + int core_id = cpu_hal_get_core_id(); + + if (!spi_flash_cache_enabled()) { +#ifdef CONFIG_IDF_TARGET_ESP32 + esp_dport_access_int_abort(); +#endif + spi_flash_enable_cache(core_id); + } +} + +void IRAM_ATTR panicHandler(void *frame) { + + panic_enable_cache(); // 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 @@ -207,8 +216,9 @@ void panicHandler(void *frame) panic_handler(frame, true); } -void xt_unhandled_exception(void *frame) +void IRAM_ATTR xt_unhandled_exception(void *frame) { + panic_enable_cache(); panic_handler(frame, false); } diff --git a/components/esp_system/port/soc/esp32c3/reset_reason.c b/components/esp_system/port/soc/esp32c3/reset_reason.c index 98e93d5934..7487eb682a 100644 --- a/components/esp_system/port/soc/esp32c3/reset_reason.c +++ b/components/esp_system/port/soc/esp32c3/reset_reason.c @@ -113,7 +113,7 @@ esp_reset_reason_t IRAM_ATTR esp_reset_reason_get_hint(void) } return (esp_reset_reason_t) low; } -static void esp_reset_reason_clear_hint(void) +static inline void esp_reset_reason_clear_hint(void) { REG_WRITE(RTC_RESET_CAUSE_REG, 0); } diff --git a/components/hal/linker.lf b/components/hal/linker.lf index 16084fd7f7..5fddfe3732 100644 --- a/components/hal/linker.lf +++ b/components/hal/linker.lf @@ -3,7 +3,7 @@ archive: libhal.a entries: spi_hal_iram (noflash) spi_slave_hal_iram (noflash) - if UART_ISR_IN_IRAM = y: + if UART_ISR_IN_IRAM = y || ESP_PANIC_HANDLER_IRAM = y: uart_hal_iram (noflash) else: uart_hal_iram (default) diff --git a/docs/en/api-guides/fatal-errors.rst b/docs/en/api-guides/fatal-errors.rst index 828a8c74b2..b1d3c1e09e 100644 --- a/docs/en/api-guides/fatal-errors.rst +++ b/docs/en/api-guides/fatal-errors.rst @@ -67,7 +67,7 @@ Behavior of panic handler is affected by two other configuration options. - If :ref:`CONFIG_ESP_PANIC_HANDLER_IRAM` is disabled (disabled by default), the panic handler code is placed in flash memory not IRAM. This means that if ESP-IDF crashes while flash cache is disabled, the panic handler will automatically re-enable flash cache before running GDB Stub or Core Dump. This adds some minor risk, if the flash cache status is also corrupted during the crash. - If this option is enabled, the panic handler code is placed in IRAM. This allows the panic handler to run without needing to re-enable cache first. This may be necessary to debug some complex issues with crashes while flash cache is disabled (for example, when writing to SPI flash). + If this option is enabled, the panic handler code (including required UART functions) is placed in IRAM. This may be necessary to debug some complex issues with crashes while flash cache is disabled (for example, when writing to SPI flash) or when flash cache is corrupted when an exception is triggered. The following diagram illustrates panic handler behavior: diff --git a/tools/test_apps/system/panic/panic_tests.py b/tools/test_apps/system/panic/panic_tests.py index fde69a5787..bb7967090e 100644 --- a/tools/test_apps/system/panic/panic_tests.py +++ b/tools/test_apps/system/panic/panic_tests.py @@ -73,7 +73,6 @@ def int_wdt_inner(env, test_name): def int_wdt_cache_disabled_inner(env, test_name): with get_dut(env, test_name, 'test_int_wdt_cache_disabled', qemu_wdt_enable=True) as dut: - dut.expect('Re-enable cpu cache.') dut.expect_gme('Interrupt wdt timeout on CPU0') dut.expect_reg_dump(0) dut.expect('Backtrace:') @@ -87,7 +86,6 @@ def int_wdt_cache_disabled_inner(env, test_name): def cache_error_inner(env, test_name): with get_dut(env, test_name, 'test_cache_error') as dut: - dut.expect('Re-enable cpu cache.') dut.expect_gme('Cache disabled but cached memory region accessed') dut.expect_reg_dump(0) dut.expect_backtrace()