From 8e2b416c382fa82bd615e2585cd1a42b331cf54c Mon Sep 17 00:00:00 2001 From: Marius Vikhammer Date: Wed, 15 Apr 2026 15:56:38 +0800 Subject: [PATCH] feat(esp_system): add CPU lockup debug support for esp32h4 and esp32s31 --- components/bootloader_support/CMakeLists.txt | 1 + .../private_include/bootloader_init.h | 7 +- .../src/bootloader_reset_common.c | 70 +++++++++++++++++++ .../src/esp32/bootloader_esp32.c | 41 ++++------- .../src/esp32c2/bootloader_esp32c2.c | 23 +++--- .../src/esp32c3/bootloader_esp32c3.c | 23 +++--- .../src/esp32c5/bootloader_esp32c5.c | 23 +++--- .../src/esp32c6/bootloader_esp32c6.c | 23 +++--- .../src/esp32c61/bootloader_esp32c61.c | 23 +++--- .../src/esp32h2/bootloader_esp32h2.c | 23 +++--- .../src/esp32h21/bootloader_esp32h21.c | 23 +++--- .../src/esp32h4/bootloader_esp32h4.c | 45 +++++++----- .../src/esp32p4/bootloader_esp32p4.c | 30 +++----- .../src/esp32s2/bootloader_esp32s2.c | 23 +++--- .../src/esp32s3/bootloader_esp32s3.c | 40 ++++------- .../src/esp32s31/bootloader_esp32s31.c | 47 +++++++++++-- .../esp32c6/include/hal/clk_gate_ll.h | 2 +- .../esp32h2/include/hal/clk_gate_ll.h | 2 +- .../esp32h21/include/hal/clk_gate_ll.h | 2 +- .../esp32p4/include/hal/clk_gate_ll.h | 2 +- .../esp_rom/esp32s31/Kconfig.soc_caps.in | 4 ++ components/esp_rom/esp32s31/esp_rom_caps.h | 1 + components/esp_system/CMakeLists.txt | 4 +- .../{hw_stack_guard.c => debug_assist.c} | 43 +++++++++--- components/esp_system/linker.lf | 6 +- components/esp_system/port/soc/esp32c2/clk.c | 2 +- components/esp_system/port/soc/esp32c3/clk.c | 2 +- components/esp_system/system_init_fn.txt | 4 +- .../main/CMakeLists.txt | 21 ++++-- .../esp_system_unity_tests/main/test_panic.c | 36 ++++++++++ .../main/test_reset_reason.c | 3 +- .../pytest_esp_system_unity_tests.py | 34 +++++++++ .../hal/esp32h4/include/hal/assist_debug_ll.h | 68 ++++++++++++++++++ .../esp32s31/include/hal/assist_debug_ll.h | 68 ++++++++++++++++++ .../esp32h4/include/soc/Kconfig.soc_caps.in | 4 ++ components/soc/esp32h4/include/soc/soc_caps.h | 1 + .../esp32s31/include/soc/Kconfig.soc_caps.in | 4 ++ .../soc/esp32s31/include/soc/soc_caps.h | 1 + 38 files changed, 533 insertions(+), 246 deletions(-) create mode 100644 components/bootloader_support/src/bootloader_reset_common.c rename components/esp_system/{hw_stack_guard.c => debug_assist.c} (76%) create mode 100644 components/esp_system/test_apps/esp_system_unity_tests/main/test_panic.c diff --git a/components/bootloader_support/CMakeLists.txt b/components/bootloader_support/CMakeLists.txt index 512aab702a..4f4f71702d 100644 --- a/components/bootloader_support/CMakeLists.txt +++ b/components/bootloader_support/CMakeLists.txt @@ -84,6 +84,7 @@ if(BOOTLOADER_BUILD OR CONFIG_APP_BUILD_TYPE_RAM) list(APPEND priv_requires esp_hal_wdt esp_hal_gpio esp_hal_uart esp_hal_ana_conv esp_hal_rtc_timer esp_hal_clock esp_hal_security) list(APPEND srcs + "src/bootloader_reset_common.c" "src/bootloader_init.c" "src/bootloader_clock_loader.c" "src/bootloader_console.c" diff --git a/components/bootloader_support/private_include/bootloader_init.h b/components/bootloader_support/private_include/bootloader_init.h index 09938891e5..09d6455767 100644 --- a/components/bootloader_support/private_include/bootloader_init.h +++ b/components/bootloader_support/private_include/bootloader_init.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2018-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2018-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,6 +7,7 @@ #include "esp_err.h" #include "esp_image_format.h" +#include "soc/reset_reasons.h" #ifdef __cplusplus extern "C" { @@ -37,6 +38,10 @@ extern esp_image_header_t bootloader_image_hdr; esp_err_t bootloader_read_bootloader_header(void); esp_err_t bootloader_check_bootloader_validity(void); void bootloader_clear_bss_section(void); +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t reset_reason); +void bootloader_dump_wdt_reset_info(int cpu); +void bootloader_enable_cpu_reset_info(void); +void bootloader_check_reset(void); void bootloader_config_wdt(void); void bootloader_enable_random(void); void bootloader_print_banner(void); diff --git a/components/bootloader_support/src/bootloader_reset_common.c b/components/bootloader_support/src/bootloader_reset_common.c new file mode 100644 index 0000000000..d2c5e0db20 --- /dev/null +++ b/components/bootloader_support/src/bootloader_reset_common.c @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "sdkconfig.h" +#include "esp_log.h" +#include "esp_rom_sys.h" +#include "soc/soc_caps.h" +#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED +#include "hal/assist_debug_ll.h" +#include "esp_rom_caps.h" +#endif +#include "bootloader_init.h" + +ESP_LOG_ATTR_TAG(TAG, "boot"); + +#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED && !ESP_ROM_PRINTS_LOCKUP_STATUS +static void lockup_info_dump(int cpu) +{ + const char *cpu_name = cpu ? "APP" : "PRO"; + + ESP_LOGW(TAG, "%s CPU reset due to CPU lockup (exception inside exception handler).", cpu_name); + ESP_LOGW(TAG, "%s CPU trap chain:", cpu_name); + for (int i = 0; i < 2; i++) { + uint32_t cause = assist_debug_ll_lockup_get_cause(cpu, i); + uint32_t tval = assist_debug_ll_lockup_get_tval(cpu, i); + uint32_t iaddr = assist_debug_ll_lockup_get_iaddr(cpu, i); + uint32_t priv = assist_debug_ll_lockup_get_priv(cpu, i); + const char *label = i == 0 ? "latest" : "previous"; + + ESP_LOGW(TAG, " [%s trap] cause=0x%02"PRIx32" PCAddr=0x%08"PRIx32" tval=0x%08"PRIx32" priv=%"PRIu32, + label, cause, iaddr, tval, priv); + } +} +#endif + +void bootloader_check_reset(void) +{ + bool any_wdt_reset = false; + soc_reset_reason_t reset_reason; + + reset_reason = esp_rom_get_reset_reason(0); + any_wdt_reset |= bootloader_check_if_wdt_reset(0, reset_reason); +#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED && !ESP_ROM_PRINTS_LOCKUP_STATUS + if (reset_reason == RESET_REASON_CPU_LOCKUP) { + lockup_info_dump(0); + } +#endif + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + reset_reason = esp_rom_get_reset_reason(1); + any_wdt_reset |= bootloader_check_if_wdt_reset(1, reset_reason); +#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED && !ESP_ROM_PRINTS_LOCKUP_STATUS + if (reset_reason == RESET_REASON_CPU_LOCKUP) { + lockup_info_dump(1); + } +#endif +#endif + + if (any_wdt_reset) { + bootloader_dump_wdt_reset_info(0); +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + bootloader_dump_wdt_reset_info(1); +#endif + } + + bootloader_enable_cpu_reset_info(); +} diff --git a/components/bootloader_support/src/esp32/bootloader_esp32.c b/components/bootloader_support/src/esp32/bootloader_esp32.c index 45bbcde115..af973a33f6 100644 --- a/components/bootloader_support/src/esp32/bootloader_esp32.c +++ b/components/bootloader_support/src/esp32/bootloader_esp32.c @@ -91,14 +91,14 @@ static inline esp_err_t bootloader_check_rated_cpu_clock(void) } #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { //We do not reset core1 info here because it didn't work before cpu1 was up. So we put it into call_start_cpu1. DPORT_REG_SET_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_PDEBUG_ENABLE | DPORT_PRO_CPU_RECORD_ENABLE); DPORT_REG_CLR_BIT(DPORT_PRO_CPU_RECORD_CTRL_REG, DPORT_PRO_CPU_RECORD_ENABLE); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0, lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 0; @@ -145,32 +145,23 @@ static void wdt_reset_info_dump(int cpu) ESP_LOGD(TAG, "WDT rst info: %s CPU PDEBUGLS0DATA 0x%08"PRIx32, cpu_name, lsdata); } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reas[2]; - - rst_reas[0] = esp_rom_get_reset_reason(0); - rst_reas[1] = esp_rom_get_reset_reason(1); - if (rst_reas[0] == RESET_REASON_CORE_RTC_WDT || rst_reas[0] == RESET_REASON_CORE_MWDT0 || rst_reas[0] == RESET_REASON_CORE_MWDT1 || - rst_reas[0] == RESET_REASON_CPU0_MWDT0 || rst_reas[0] == RESET_REASON_CPU0_RTC_WDT) { + if (cpu == 0 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || + rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 || + rst_reason == RESET_REASON_CPU0_RTC_WDT)) { ESP_LOGW(TAG, "PRO CPU has been reset by WDT"); - wdt_rst = 1; + return true; } - if (rst_reas[1] == RESET_REASON_CORE_RTC_WDT || rst_reas[1] == RESET_REASON_CORE_MWDT0 || rst_reas[1] == RESET_REASON_CORE_MWDT1 || - rst_reas[1] == RESET_REASON_CPU1_MWDT1 || rst_reas[1] == RESET_REASON_CPU1_RTC_WDT) { + if (cpu == 1 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || + rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU1_MWDT1 || + rst_reason == RESET_REASON_CPU1_RTC_WDT)) { ESP_LOGW(TAG, "APP CPU has been reset by WDT"); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); -#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE - wdt_reset_info_dump(1); -#endif - } - wdt_reset_cpu0_info_enable(); + return false; } + #endif // SOC_RTC_WDT_SUPPORTED esp_err_t bootloader_init(void) @@ -244,10 +235,8 @@ esp_err_t bootloader_init(void) } #endif // #if !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32c2/bootloader_esp32c2.c b/components/bootloader_support/src/esp32c2/bootloader_esp32c2.c index 7d4b0496d6..8ab40e7ddd 100644 --- a/components/bootloader_support/src/esp32c2/bootloader_esp32c2.c +++ b/components/bootloader_support/src/esp32c2/bootloader_esp32c2.c @@ -42,34 +42,29 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32c2"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { REG_SET_BIT(SYSTEM_CPU_PERI_CLK_EN_REG, SYSTEM_CLK_EN_ASSIST_DEBUG); REG_CLR_BIT(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG); REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { (void) cpu; // saved PC was already printed by the ROM bootloader. // nothing to do here. } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + (void) cpu; if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_RTC_WDT) { ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -141,10 +136,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c b/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c index c2b51d50a8..d13a910275 100644 --- a/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c +++ b/components/bootloader_support/src/esp32c3/bootloader_esp32c3.c @@ -47,34 +47,29 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32c3"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { REG_SET_BIT(SYSTEM_CPU_PERI_CLK_EN_REG, SYSTEM_CLK_EN_ASSIST_DEBUG); REG_CLR_BIT(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG); REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { (void) cpu; // saved PC was already printed by the ROM bootloader. // nothing to do here. } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + (void) cpu; if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) { ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -185,10 +180,8 @@ esp_err_t bootloader_init(void) } #endif //#if !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32c5/bootloader_esp32c5.c b/components/bootloader_support/src/esp32c5/bootloader_esp32c5.c index 7dd56f8012..b8b53a851a 100644 --- a/components/bootloader_support/src/esp32c5/bootloader_esp32c5.c +++ b/components/bootloader_support/src/esp32c5/bootloader_esp32c5.c @@ -47,34 +47,29 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32c5"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN); REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN); REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { (void) cpu; // saved PC was already printed by the ROM bootloader. // nothing to do here. } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + (void) cpu; if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) { ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -169,10 +164,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32c6/bootloader_esp32c6.c b/components/bootloader_support/src/esp32c6/bootloader_esp32c6.c index d5ff1e8935..71007a966d 100644 --- a/components/bootloader_support/src/esp32c6/bootloader_esp32c6.c +++ b/components/bootloader_support/src/esp32c6/bootloader_esp32c6.c @@ -49,34 +49,29 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32c6"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN); REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN); REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { (void) cpu; // saved PC was already printed by the ROM bootloader. // nothing to do here. } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + (void) cpu; if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) { ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -169,10 +164,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32c61/bootloader_esp32c61.c b/components/bootloader_support/src/esp32c61/bootloader_esp32c61.c index 6a2c45c04d..a7d81d5904 100644 --- a/components/bootloader_support/src/esp32c61/bootloader_esp32c61.c +++ b/components/bootloader_support/src/esp32c61/bootloader_esp32c61.c @@ -49,34 +49,29 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32c61"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN); REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN); REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { (void) cpu; // saved PC was already printed by the ROM bootloader. // nothing to do here. } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + (void) cpu; if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) { ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -161,10 +156,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32h2/bootloader_esp32h2.c b/components/bootloader_support/src/esp32h2/bootloader_esp32h2.c index 4b7a057b28..e58dbe10f2 100644 --- a/components/bootloader_support/src/esp32h2/bootloader_esp32h2.c +++ b/components/bootloader_support/src/esp32h2/bootloader_esp32h2.c @@ -48,34 +48,29 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32h2"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN); REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN); REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { (void) cpu; // saved PC was already printed by the ROM bootloader. // nothing to do here. } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + (void) cpu; if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) { ESP_EARLY_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -166,10 +161,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM - // check whether a WDT reset happened -#if SOC_RTC_WDT_SUPPORTED - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32h21/bootloader_esp32h21.c b/components/bootloader_support/src/esp32h21/bootloader_esp32h21.c index d321da19d3..a1e8dad905 100644 --- a/components/bootloader_support/src/esp32h21/bootloader_esp32h21.c +++ b/components/bootloader_support/src/esp32h21/bootloader_esp32h21.c @@ -48,34 +48,29 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32h21"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { REG_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN); REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_EN); REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_EN_REG, ASSIST_DEBUG_CORE_0_RCD_PDEBUGEN | ASSIST_DEBUG_CORE_0_RCD_RECORDEN); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { (void) cpu; // saved PC was already printed by the ROM bootloader. // nothing to do here. } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + (void) cpu; if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) { ESP_EARLY_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -163,10 +158,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32h4/bootloader_esp32h4.c b/components/bootloader_support/src/esp32h4/bootloader_esp32h4.c index 76229966db..aca55b6964 100644 --- a/components/bootloader_support/src/esp32h4/bootloader_esp32h4.c +++ b/components/bootloader_support/src/esp32h4/bootloader_esp32h4.c @@ -44,43 +44,54 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32h4"); -#if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +#if SOC_RTC_WDT_SUPPORTED || SOC_CPU_LOCKUP_DEBUG_SUPPORTED +void bootloader_enable_cpu_reset_info(void) { assist_debug_ll_enable_bus_clock(0, true); assist_debug_ll_enable_pc_recording(0, true); + assist_debug_ll_lockup_monitor_enable(0, true); + assist_debug_ll_lockup_reset_enable(0); +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + assist_debug_ll_enable_bus_clock(1, true); + assist_debug_ll_enable_pc_recording(1, true); + assist_debug_ll_lockup_monitor_enable(1, true); + assist_debug_ll_lockup_reset_enable(1); +#endif } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { (void) cpu; // saved PC was already printed by the ROM bootloader. // nothing to do here. } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t reset_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); - if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 || - rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) { + if (cpu == 0 && (reset_reason == RESET_REASON_CORE_RTC_WDT || reset_reason == RESET_REASON_CORE_MWDT0 || + reset_reason == RESET_REASON_CORE_MWDT1 || reset_reason == RESET_REASON_CPU0_MWDT0 || + reset_reason == RESET_REASON_CPU0_MWDT1 || reset_reason == RESET_REASON_CPU0_RTC_WDT)) { ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); + if (cpu == 1 && (reset_reason == RESET_REASON_CORE_RTC_WDT || reset_reason == RESET_REASON_CORE_MWDT0 || + reset_reason == RESET_REASON_CORE_MWDT1 || reset_reason == RESET_REASON_CPU0_MWDT0 || + reset_reason == RESET_REASON_CPU0_MWDT1 || reset_reason == RESET_REASON_CPU0_RTC_WDT)) { + ESP_LOGW(TAG, "APP CPU has been reset by WDT."); + return true; } - wdt_reset_cpu0_info_enable(); + return false; } +#if SOC_RTC_WDT_SUPPORTED static void bootloader_super_wdt_auto_feed(void) { REG_WRITE(LP_WDT_SWD_WPROTECT_REG, LP_WDT_SWD_WKEY_VALUE); REG_SET_BIT(LP_WDT_SWD_CONFIG_REG, LP_WDT_SWD_AUTO_FEED_EN); REG_WRITE(LP_WDT_SWD_WPROTECT_REG, 0); } -#endif // SOC_RTC_WDT_SUPPORTED +#endif +#endif // SOC_RTC_WDT_SUPPORTED || SOC_CPU_LOCKUP_DEBUG_SUPPORTED static inline void bootloader_hardware_init(void) { @@ -178,10 +189,8 @@ esp_err_t bootloader_init(void) #endif // !CONFIG_APP_BUILD_TYPE_RAM bootloader_config_dcache(); bootloader_config_icache1(); -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c b/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c index c7a2b3a8f1..e5c17522ee 100644 --- a/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c +++ b/components/bootloader_support/src/esp32p4/bootloader_esp32p4.c @@ -55,36 +55,28 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32p4"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { _assist_debug_ll_enable_bus_clock(0, true); assist_debug_ll_enable_pc_recording(0, true); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { (void) cpu; // saved PC was already printed by the ROM bootloader. // nothing to do here. } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); - if (rst_reason == RESET_REASON_CPU_MWDT || rst_reason == RESET_REASON_CPU_RWDT || rst_reason == RESET_REASON_CORE_MWDT || - rst_reason == RESET_REASON_CORE_RWDT || rst_reason == RESET_REASON_SYS_RWDT) { + if (cpu == 0 && (rst_reason == RESET_REASON_CPU_MWDT || rst_reason == RESET_REASON_CPU_RWDT || + rst_reason == RESET_REASON_CORE_MWDT || rst_reason == RESET_REASON_CORE_RWDT || + rst_reason == RESET_REASON_SYS_RWDT)) { ESP_LOGW(TAG, "CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); -#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE - wdt_reset_info_dump(1); -#endif - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -187,10 +179,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c index b1584b4251..b18965768b 100644 --- a/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c +++ b/components/bootloader_support/src/esp32s2/bootloader_esp32s2.c @@ -42,7 +42,7 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32s2"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { DPORT_REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_ASSIST_DEBUG); DPORT_REG_CLR_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_ASSIST_DEBUG); @@ -50,7 +50,7 @@ static void wdt_reset_cpu0_info_enable(void) REG_WRITE(ASSIST_DEBUG_PRO_RCD_RECORDING, 1); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0, lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 0; @@ -83,20 +83,15 @@ static void wdt_reset_info_dump(int cpu) ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08"PRIx32, cpu_name, lsdata); } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); + (void) cpu; if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_MWDT1 || rst_reason == RESET_REASON_CPU0_RTC_WDT) { ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -169,10 +164,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32s3/bootloader_esp32s3.c b/components/bootloader_support/src/esp32s3/bootloader_esp32s3.c index 2292c2ca33..de6ff9cfdc 100644 --- a/components/bootloader_support/src/esp32s3/bootloader_esp32s3.c +++ b/components/bootloader_support/src/esp32s3/bootloader_esp32s3.c @@ -48,7 +48,7 @@ ESP_LOG_ATTR_TAG(TAG, "boot.esp32s3"); #if SOC_RTC_WDT_SUPPORTED -static void wdt_reset_cpu0_info_enable(void) +void bootloader_enable_cpu_reset_info(void) { REG_SET_BIT(SYSTEM_CPU_PERI_CLK_EN_REG, SYSTEM_CLK_EN_ASSIST_DEBUG); REG_CLR_BIT(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG); @@ -56,7 +56,7 @@ static void wdt_reset_cpu0_info_enable(void) REG_WRITE(ASSIST_DEBUG_CORE_0_RCD_RECORDING_REG, 1); } -static void wdt_reset_info_dump(int cpu) +void bootloader_dump_wdt_reset_info(int cpu) { uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0, lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 0; @@ -98,31 +98,21 @@ static void wdt_reset_info_dump(int cpu) ESP_LOGD(TAG, "WDT reset info: %s CPU PDEBUGLS0DATA 0x%08"PRIx32, cpu_name, lsdata); } -static void bootloader_check_wdt_reset(void) +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t rst_reason) { - int wdt_rst = 0; - soc_reset_reason_t rst_reas[2]; - - rst_reas[0] = esp_rom_get_reset_reason(0); - rst_reas[1] = esp_rom_get_reset_reason(1); - if (rst_reas[0] == RESET_REASON_CORE_RTC_WDT || rst_reas[0] == RESET_REASON_CORE_MWDT0 || rst_reas[0] == RESET_REASON_CORE_MWDT1 || - rst_reas[0] == RESET_REASON_CPU0_MWDT0 || rst_reas[0] == RESET_REASON_CPU0_RTC_WDT) { + if (cpu == 0 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || + rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 || + rst_reason == RESET_REASON_CPU0_RTC_WDT)) { ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (rst_reas[1] == RESET_REASON_CORE_RTC_WDT || rst_reas[1] == RESET_REASON_CORE_MWDT0 || rst_reas[1] == RESET_REASON_CORE_MWDT1 || - rst_reas[1] == RESET_REASON_CPU1_MWDT1 || rst_reas[1] == RESET_REASON_CPU1_RTC_WDT) { + if (cpu == 1 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || + rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU1_MWDT1 || + rst_reason == RESET_REASON_CPU1_RTC_WDT)) { ESP_LOGW(TAG, "APP CPU has been reset by WDT."); - wdt_rst = 1; + return true; } - if (wdt_rst) { - // if reset by WDT dump info from trace port - wdt_reset_info_dump(0); -#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE - wdt_reset_info_dump(1); -#endif - } - wdt_reset_cpu0_info_enable(); + return false; } static void bootloader_super_wdt_auto_feed(void) @@ -208,10 +198,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - bootloader_check_wdt_reset(); -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/bootloader_support/src/esp32s31/bootloader_esp32s31.c b/components/bootloader_support/src/esp32s31/bootloader_esp32s31.c index bb20bb8ca8..642c685d85 100644 --- a/components/bootloader_support/src/esp32s31/bootloader_esp32s31.c +++ b/components/bootloader_support/src/esp32s31/bootloader_esp32s31.c @@ -26,6 +26,9 @@ #include "soc/pmu_reg.h" #include "hal/regi2c_ctrl_ll.h" #include "hal/modem_lpcon_ll.h" +#include "soc/reset_reasons.h" +#include "hal/assist_debug_ll.h" +#include "esp_rom_sys.h" ESP_LOG_ATTR_TAG(TAG, "boot.esp32s31"); @@ -44,6 +47,44 @@ static inline void bootloader_hardware_init(void) #endif } +void bootloader_enable_cpu_reset_info(void) +{ + assist_debug_ll_enable_bus_clock(0, true); + assist_debug_ll_enable_pc_recording(0, true); + assist_debug_ll_lockup_monitor_enable(0, true); + assist_debug_ll_lockup_reset_enable(0); +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + assist_debug_ll_enable_bus_clock(1, true); + assist_debug_ll_enable_pc_recording(1, true); + assist_debug_ll_lockup_monitor_enable(1, true); + assist_debug_ll_lockup_reset_enable(1); +#endif +} + +void bootloader_dump_wdt_reset_info(int cpu) +{ + (void) cpu; + // saved PC was already printed by the ROM bootloader. + // nothing to do here. +} + +bool bootloader_check_if_wdt_reset(int cpu, soc_reset_reason_t reset_reason) +{ + if (cpu == 0 && (reset_reason == RESET_REASON_CORE_MWDT0 || reset_reason == RESET_REASON_CORE_MWDT1 || + reset_reason == RESET_REASON_CORE_RWDT || reset_reason == RESET_REASON_CPU_MWDT || + reset_reason == RESET_REASON_CPU_RWDT || reset_reason == RESET_REASON_SYS_RWDT)) { + ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); + return true; + } + if (cpu == 1 && (reset_reason == RESET_REASON_CORE_MWDT0 || reset_reason == RESET_REASON_CORE_MWDT1 || + reset_reason == RESET_REASON_CORE_RWDT || reset_reason == RESET_REASON_CPU_MWDT || + reset_reason == RESET_REASON_CPU_RWDT || reset_reason == RESET_REASON_SYS_RWDT)) { + ESP_LOGW(TAG, "APP CPU has been reset by WDT."); + return true; + } + return false; +} + #if SOC_RTC_WDT_SUPPORTED static void bootloader_super_wdt_auto_feed(void) { @@ -112,10 +153,8 @@ esp_err_t bootloader_init(void) } #endif // !CONFIG_APP_BUILD_TYPE_RAM -#if SOC_RTC_WDT_SUPPORTED - // check whether a WDT reset happened - // bootloader_check_wdt_reset(); // TODO: IDF-14678 -#endif + // check reset reason and dump diagnostic info + bootloader_check_reset(); #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED // config WDT bootloader_config_wdt(); diff --git a/components/esp_hal_clock/esp32c6/include/hal/clk_gate_ll.h b/components/esp_hal_clock/esp32c6/include/hal/clk_gate_ll.h index 6cb994ba07..8f6972ff06 100644 --- a/components/esp_hal_clock/esp32c6/include/hal/clk_gate_ll.h +++ b/components/esp_hal_clock/esp32c6/include/hal/clk_gate_ll.h @@ -200,7 +200,7 @@ static inline void periph_ll_clk_gate_set_default(soc_reset_reason_t rst_reason, if (config->disable_assist_clk) { /* Disable ASSIST Debug module clock if PC recoreding function is not used, - * if stack guard function needs it, it will be re-enabled at esp_hw_stack_guard_init */ + * if stack guard function needs it, it will be re-enabled at esp_hw_debug_assist_init */ PCR.assist_conf.assist_clk_en = 0; } diff --git a/components/esp_hal_clock/esp32h2/include/hal/clk_gate_ll.h b/components/esp_hal_clock/esp32h2/include/hal/clk_gate_ll.h index aa4b1ecb83..47a83bc17f 100644 --- a/components/esp_hal_clock/esp32h2/include/hal/clk_gate_ll.h +++ b/components/esp_hal_clock/esp32h2/include/hal/clk_gate_ll.h @@ -174,7 +174,7 @@ static inline void periph_ll_clk_gate_set_default(soc_reset_reason_t rst_reason, if (config->disable_assist_clk) { /* Disable ASSIST Debug module clock if PC recoreding function is not used, - * if stack guard function needs it, it will be re-enabled at esp_hw_stack_guard_init */ + * if stack guard function needs it, it will be re-enabled at esp_hw_debug_assist_init */ PCR.assist_conf.assist_clk_en = 0; } diff --git a/components/esp_hal_clock/esp32h21/include/hal/clk_gate_ll.h b/components/esp_hal_clock/esp32h21/include/hal/clk_gate_ll.h index eaa191784d..0acf7bc4df 100644 --- a/components/esp_hal_clock/esp32h21/include/hal/clk_gate_ll.h +++ b/components/esp_hal_clock/esp32h21/include/hal/clk_gate_ll.h @@ -166,7 +166,7 @@ static inline void periph_ll_clk_gate_set_default(soc_reset_reason_t rst_reason, if (config->disable_assist_clk) { /* Disable ASSIST Debug module clock if PC recording is not used; - * stack guard may re-enable in esp_hw_stack_guard_init */ + * stack guard may re-enable in esp_hw_debug_assist_init */ PCR.assist_conf.assist_clk_en = 0; } diff --git a/components/esp_hal_clock/esp32p4/include/hal/clk_gate_ll.h b/components/esp_hal_clock/esp32p4/include/hal/clk_gate_ll.h index 3e3e1c3082..f2e17f105d 100644 --- a/components/esp_hal_clock/esp32p4/include/hal/clk_gate_ll.h +++ b/components/esp_hal_clock/esp32p4/include/hal/clk_gate_ll.h @@ -291,7 +291,7 @@ static inline void periph_ll_clk_gate_set_default(soc_reset_reason_t rst_reason, if (config->disable_assist_clk) { /* Disable ASSIST Debug module clock if PC recoreding function is not used, - * if stack guard function needs it, it will be re-enabled at esp_hw_stack_guard_init */ + * if stack guard function needs it, it will be re-enabled at esp_hw_debug_assist_init */ REG_CLR_BIT(HP_SYS_CLKRST_SOC_CLK_CTRL0_REG, HP_SYS_CLKRST_REG_BUSMON_CPU_CLK_EN); REG_CLR_BIT(ASSIST_DEBUG_CLOCK_GATE_REG, ASSIST_DEBUG_CLK_EN); } diff --git a/components/esp_rom/esp32s31/Kconfig.soc_caps.in b/components/esp_rom/esp32s31/Kconfig.soc_caps.in index 9d4d933fb3..4706a00e0d 100644 --- a/components/esp_rom/esp32s31/Kconfig.soc_caps.in +++ b/components/esp_rom/esp32s31/Kconfig.soc_caps.in @@ -74,3 +74,7 @@ config ESP_ROM_HAS_VERSION config ESP_ROM_MULTI_HEAP_WALK_PATCH bool default y + +config ESP_ROM_PRINTS_LOCKUP_STATUS + bool + default y diff --git a/components/esp_rom/esp32s31/esp_rom_caps.h b/components/esp_rom/esp32s31/esp_rom_caps.h index c165e4e3a2..4471feac56 100644 --- a/components/esp_rom/esp32s31/esp_rom_caps.h +++ b/components/esp_rom/esp32s31/esp_rom_caps.h @@ -24,3 +24,4 @@ #define ESP_ROM_HAS_NEWLIB_NANO_FORMAT (1) // ROM has the newlib nano version of formatting functions #define ESP_ROM_HAS_VERSION (1) // ROM has version/eco information #define ESP_ROM_MULTI_HEAP_WALK_PATCH (1) // ROM does not contain the patch of multi_heap_walk() +#define ESP_ROM_PRINTS_LOCKUP_STATUS (1) // ROM bootloader already prints CPU lockup diagnostic status diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index b5bbfa9663..cc435662c9 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -83,8 +83,8 @@ else() list(APPEND srcs "systick_etm.c") endif() - if(CONFIG_ESP_SYSTEM_HW_STACK_GUARD) - list(APPEND srcs "hw_stack_guard.c") + if(CONFIG_ESP_SYSTEM_HW_STACK_GUARD OR CONFIG_ESP_SYSTEM_HW_PC_RECORD OR CONFIG_SOC_CPU_LOCKUP_DEBUG_SUPPORTED) + list(APPEND srcs "debug_assist.c") endif() idf_component_register(SRCS "${srcs}" diff --git a/components/esp_system/hw_stack_guard.c b/components/esp_system/debug_assist.c similarity index 76% rename from components/esp_system/hw_stack_guard.c rename to components/esp_system/debug_assist.c index a6fb9dcfa6..28a442be90 100644 --- a/components/esp_system/hw_stack_guard.c +++ b/components/esp_system/debug_assist.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include "hal/assist_debug_hal.h" +#include "hal/assist_debug_ll.h" #include "esp_private/hw_stack_guard.h" #include "esp_private/periph_ctrl.h" #include "esp_private/startup_internal.h" @@ -12,12 +13,8 @@ #include "esp_rom_sys.h" #include "esp_cpu.h" -ESP_SYSTEM_INIT_FN(esp_hw_stack_guard_init, SECONDARY, ESP_SYSTEM_INIT_ALL_CORES, 101) +static void esp_hw_debug_assist_enable_module(uint32_t core_id) { - uint32_t core_id = esp_cpu_get_core_id(); - - ESP_INTR_DISABLE(ETS_ASSIST_DEBUG_INUM); - #if SOC_CPU_CORES_NUM > 1 PERIPH_RCC_ATOMIC() #endif @@ -25,16 +22,20 @@ ESP_SYSTEM_INIT_FN(esp_hw_stack_guard_init, SECONDARY, ESP_SYSTEM_INIT_ALL_CORES assist_debug_ll_enable_bus_clock(core_id, true); assist_debug_ll_reset_register(core_id); } +} - assist_debug_ll_enable_pc_recording(core_id, true); +#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD +static void esp_hw_stack_guard_init(uint32_t core_id) +{ + ESP_INTR_DISABLE(ETS_ASSIST_DEBUG_INUM); - /* set interrupt to matrix */ + /* Set interrupt to matrix. */ esp_rom_route_intr_matrix(core_id, ETS_ASSIST_DEBUG_INTR_SOURCE, ETS_ASSIST_DEBUG_INUM); esprv_int_set_type(ETS_ASSIST_DEBUG_INUM, INTR_TYPE_LEVEL); esprv_int_set_priority(ETS_ASSIST_DEBUG_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); /* - * enable interrupt + * Enable interrupt. * Note: to control hw_stack_guard use monitor enable/disable because in case: * - monitor == active * - interrupt != active @@ -46,6 +47,27 @@ ESP_SYSTEM_INIT_FN(esp_hw_stack_guard_init, SECONDARY, ESP_SYSTEM_INIT_ALL_CORES assist_debug_hal_sp_int_enable(core_id); ESP_INTR_ENABLE(ETS_ASSIST_DEBUG_INUM); +} +#endif + +ESP_SYSTEM_INIT_FN(esp_hw_debug_assist_init, SECONDARY, ESP_SYSTEM_INIT_ALL_CORES, 101) +{ + uint32_t core_id = esp_cpu_get_core_id(); + + esp_hw_debug_assist_enable_module(core_id); + +#if CONFIG_ESP_SYSTEM_HW_PC_RECORD + assist_debug_ll_enable_pc_recording(core_id, true); +#endif + +#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD + esp_hw_stack_guard_init(core_id); +#endif + +#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED + assist_debug_ll_lockup_monitor_enable(core_id, true); +#endif + return ESP_OK; } @@ -56,14 +78,15 @@ void esp_hw_stack_guard_monitor_start(void) { uint32_t core_id = esp_cpu_get_core_id(); - /* enable monitor. Interrupt is always enabled (see comment in esp_hw_stack_guard_init()) */ + /* Enable monitor. Interrupt is configured during assist-debug init. */ assist_debug_hal_sp_mon_enable(core_id); } void esp_hw_stack_guard_monitor_stop(void) { uint32_t core_id = esp_cpu_get_core_id(); - /* disable monitor. Interrupt is always enabled (see comment in esp_hw_stack_guard_init()) */ + + /* Disable monitor. Interrupt is configured during assist-debug init. */ assist_debug_hal_sp_mon_disable(core_id); } diff --git a/components/esp_system/linker.lf b/components/esp_system/linker.lf index 15276c7851..226113e4ce 100644 --- a/components/esp_system/linker.lf +++ b/components/esp_system/linker.lf @@ -8,9 +8,9 @@ entries: cache_err_int (noflash) reset_reason:esp_reset_reason_get_hint (noflash) if ESP_SYSTEM_HW_STACK_GUARD = y: - hw_stack_guard:esp_hw_stack_guard_get_bounds (noflash) - hw_stack_guard:esp_hw_stack_guard_get_fired_cpu (noflash) - hw_stack_guard:esp_hw_stack_guard_get_pc (noflash) + debug_assist:esp_hw_stack_guard_get_bounds (noflash) + debug_assist:esp_hw_stack_guard_get_fired_cpu (noflash) + debug_assist:esp_hw_stack_guard_get_pc (noflash) # These functions are called when the cache is disabled system_internal:esp_restart_noos (noflash) diff --git a/components/esp_system/port/soc/esp32c2/clk.c b/components/esp_system/port/soc/esp32c2/clk.c index 1d915210d0..04fcdc051f 100644 --- a/components/esp_system/port/soc/esp32c2/clk.c +++ b/components/esp_system/port/soc/esp32c2/clk.c @@ -257,7 +257,7 @@ __attribute__((weak)) void esp_perip_clk_init(void) #if !CONFIG_ESP_SYSTEM_HW_PC_RECORD /* Disable ASSIST Debug module clock if PC recoreding function is not used, - * if stack guard function needs it, it will be re-enabled at esp_hw_stack_guard_init */ + * if stack guard function needs it, it will be re-enabled at esp_hw_debug_assist_init */ CLEAR_PERI_REG_MASK(SYSTEM_CPU_PERI_CLK_EN_REG, SYSTEM_CLK_EN_ASSIST_DEBUG); SET_PERI_REG_MASK(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG); #endif diff --git a/components/esp_system/port/soc/esp32c3/clk.c b/components/esp_system/port/soc/esp32c3/clk.c index b3d3ca2857..b35b9e2d21 100644 --- a/components/esp_system/port/soc/esp32c3/clk.c +++ b/components/esp_system/port/soc/esp32c3/clk.c @@ -299,7 +299,7 @@ __attribute__((weak)) void esp_perip_clk_init(void) #if !CONFIG_ESP_SYSTEM_HW_PC_RECORD /* Disable ASSIST Debug module clock if PC recoreding function is not used, - * if stack guard function needs it, it will be re-enabled at esp_hw_stack_guard_init */ + * if stack guard function needs it, it will be re-enabled at esp_hw_debug_assist_init */ CLEAR_PERI_REG_MASK(SYSTEM_CPU_PERI_CLK_EN_REG, SYSTEM_CLK_EN_ASSIST_DEBUG); SET_PERI_REG_MASK(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG); #endif diff --git a/components/esp_system/system_init_fn.txt b/components/esp_system/system_init_fn.txt index 661862b2b4..e28a73a22d 100644 --- a/components/esp_system/system_init_fn.txt +++ b/components/esp_system/system_init_fn.txt @@ -72,8 +72,8 @@ CORE: 170: init_xt_wdt in components/esp_system/startup_funcs.c on BIT(0) # esp_timer has to be initialized early, since it is used by several other components SECONDARY: 100: esp_timer_init_os in components/esp_timer/src/esp_timer.c on ESP_TIMER_INIT_MASK -# HW stack guard via assist-debug module. -SECONDARY: 101: esp_hw_stack_guard_init in components/esp_system/hw_stack_guard.c on ESP_SYSTEM_INIT_ALL_CORES +# Assist-debug early init for stack guard and PC recording. +SECONDARY: 101: esp_hw_debug_assist_init in components/esp_system/debug_assist.c on ESP_SYSTEM_INIT_ALL_CORES # Initialize RNG (enable clock which is disabled in `esp_perip_clk_init`, configure entropy sources) SECONDARY: 102: init_rng in components/esp_hw_support/hw_random.c on BIT(0) diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt b/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt index 4542a3dad0..b22dd0124f 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/CMakeLists.txt @@ -8,13 +8,14 @@ set(requires "unity" "esp_psram") set(SRC "test_app_main.c" - "test_backtrace.c" - "test_ipc.c" - "test_reset_reason.c" - "test_shared_stack_printf.c" - "test_stack_check.c" - "test_system_time.c" - "test_task_wdt.c") + "test_backtrace.c" + "test_ipc.c" + "test_panic.c" + "test_reset_reason.c" + "test_shared_stack_printf.c" + "test_stack_check.c" + "test_system_time.c" + "test_task_wdt.c") if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED OR CONFIG_SOC_DEEP_SLEEP_SUPPORTED) list(APPEND SRC "test_sleep.c" @@ -42,3 +43,9 @@ idf_component_register(SRCS ${SRC} PRIV_INCLUDE_DIRS . PRIV_REQUIRES "${requires}" WHOLE_ARCHIVE) + +if(CONFIG_SOC_CPU_LOCKUP_DEBUG_SUPPORTED) + # Wrap esp_panic_handler so the lockup test can inject a second exception + # inside the panic handler. All other panics in the test binary are unaffected. + target_link_options(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=esp_panic_handler") +endif() diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/test_panic.c b/components/esp_system/test_apps/esp_system_unity_tests/main/test_panic.c new file mode 100644 index 0000000000..ddcf731bcd --- /dev/null +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/test_panic.c @@ -0,0 +1,36 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include +#include "sdkconfig.h" +#include "unity.h" +#include "soc/soc_caps.h" + +#if SOC_CPU_LOCKUP_DEBUG_SUPPORTED + +static bool s_trigger_lockup_in_panic; + +/* __wrap_esp_panic_handler intercepts all panics in this test binary. + * Normally it calls through to the real handler. When s_trigger_lockup_in_panic + * is set it causes a second exception inside the handler, which triggers a + * hardware CPU lockup reset. + */ +void __real_esp_panic_handler(void *info); +void __wrap_esp_panic_handler(void *info) +{ + if (s_trigger_lockup_in_panic) { + __asm__ volatile("unimp"); /* exception inside exception handler -> lockup */ + } + __real_esp_panic_handler(info); +} + +TEST_CASE("CPU lockup output", "[cpu_lockup][ignore]") +{ + s_trigger_lockup_in_panic = true; + __asm__ volatile("unimp"); /* first exception -> panic handler -> second exception -> lockup */ +} + +#endif // SOC_CPU_LOCKUP_DEBUG_SUPPORTED diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/test_reset_reason.c b/components/esp_system/test_apps/esp_system_unity_tests/main/test_reset_reason.c index e5e482cb02..baaa1048ea 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/test_reset_reason.c +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/test_reset_reason.c @@ -1,11 +1,12 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ #include "sdkconfig.h" #include #include "unity.h" +#include "soc/soc_caps.h" #include "esp_system.h" #include "esp_task_wdt.h" #include "esp_attr.h" diff --git a/components/esp_system/test_apps/esp_system_unity_tests/pytest_esp_system_unity_tests.py b/components/esp_system/test_apps/esp_system_unity_tests/pytest_esp_system_unity_tests.py index b9a449bb52..6d73284b55 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/pytest_esp_system_unity_tests.py +++ b/components/esp_system/test_apps/esp_system_unity_tests/pytest_esp_system_unity_tests.py @@ -123,6 +123,40 @@ def test_sleep_uart_handling(dut: Dut) -> None: ) +@pytest.mark.generic +@idf_parametrize('config', ['default'], indirect=['config']) +@idf_parametrize( + 'target', + [target for target in soc_filtered_targets('SOC_CPU_LOCKUP_DEBUG_SUPPORTED == 1')], + indirect=['target'], +) +def test_cpu_lockup_trap_chain(dut: Dut) -> None: + """Trigger a PRO CPU lockup and verify the lockup output.""" + esp_reset_and_wait_ready(dut) + dut.write('"CPU lockup output"') + + if dut.target == 'esp32s31': + # ROM should print a non-zero Core0 trap PC for both exceptions. + dut.expect(r'\[Core0\]', timeout=10) + dut.expect(r'1st Exception:', timeout=5) + dut.expect(r'PCAddr:\s+0x(?!00000000)[0-9a-f]{8}', timeout=5) + dut.expect(r'2nd Exception:', timeout=5) + dut.expect(r'PCAddr:\s+0x(?!00000000)[0-9a-f]{8}', timeout=5) + else: + # 2nd stage bootloader should log the trap chain after the lockup reset. + dut.expect('PRO CPU reset due to CPU lockup', timeout=10) + dut.expect('PRO CPU trap chain:', timeout=5) + # Both traps should be illegal instruction (RISC-V mcause=2) + dut.expect( + r'\[latest trap\] cause=0x02 PCAddr=0x(?!00000000)[0-9a-f]{8} tval=0x[0-9a-f]{8} priv=[0-9]+', timeout=5 + ) + dut.expect( + r'\[previous trap\] cause=0x02 PCAddr=0x(?!00000000)[0-9a-f]{8} tval=0x[0-9a-f]{8} priv=[0-9]+', timeout=5 + ) + + dut.expect_exact('Press ENTER to see the list of tests', timeout=30) + + @pytest.mark.generic @idf_parametrize('config', ['default'], indirect=['config']) @idf_parametrize('target', ['supported_targets'], indirect=['target']) diff --git a/components/hal/esp32h4/include/hal/assist_debug_ll.h b/components/hal/esp32h4/include/hal/assist_debug_ll.h index 159e8dc8f2..33c3aa9adb 100644 --- a/components/hal/esp32h4/include/hal/assist_debug_ll.h +++ b/components/hal/esp32h4/include/hal/assist_debug_ll.h @@ -17,6 +17,7 @@ #include "esp_attr.h" #include "soc/pcr_struct.h" #include "soc/bus_monitor_struct.h" +#include "soc/lp_clkrst_struct.h" #ifdef __cplusplus extern "C" { @@ -172,6 +173,73 @@ FORCE_INLINE_ATTR bool assist_debug_ll_is_debugger_active(void) return BUS_MONITOR.monitor_core_0_debug_mode.monitor_core_0_debug_module_active; } +FORCE_INLINE_ATTR void assist_debug_ll_lockup_monitor_enable(uint32_t core_id, bool enable) +{ + if (core_id) { + BUS_MONITOR.monitor_core_1_montr_ena.monitor_core_1_trace_lockup_ena = enable; + } else { + BUS_MONITOR.monitor_core_0_montr_ena.monitor_core_0_trace_lockup_ena = enable; + } +} + +// trap_idx: 0 = latest trap, 1 = previous trap +// MCause for the exception +FORCE_INLINE_ATTR uint32_t assist_debug_ll_lockup_get_cause(uint32_t core_id, int trap_idx) +{ + if (core_id) { + return trap_idx ? BUS_MONITOR.monitor_core_1_trace_lockup_cause_1.monitor_core_1_trace_lockup_recording_cause_1 + : BUS_MONITOR.monitor_core_1_trace_lockup_cause_0.monitor_core_1_trace_lockup_recording_cause_0; + } else { + return trap_idx ? BUS_MONITOR.monitor_core_0_trace_lockup_cause_1.monitor_core_0_trace_lockup_recording_cause_1 + : BUS_MONITOR.monitor_core_0_trace_lockup_cause_0.monitor_core_0_trace_lockup_recording_cause_0; + } +} + +FORCE_INLINE_ATTR uint32_t assist_debug_ll_lockup_get_tval(uint32_t core_id, int trap_idx) +{ + if (core_id) { + return trap_idx ? BUS_MONITOR.monitor_core_1_trace_lockup_tval_1.monitor_core_1_trace_lockup_recording_tval_1 + : BUS_MONITOR.monitor_core_1_trace_lockup_tval_0.monitor_core_1_trace_lockup_recording_tval_0; + } else { + return trap_idx ? BUS_MONITOR.monitor_core_0_trace_lockup_tval_1.monitor_core_0_trace_lockup_recording_tval_1 + : BUS_MONITOR.monitor_core_0_trace_lockup_tval_0.monitor_core_0_trace_lockup_recording_tval_0; + } +} + +FORCE_INLINE_ATTR uint32_t assist_debug_ll_lockup_get_iaddr(uint32_t core_id, int trap_idx) +{ + if (core_id) { + return trap_idx ? BUS_MONITOR.monitor_core_1_trace_lockup_iaddr_1.monitor_core_1_trace_lockup_recording_iaddr_1 + : BUS_MONITOR.monitor_core_1_trace_lockup_iaddr_0.monitor_core_1_trace_lockup_recording_iaddr_0; + } else { + return trap_idx ? BUS_MONITOR.monitor_core_0_trace_lockup_iaddr_1.monitor_core_0_trace_lockup_recording_iaddr_1 + : BUS_MONITOR.monitor_core_0_trace_lockup_iaddr_0.monitor_core_0_trace_lockup_recording_iaddr_0; + } +} + +FORCE_INLINE_ATTR uint32_t assist_debug_ll_lockup_get_priv(uint32_t core_id, int trap_idx) +{ + if (core_id) { + return trap_idx ? BUS_MONITOR.monitor_core_1_trace_lockup_priv_1.monitor_core_1_trace_lockup_recording_priv_1 + : BUS_MONITOR.monitor_core_1_trace_lockup_priv_0.monitor_core_1_trace_lockup_recording_priv_0; + } else { + return trap_idx ? BUS_MONITOR.monitor_core_0_trace_lockup_priv_1.monitor_core_0_trace_lockup_recording_priv_1 + : BUS_MONITOR.monitor_core_0_trace_lockup_priv_0.monitor_core_0_trace_lockup_recording_priv_0; + } +} + +/* Enable the hardware lockup reset for the given core via LP_CLKRST. + * This controls whether a CPU lockup (exception inside exception handler) triggers + * a system reset. Defaults to 1 on H4 but must be set explicitly to be safe. */ +FORCE_INLINE_ATTR void assist_debug_ll_lockup_reset_enable(uint32_t core_id) +{ + if (core_id) { + LP_CLKRST.cpu_core1_reset.hpcore1_lockup_reset_en = 1; + } else { + LP_CLKRST.cpu_core0_reset.hpcore0_lockup_reset_en = 1; + } +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s31/include/hal/assist_debug_ll.h b/components/hal/esp32s31/include/hal/assist_debug_ll.h index a0bdfcb41b..9ce6201762 100644 --- a/components/hal/esp32s31/include/hal/assist_debug_ll.h +++ b/components/hal/esp32s31/include/hal/assist_debug_ll.h @@ -17,6 +17,7 @@ #include "esp_attr.h" #include "soc/hp_sys_clkrst_struct.h" #include "soc/bus_monitor_struct.h" +#include "soc/lp_clkrst_struct.h" #ifdef __cplusplus extern "C" { @@ -172,6 +173,73 @@ FORCE_INLINE_ATTR bool assist_debug_ll_is_debugger_active(void) return BUS_MONITOR.core_0_debug_mode.core_0_debug_module_active; } +FORCE_INLINE_ATTR void assist_debug_ll_lockup_monitor_enable(uint32_t core_id, bool enable) +{ + if (core_id) { + BUS_MONITOR.core_1_montr_ena.core_1_trace_lockup_ena = enable; + } else { + BUS_MONITOR.core_0_montr_ena.core_0_trace_lockup_ena = enable; + } +} + +// trap_idx: 0 = latest trap, 1 = previous trap +// MCause for the exception +FORCE_INLINE_ATTR uint32_t assist_debug_ll_lockup_get_cause(uint32_t core_id, int trap_idx) +{ + if (core_id) { + return trap_idx ? BUS_MONITOR.core_1_trace_lockup_cause_1.core_1_trace_lockup_recording_cause_1 + : BUS_MONITOR.core_1_trace_lockup_cause_0.core_1_trace_lockup_recording_cause_0; + } else { + return trap_idx ? BUS_MONITOR.core_0_trace_lockup_cause_1.core_0_trace_lockup_recording_cause_1 + : BUS_MONITOR.core_0_trace_lockup_cause_0.core_0_trace_lockup_recording_cause_0; + } +} + +FORCE_INLINE_ATTR uint32_t assist_debug_ll_lockup_get_tval(uint32_t core_id, int trap_idx) +{ + if (core_id) { + return trap_idx ? BUS_MONITOR.core_1_trace_lockup_tval_1.core_1_trace_lockup_recording_tval_1 + : BUS_MONITOR.core_1_trace_lockup_tval_0.core_1_trace_lockup_recording_tval_0; + } else { + return trap_idx ? BUS_MONITOR.core_0_trace_lockup_tval_1.core_0_trace_lockup_recording_tval_1 + : BUS_MONITOR.core_0_trace_lockup_tval_0.core_0_trace_lockup_recording_tval_0; + } +} + +FORCE_INLINE_ATTR uint32_t assist_debug_ll_lockup_get_iaddr(uint32_t core_id, int trap_idx) +{ + if (core_id) { + return trap_idx ? BUS_MONITOR.core_1_trace_lockup_iaddr_1.core_1_trace_lockup_recording_iaddr_1 + : BUS_MONITOR.core_1_trace_lockup_iaddr_0.core_1_trace_lockup_recording_iaddr_0; + } else { + return trap_idx ? BUS_MONITOR.core_0_trace_lockup_iaddr_1.core_0_trace_lockup_recording_iaddr_1 + : BUS_MONITOR.core_0_trace_lockup_iaddr_0.core_0_trace_lockup_recording_iaddr_0; + } +} + +FORCE_INLINE_ATTR uint32_t assist_debug_ll_lockup_get_priv(uint32_t core_id, int trap_idx) +{ + if (core_id) { + return trap_idx ? BUS_MONITOR.core_1_trace_lockup_priv_1.core_1_trace_lockup_recording_priv_1 + : BUS_MONITOR.core_1_trace_lockup_priv_0.core_1_trace_lockup_recording_priv_0; + } else { + return trap_idx ? BUS_MONITOR.core_0_trace_lockup_priv_1.core_0_trace_lockup_recording_priv_1 + : BUS_MONITOR.core_0_trace_lockup_priv_0.core_0_trace_lockup_recording_priv_0; + } +} + +/* Enable the hardware lockup reset for the given core via LP_CLKRST. + * This controls whether a CPU lockup (exception inside exception handler) triggers + * a system reset. Defaults to 0 on S31 so must be explicitly set. */ +FORCE_INLINE_ATTR void assist_debug_ll_lockup_reset_enable(uint32_t core_id) +{ + if (core_id) { + LP_CLKRST.hpcore1_reset_ctrl.hpcore1_lockup_reset_en = 1; + } else { + LP_CLKRST.hpcore0_reset_ctrl.hpcore0_lockup_reset_en = 1; + } +} + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index c97a20edaa..5627505d61 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -171,6 +171,10 @@ config SOC_ASSIST_DEBUG_SUPPORTED bool default y +config SOC_CPU_LOCKUP_DEBUG_SUPPORTED + bool + default y + config SOC_WDT_SUPPORTED bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index f81103e9f3..579c7bd939 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -85,6 +85,7 @@ #define SOC_REGI2C_SUPPORTED 1 #define SOC_CLK_TREE_SUPPORTED 1 #define SOC_ASSIST_DEBUG_SUPPORTED 1 +#define SOC_CPU_LOCKUP_DEBUG_SUPPORTED 1 #define SOC_WDT_SUPPORTED 1 #define SOC_RTC_WDT_SUPPORTED 1 #define SOC_SPI_FLASH_SUPPORTED 1 diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index b07cbe31f3..2a291dd827 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -123,6 +123,10 @@ config SOC_ASSIST_DEBUG_SUPPORTED bool default y +config SOC_CPU_LOCKUP_DEBUG_SUPPORTED + bool + default y + config SOC_WDT_SUPPORTED bool default y diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 2449699a9f..7136a6e917 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -86,6 +86,7 @@ // #define SOC_SDMMC_HOST_SUPPORTED 1 // TODO: [ESP32S31] IDF-14705 #define SOC_CLK_TREE_SUPPORTED 1 #define SOC_ASSIST_DEBUG_SUPPORTED 1 +#define SOC_CPU_LOCKUP_DEBUG_SUPPORTED 1 // #define SOC_DEBUG_PROBE_SUPPORTED 1 // TODO: [ESP32S31] IDF-14798 #define SOC_WDT_SUPPORTED 1 #define SOC_RTC_WDT_SUPPORTED 1