feat(esp_system): add CPU lockup debug support for esp32h4 and esp32s31

This commit is contained in:
Marius Vikhammer
2026-04-15 15:56:38 +08:00
parent 38e2cacc27
commit 8e2b416c38
38 changed files with 533 additions and 246 deletions
@@ -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 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) esp_hal_clock esp_hal_security)
list(APPEND srcs list(APPEND srcs
"src/bootloader_reset_common.c"
"src/bootloader_init.c" "src/bootloader_init.c"
"src/bootloader_clock_loader.c" "src/bootloader_clock_loader.c"
"src/bootloader_console.c" "src/bootloader_console.c"
@@ -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 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -7,6 +7,7 @@
#include "esp_err.h" #include "esp_err.h"
#include "esp_image_format.h" #include "esp_image_format.h"
#include "soc/reset_reasons.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { 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_read_bootloader_header(void);
esp_err_t bootloader_check_bootloader_validity(void); esp_err_t bootloader_check_bootloader_validity(void);
void bootloader_clear_bss_section(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_config_wdt(void);
void bootloader_enable_random(void); void bootloader_enable_random(void);
void bootloader_print_banner(void); void bootloader_print_banner(void);
@@ -0,0 +1,70 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#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();
}
@@ -91,14 +91,14 @@ static inline esp_err_t bootloader_check_rated_cpu_clock(void)
} }
#if SOC_RTC_WDT_SUPPORTED #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. //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_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); 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, uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0,
lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 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); 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; if (cpu == 0 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 ||
soc_reset_reason_t rst_reas[2]; rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 ||
rst_reason == RESET_REASON_CPU0_RTC_WDT)) {
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) {
ESP_LOGW(TAG, "PRO CPU has been reset by 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 || if (cpu == 1 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 ||
rst_reas[1] == RESET_REASON_CPU1_MWDT1 || rst_reas[1] == RESET_REASON_CPU1_RTC_WDT) { 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"); ESP_LOGW(TAG, "APP CPU has been reset by WDT");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// 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();
} }
#endif // SOC_RTC_WDT_SUPPORTED #endif // SOC_RTC_WDT_SUPPORTED
esp_err_t bootloader_init(void) esp_err_t bootloader_init(void)
@@ -244,10 +235,8 @@ esp_err_t bootloader_init(void)
} }
#endif // #if !CONFIG_APP_BUILD_TYPE_RAM #endif // #if !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -42,34 +42,29 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c2"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32c2");
#if SOC_RTC_WDT_SUPPORTED #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_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_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); 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; (void) cpu;
// saved PC was already printed by the ROM bootloader. // saved PC was already printed by the ROM bootloader.
// nothing to do here. // 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; (void) cpu;
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 || 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) { rst_reason == RESET_REASON_CPU0_MWDT0 || rst_reason == RESET_REASON_CPU0_RTC_WDT) {
ESP_LOGW(TAG, "PRO CPU has been reset by WDT."); ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// if reset by WDT dump info from trace port
wdt_reset_info_dump(0);
}
wdt_reset_cpu0_info_enable();
} }
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
@@ -141,10 +136,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -47,34 +47,29 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c3"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32c3");
#if SOC_RTC_WDT_SUPPORTED #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_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_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); 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; (void) cpu;
// saved PC was already printed by the ROM bootloader. // saved PC was already printed by the ROM bootloader.
// nothing to do here. // 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; (void) cpu;
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 || 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) { 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."); ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// if reset by WDT dump info from trace port
wdt_reset_info_dump(0);
}
wdt_reset_cpu0_info_enable();
} }
static void bootloader_super_wdt_auto_feed(void) 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 #endif //#if !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -47,34 +47,29 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c5"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32c5");
#if SOC_RTC_WDT_SUPPORTED #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_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_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); 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; (void) cpu;
// saved PC was already printed by the ROM bootloader. // saved PC was already printed by the ROM bootloader.
// nothing to do here. // 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; (void) cpu;
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 || 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) { 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."); ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// if reset by WDT dump info from trace port
wdt_reset_info_dump(0);
}
wdt_reset_cpu0_info_enable();
} }
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
@@ -169,10 +164,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -49,34 +49,29 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c6"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32c6");
#if SOC_RTC_WDT_SUPPORTED #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_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_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); 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; (void) cpu;
// saved PC was already printed by the ROM bootloader. // saved PC was already printed by the ROM bootloader.
// nothing to do here. // 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; (void) cpu;
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 || 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) { 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."); ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// if reset by WDT dump info from trace port
wdt_reset_info_dump(0);
}
wdt_reset_cpu0_info_enable();
} }
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
@@ -169,10 +164,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -49,34 +49,29 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32c61"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32c61");
#if SOC_RTC_WDT_SUPPORTED #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_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_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); 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; (void) cpu;
// saved PC was already printed by the ROM bootloader. // saved PC was already printed by the ROM bootloader.
// nothing to do here. // 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; (void) cpu;
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 || 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) { 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."); ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// if reset by WDT dump info from trace port
wdt_reset_info_dump(0);
}
wdt_reset_cpu0_info_enable();
} }
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
@@ -161,10 +156,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -48,34 +48,29 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32h2"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32h2");
#if SOC_RTC_WDT_SUPPORTED #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_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_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); 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; (void) cpu;
// saved PC was already printed by the ROM bootloader. // saved PC was already printed by the ROM bootloader.
// nothing to do here. // 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; (void) cpu;
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 || 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) { 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."); ESP_EARLY_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// if reset by WDT dump info from trace port
wdt_reset_info_dump(0);
}
wdt_reset_cpu0_info_enable();
} }
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
@@ -166,10 +161,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
// check whether a WDT reset happened // check reset reason and dump diagnostic info
#if SOC_RTC_WDT_SUPPORTED bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -48,34 +48,29 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32h21"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32h21");
#if SOC_RTC_WDT_SUPPORTED #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_SET_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_CLK_EN);
REG_CLR_BIT(PCR_ASSIST_CONF_REG, PCR_ASSIST_RST_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); 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; (void) cpu;
// saved PC was already printed by the ROM bootloader. // saved PC was already printed by the ROM bootloader.
// nothing to do here. // 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; (void) cpu;
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 || 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) { 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."); ESP_EARLY_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// if reset by WDT dump info from trace port
wdt_reset_info_dump(0);
}
wdt_reset_cpu0_info_enable();
} }
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
@@ -163,10 +158,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -44,43 +44,54 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32h4"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32h4");
#if SOC_RTC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_CPU_LOCKUP_DEBUG_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_bus_clock(0, true);
assist_debug_ll_enable_pc_recording(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; (void) cpu;
// saved PC was already printed by the ROM bootloader. // saved PC was already printed by the ROM bootloader.
// nothing to do here. // 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; if (cpu == 0 && (reset_reason == RESET_REASON_CORE_RTC_WDT || reset_reason == RESET_REASON_CORE_MWDT0 ||
soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); reset_reason == RESET_REASON_CORE_MWDT1 || reset_reason == RESET_REASON_CPU0_MWDT0 ||
if (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 || rst_reason == RESET_REASON_CORE_MWDT1 || reset_reason == RESET_REASON_CPU0_MWDT1 || reset_reason == RESET_REASON_CPU0_RTC_WDT)) {
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."); ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { if (cpu == 1 && (reset_reason == RESET_REASON_CORE_RTC_WDT || reset_reason == RESET_REASON_CORE_MWDT0 ||
// if reset by WDT dump info from trace port reset_reason == RESET_REASON_CORE_MWDT1 || reset_reason == RESET_REASON_CPU0_MWDT0 ||
wdt_reset_info_dump(0); 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) static void bootloader_super_wdt_auto_feed(void)
{ {
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, LP_WDT_SWD_WKEY_VALUE); 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_SET_BIT(LP_WDT_SWD_CONFIG_REG, LP_WDT_SWD_AUTO_FEED_EN);
REG_WRITE(LP_WDT_SWD_WPROTECT_REG, 0); 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) static inline void bootloader_hardware_init(void)
{ {
@@ -178,10 +189,8 @@ esp_err_t bootloader_init(void)
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
bootloader_config_dcache(); bootloader_config_dcache();
bootloader_config_icache1(); bootloader_config_icache1();
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -55,36 +55,28 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32p4"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32p4");
#if SOC_RTC_WDT_SUPPORTED #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_bus_clock(0, true);
assist_debug_ll_enable_pc_recording(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; (void) cpu;
// saved PC was already printed by the ROM bootloader. // saved PC was already printed by the ROM bootloader.
// nothing to do here. // 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; if (cpu == 0 && (rst_reason == RESET_REASON_CPU_MWDT || rst_reason == RESET_REASON_CPU_RWDT ||
soc_reset_reason_t rst_reason = esp_rom_get_reset_reason(0); rst_reason == RESET_REASON_CORE_MWDT || rst_reason == RESET_REASON_CORE_RWDT ||
if (rst_reason == RESET_REASON_CPU_MWDT || rst_reason == RESET_REASON_CPU_RWDT || rst_reason == RESET_REASON_CORE_MWDT || rst_reason == RESET_REASON_SYS_RWDT)) {
rst_reason == RESET_REASON_CORE_RWDT || rst_reason == RESET_REASON_SYS_RWDT) {
ESP_LOGW(TAG, "CPU has been reset by WDT."); ESP_LOGW(TAG, "CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// 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();
} }
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
@@ -187,10 +179,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -42,7 +42,7 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32s2"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32s2");
#if SOC_RTC_WDT_SUPPORTED #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_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); 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); 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, uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0,
lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 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); 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; (void) cpu;
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 || 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) { 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."); ESP_LOGW(TAG, "PRO CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// if reset by WDT dump info from trace port
wdt_reset_info_dump(0);
}
wdt_reset_cpu0_info_enable();
} }
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
@@ -169,10 +164,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -48,7 +48,7 @@
ESP_LOG_ATTR_TAG(TAG, "boot.esp32s3"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32s3");
#if SOC_RTC_WDT_SUPPORTED #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_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_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); 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, uint32_t inst = 0, pid = 0, stat = 0, data = 0, pc = 0,
lsstat = 0, lsaddr = 0, lsdata = 0, dstat = 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); 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; if (cpu == 0 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 ||
soc_reset_reason_t rst_reas[2]; rst_reason == RESET_REASON_CORE_MWDT1 || rst_reason == RESET_REASON_CPU0_MWDT0 ||
rst_reason == RESET_REASON_CPU0_RTC_WDT)) {
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) {
ESP_LOGW(TAG, "PRO CPU has been reset by 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 || if (cpu == 1 && (rst_reason == RESET_REASON_CORE_RTC_WDT || rst_reason == RESET_REASON_CORE_MWDT0 ||
rst_reas[1] == RESET_REASON_CPU1_MWDT1 || rst_reas[1] == RESET_REASON_CPU1_RTC_WDT) { 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."); ESP_LOGW(TAG, "APP CPU has been reset by WDT.");
wdt_rst = 1; return true;
} }
if (wdt_rst) { return false;
// 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();
} }
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
@@ -208,10 +198,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
bootloader_check_wdt_reset();
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -26,6 +26,9 @@
#include "soc/pmu_reg.h" #include "soc/pmu_reg.h"
#include "hal/regi2c_ctrl_ll.h" #include "hal/regi2c_ctrl_ll.h"
#include "hal/modem_lpcon_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"); ESP_LOG_ATTR_TAG(TAG, "boot.esp32s31");
@@ -44,6 +47,44 @@ static inline void bootloader_hardware_init(void)
#endif #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 #if SOC_RTC_WDT_SUPPORTED
static void bootloader_super_wdt_auto_feed(void) static void bootloader_super_wdt_auto_feed(void)
{ {
@@ -112,10 +153,8 @@ esp_err_t bootloader_init(void)
} }
#endif // !CONFIG_APP_BUILD_TYPE_RAM #endif // !CONFIG_APP_BUILD_TYPE_RAM
#if SOC_RTC_WDT_SUPPORTED // check reset reason and dump diagnostic info
// check whether a WDT reset happened bootloader_check_reset();
// bootloader_check_wdt_reset(); // TODO: IDF-14678
#endif
#if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED #if SOC_RTC_WDT_SUPPORTED || SOC_WDT_SUPPORTED
// config WDT // config WDT
bootloader_config_wdt(); bootloader_config_wdt();
@@ -200,7 +200,7 @@ static inline void periph_ll_clk_gate_set_default(soc_reset_reason_t rst_reason,
if (config->disable_assist_clk) { if (config->disable_assist_clk) {
/* Disable ASSIST Debug module clock if PC recoreding function is not used, /* 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; PCR.assist_conf.assist_clk_en = 0;
} }
@@ -174,7 +174,7 @@ static inline void periph_ll_clk_gate_set_default(soc_reset_reason_t rst_reason,
if (config->disable_assist_clk) { if (config->disable_assist_clk) {
/* Disable ASSIST Debug module clock if PC recoreding function is not used, /* 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; PCR.assist_conf.assist_clk_en = 0;
} }
@@ -166,7 +166,7 @@ static inline void periph_ll_clk_gate_set_default(soc_reset_reason_t rst_reason,
if (config->disable_assist_clk) { if (config->disable_assist_clk) {
/* Disable ASSIST Debug module clock if PC recording is not used; /* 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; PCR.assist_conf.assist_clk_en = 0;
} }
@@ -291,7 +291,7 @@ static inline void periph_ll_clk_gate_set_default(soc_reset_reason_t rst_reason,
if (config->disable_assist_clk) { if (config->disable_assist_clk) {
/* Disable ASSIST Debug module clock if PC recoreding function is not used, /* 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(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); REG_CLR_BIT(ASSIST_DEBUG_CLOCK_GATE_REG, ASSIST_DEBUG_CLK_EN);
} }
@@ -74,3 +74,7 @@ config ESP_ROM_HAS_VERSION
config ESP_ROM_MULTI_HEAP_WALK_PATCH config ESP_ROM_MULTI_HEAP_WALK_PATCH
bool bool
default y default y
config ESP_ROM_PRINTS_LOCKUP_STATUS
bool
default y
@@ -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_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_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_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
+2 -2
View File
@@ -83,8 +83,8 @@ else()
list(APPEND srcs "systick_etm.c") list(APPEND srcs "systick_etm.c")
endif() endif()
if(CONFIG_ESP_SYSTEM_HW_STACK_GUARD) if(CONFIG_ESP_SYSTEM_HW_STACK_GUARD OR CONFIG_ESP_SYSTEM_HW_PC_RECORD OR CONFIG_SOC_CPU_LOCKUP_DEBUG_SUPPORTED)
list(APPEND srcs "hw_stack_guard.c") list(APPEND srcs "debug_assist.c")
endif() endif()
idf_component_register(SRCS "${srcs}" idf_component_register(SRCS "${srcs}"
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include "hal/assist_debug_hal.h" #include "hal/assist_debug_hal.h"
#include "hal/assist_debug_ll.h"
#include "esp_private/hw_stack_guard.h" #include "esp_private/hw_stack_guard.h"
#include "esp_private/periph_ctrl.h" #include "esp_private/periph_ctrl.h"
#include "esp_private/startup_internal.h" #include "esp_private/startup_internal.h"
@@ -12,12 +13,8 @@
#include "esp_rom_sys.h" #include "esp_rom_sys.h"
#include "esp_cpu.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 #if SOC_CPU_CORES_NUM > 1
PERIPH_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#endif #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_enable_bus_clock(core_id, true);
assist_debug_ll_reset_register(core_id); 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); 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_type(ETS_ASSIST_DEBUG_INUM, INTR_TYPE_LEVEL);
esprv_int_set_priority(ETS_ASSIST_DEBUG_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); 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: * Note: to control hw_stack_guard use monitor enable/disable because in case:
* - monitor == active * - monitor == active
* - interrupt != 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); assist_debug_hal_sp_int_enable(core_id);
ESP_INTR_ENABLE(ETS_ASSIST_DEBUG_INUM); 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; return ESP_OK;
} }
@@ -56,14 +78,15 @@ void esp_hw_stack_guard_monitor_start(void)
{ {
uint32_t core_id = esp_cpu_get_core_id(); 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); assist_debug_hal_sp_mon_enable(core_id);
} }
void esp_hw_stack_guard_monitor_stop(void) void esp_hw_stack_guard_monitor_stop(void)
{ {
uint32_t core_id = esp_cpu_get_core_id(); 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); assist_debug_hal_sp_mon_disable(core_id);
} }
+3 -3
View File
@@ -8,9 +8,9 @@ entries:
cache_err_int (noflash) cache_err_int (noflash)
reset_reason:esp_reset_reason_get_hint (noflash) reset_reason:esp_reset_reason_get_hint (noflash)
if ESP_SYSTEM_HW_STACK_GUARD = y: if ESP_SYSTEM_HW_STACK_GUARD = y:
hw_stack_guard:esp_hw_stack_guard_get_bounds (noflash) debug_assist:esp_hw_stack_guard_get_bounds (noflash)
hw_stack_guard:esp_hw_stack_guard_get_fired_cpu (noflash) debug_assist: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_pc (noflash)
# These functions are called when the cache is disabled # These functions are called when the cache is disabled
system_internal:esp_restart_noos (noflash) system_internal:esp_restart_noos (noflash)
+1 -1
View File
@@ -257,7 +257,7 @@ __attribute__((weak)) void esp_perip_clk_init(void)
#if !CONFIG_ESP_SYSTEM_HW_PC_RECORD #if !CONFIG_ESP_SYSTEM_HW_PC_RECORD
/* Disable ASSIST Debug module clock if PC recoreding function is not used, /* 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); 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); SET_PERI_REG_MASK(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG);
#endif #endif
+1 -1
View File
@@ -299,7 +299,7 @@ __attribute__((weak)) void esp_perip_clk_init(void)
#if !CONFIG_ESP_SYSTEM_HW_PC_RECORD #if !CONFIG_ESP_SYSTEM_HW_PC_RECORD
/* Disable ASSIST Debug module clock if PC recoreding function is not used, /* 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); 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); SET_PERI_REG_MASK(SYSTEM_CPU_PERI_RST_EN_REG, SYSTEM_RST_EN_ASSIST_DEBUG);
#endif #endif
+2 -2
View File
@@ -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 # 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 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. # Assist-debug early init for stack guard and PC recording.
SECONDARY: 101: esp_hw_stack_guard_init in components/esp_system/hw_stack_guard.c on ESP_SYSTEM_INIT_ALL_CORES 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) # 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) SECONDARY: 102: init_rng in components/esp_hw_support/hw_random.c on BIT(0)
@@ -8,13 +8,14 @@ set(requires "unity"
"esp_psram") "esp_psram")
set(SRC "test_app_main.c" set(SRC "test_app_main.c"
"test_backtrace.c" "test_backtrace.c"
"test_ipc.c" "test_ipc.c"
"test_reset_reason.c" "test_panic.c"
"test_shared_stack_printf.c" "test_reset_reason.c"
"test_stack_check.c" "test_shared_stack_printf.c"
"test_system_time.c" "test_stack_check.c"
"test_task_wdt.c") "test_system_time.c"
"test_task_wdt.c")
if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED OR CONFIG_SOC_DEEP_SLEEP_SUPPORTED) if(CONFIG_SOC_LIGHT_SLEEP_SUPPORTED OR CONFIG_SOC_DEEP_SLEEP_SUPPORTED)
list(APPEND SRC "test_sleep.c" list(APPEND SRC "test_sleep.c"
@@ -42,3 +43,9 @@ idf_component_register(SRCS ${SRC}
PRIV_INCLUDE_DIRS . PRIV_INCLUDE_DIRS .
PRIV_REQUIRES "${requires}" PRIV_REQUIRES "${requires}"
WHOLE_ARCHIVE) 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()
@@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdbool.h>
#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
@@ -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 * SPDX-License-Identifier: Unlicense OR CC0-1.0
*/ */
#include "sdkconfig.h" #include "sdkconfig.h"
#include <inttypes.h> #include <inttypes.h>
#include "unity.h" #include "unity.h"
#include "soc/soc_caps.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_task_wdt.h" #include "esp_task_wdt.h"
#include "esp_attr.h" #include "esp_attr.h"
@@ -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 @pytest.mark.generic
@idf_parametrize('config', ['default'], indirect=['config']) @idf_parametrize('config', ['default'], indirect=['config'])
@idf_parametrize('target', ['supported_targets'], indirect=['target']) @idf_parametrize('target', ['supported_targets'], indirect=['target'])
@@ -17,6 +17,7 @@
#include "esp_attr.h" #include "esp_attr.h"
#include "soc/pcr_struct.h" #include "soc/pcr_struct.h"
#include "soc/bus_monitor_struct.h" #include "soc/bus_monitor_struct.h"
#include "soc/lp_clkrst_struct.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { 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; 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 #ifdef __cplusplus
} }
#endif #endif
@@ -17,6 +17,7 @@
#include "esp_attr.h" #include "esp_attr.h"
#include "soc/hp_sys_clkrst_struct.h" #include "soc/hp_sys_clkrst_struct.h"
#include "soc/bus_monitor_struct.h" #include "soc/bus_monitor_struct.h"
#include "soc/lp_clkrst_struct.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { 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; 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 #ifdef __cplusplus
} }
#endif #endif
@@ -171,6 +171,10 @@ config SOC_ASSIST_DEBUG_SUPPORTED
bool bool
default y default y
config SOC_CPU_LOCKUP_DEBUG_SUPPORTED
bool
default y
config SOC_WDT_SUPPORTED config SOC_WDT_SUPPORTED
bool bool
default y default y
@@ -85,6 +85,7 @@
#define SOC_REGI2C_SUPPORTED 1 #define SOC_REGI2C_SUPPORTED 1
#define SOC_CLK_TREE_SUPPORTED 1 #define SOC_CLK_TREE_SUPPORTED 1
#define SOC_ASSIST_DEBUG_SUPPORTED 1 #define SOC_ASSIST_DEBUG_SUPPORTED 1
#define SOC_CPU_LOCKUP_DEBUG_SUPPORTED 1
#define SOC_WDT_SUPPORTED 1 #define SOC_WDT_SUPPORTED 1
#define SOC_RTC_WDT_SUPPORTED 1 #define SOC_RTC_WDT_SUPPORTED 1
#define SOC_SPI_FLASH_SUPPORTED 1 #define SOC_SPI_FLASH_SUPPORTED 1
@@ -123,6 +123,10 @@ config SOC_ASSIST_DEBUG_SUPPORTED
bool bool
default y default y
config SOC_CPU_LOCKUP_DEBUG_SUPPORTED
bool
default y
config SOC_WDT_SUPPORTED config SOC_WDT_SUPPORTED
bool bool
default y default y
@@ -86,6 +86,7 @@
// #define SOC_SDMMC_HOST_SUPPORTED 1 // TODO: [ESP32S31] IDF-14705 // #define SOC_SDMMC_HOST_SUPPORTED 1 // TODO: [ESP32S31] IDF-14705
#define SOC_CLK_TREE_SUPPORTED 1 #define SOC_CLK_TREE_SUPPORTED 1
#define SOC_ASSIST_DEBUG_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_DEBUG_PROBE_SUPPORTED 1 // TODO: [ESP32S31] IDF-14798
#define SOC_WDT_SUPPORTED 1 #define SOC_WDT_SUPPORTED 1
#define SOC_RTC_WDT_SUPPORTED 1 #define SOC_RTC_WDT_SUPPORTED 1