Merge branch 'bug/xtensa_cpu1_sys_lockup_v5.4' into 'release/v5.4'

fix(panic_handler): Updated panic handler to use RTC WDT (v5.4)

See merge request espressif/esp-idf!37112
This commit is contained in:
Wang Meng Yang
2025-04-01 14:51:18 +08:00
20 changed files with 578 additions and 163 deletions
+3 -3
View File
@@ -131,7 +131,7 @@ extern int ble_controller_init(esp_bt_controller_config_t *cfg);
extern int ble_log_init_async(interface_func_t bt_controller_log_interface, bool task_create, uint8_t buffers, uint32_t *bufs_size);
extern int ble_log_deinit_async(void);
extern void ble_log_async_output_dump_all(bool output);
extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms);
extern void esp_panic_handler_feed_wdts(void);
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
extern int ble_controller_deinit(void);
extern int ble_controller_enable(uint8_t mode);
@@ -392,7 +392,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
ble_log_async_output_dump_all(true);
stop_write = true;
esp_bt_ontroller_log_deinit();
@@ -450,7 +450,7 @@ void esp_ble_controller_log_dump_all(bool output)
} else {
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
BT_ASSERT_PRINT("\r\n[DUMP_START:");
ble_log_async_output_dump_all(output);
BT_ASSERT_PRINT(":DUMP_END]\r\n");
+6 -6
View File
@@ -111,7 +111,7 @@ extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bo
extern int r_ble_log_deinit_async(void);
extern void r_ble_log_async_select_dump_buffers(uint8_t buffers);
extern void r_ble_log_async_output_dump_all(bool output);
extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms);
extern void esp_panic_handler_feed_wdts(void);
extern int r_ble_log_ctrl_level_and_mod(uint8_t log_level, uint32_t mod_switch);
extern int r_ble_ctrl_mod_type(uint16_t mod, uint32_t mod_type_switch);
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
@@ -358,13 +358,13 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
r_ble_log_async_output_dump_all(true);
esp_bt_ontroller_log_deinit();
stop_write = true;
buffer = (const uint8_t *)mapped_ptr;
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
if (is_filled) {
read_index = next_erase_index;
} else {
@@ -376,7 +376,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
while (read_index != write_index) {
esp_rom_printf("%02x ", buffer[read_index]);
if (print_len > max_print_len) {
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
print_len = 0;
}
@@ -1378,7 +1378,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b
} else {
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(1000);
esp_panic_handler_feed_wdts();
for (int i = 0; i < len; i++) {
esp_rom_printf("%02x ", addr[i]);
}
@@ -1399,7 +1399,7 @@ void esp_ble_controller_log_dump_all(bool output)
} else {
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
BT_ASSERT_PRINT("\r\n[DUMP_START:");
r_ble_log_async_output_dump_all(output);
BT_ASSERT_PRINT(":DUMP_END]\r\n");
+6 -6
View File
@@ -121,7 +121,7 @@ extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bo
extern int r_ble_log_deinit_async(void);
extern void r_ble_log_async_select_dump_buffers(uint8_t buffers);
extern void r_ble_log_async_output_dump_all(bool output);
extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms);
extern void esp_panic_handler_feed_wdts(void);
extern int r_ble_log_ctrl_level_and_mod(uint8_t log_level, uint32_t mod_switch);
extern int r_ble_ctrl_mod_type(uint16_t mod, uint32_t mod_type_switch);
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
@@ -381,13 +381,13 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
r_ble_log_async_output_dump_all(true);
esp_bt_ontroller_log_deinit();
stop_write = true;
buffer = (const uint8_t *)mapped_ptr;
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
if (is_filled) {
read_index = next_erase_index;
} else {
@@ -399,7 +399,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
while (read_index != write_index) {
esp_rom_printf("%02x ", buffer[read_index]);
if (print_len > max_print_len) {
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
print_len = 0;
}
@@ -1419,7 +1419,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b
} else {
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(1000);
esp_panic_handler_feed_wdts();
for (int i = 0; i < len; i++) {
esp_rom_printf("%02x ", addr[i]);
}
@@ -1440,7 +1440,7 @@ void esp_ble_controller_log_dump_all(bool output)
} else {
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
BT_ASSERT_PRINT("\r\n[DUMP_START:");
r_ble_log_async_output_dump_all(output);
BT_ASSERT_PRINT(":DUMP_END]\r\n");
+6 -6
View File
@@ -116,7 +116,7 @@ extern int r_ble_log_init_async(interface_func_t bt_controller_log_interface, bo
extern int r_ble_log_deinit_async(void);
extern void r_ble_log_async_select_dump_buffers(uint8_t buffers);
extern void r_ble_log_async_output_dump_all(bool output);
extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms);
extern void esp_panic_handler_feed_wdts(void);
extern int r_ble_log_ctrl_level_and_mod(uint8_t log_level, uint32_t mod_switch);
extern int r_ble_ctrl_mod_type(uint16_t mod, uint32_t mod_type_switch);
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
@@ -379,13 +379,13 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
r_ble_log_async_output_dump_all(true);
esp_bt_ontroller_log_deinit();
stop_write = true;
buffer = (const uint8_t *)mapped_ptr;
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
if (is_filled) {
read_index = next_erase_index;
} else {
@@ -397,7 +397,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
while (read_index != write_index) {
esp_rom_printf("%02x ", buffer[read_index]);
if (print_len > max_print_len) {
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
print_len = 0;
}
@@ -1393,7 +1393,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b
} else {
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(1000);
esp_panic_handler_feed_wdts();
for (int i = 0; i < len; i++) {
esp_rom_printf("%02x ", addr[i]);
}
@@ -1413,7 +1413,7 @@ void esp_ble_controller_log_dump_all(bool output)
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL_SAFE(&spinlock);
esp_panic_handler_reconfigure_wdts(5000);
esp_panic_handler_feed_wdts();
BT_ASSERT_PRINT("\r\n[DUMP_START:");
r_ble_log_async_output_dump_all(output);
BT_ASSERT_PRINT(":DUMP_END]\r\n");
+127 -113
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -74,13 +74,19 @@
#define MWDT_DEFAULT_TICKS_PER_US 500
#define PANIC_ENTRY_COUNT_MAX 2 // We allow at least 2 panic entries to let the panic handler process Double Exceptions
bool g_panic_abort = false;
char *g_panic_abort_details = NULL;
static wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
static uint32_t DRAM_ATTR g_panic_entry_count[CONFIG_FREERTOS_NUMBER_OF_CORES] = {0}; // Number of times panic handler has been entered per core since multiple cores can enter the panic handler simultaneously
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
/********************** Panic print functions **********************/
#if CONFIG_ESP_CONSOLE_UART
static uart_hal_context_t s_panic_uart = { .dev = CONFIG_ESP_CONSOLE_UART_NUM == 0 ? &UART0 :&UART1 };
@@ -171,68 +177,106 @@ void panic_print_dec(int d)
}
#endif // CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
/*
If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
the risk of somehow halting in the panic handler and not resetting. That is why this routine kills
all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
one second.
We have to do this before we do anything that might cause issues in the WDT interrupt handlers,
for example stalling the other core on ESP32 may cause the ESP32_ECO3_CACHE_LOCK_FIX
handler to get stuck.
*/
void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms)
static void print_abort_details(const void *f)
{
wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
#if SOC_TIMER_GROUPS >= 2
// IDF-3825
wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
#endif
//Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context
//Reconfigure TWDT (Timer Group 0)
wdt_hal_init(&wdt0_context, WDT_MWDT0, MWDT_LL_DEFAULT_CLK_PRESCALER, false); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US
wdt_hal_write_protect_disable(&wdt0_context);
wdt_hal_config_stage(&wdt0_context, 0, timeout_ms * 1000 / MWDT_DEFAULT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //1 second before reset
wdt_hal_enable(&wdt0_context);
wdt_hal_write_protect_enable(&wdt0_context);
#if SOC_TIMER_GROUPS >= 2
//Disable IWDT (Timer Group 1)
wdt_hal_write_protect_disable(&wdt1_context);
wdt_hal_disable(&wdt1_context);
wdt_hal_write_protect_enable(&wdt1_context);
#endif
panic_print_str(g_panic_abort_details);
}
/*
This disables all the watchdogs for when we call the gdbstub.
*/
static inline void disable_all_wdts(void)
/********************** Panic handler watchdog timer functions **********************/
/* This function disables the Timer Group WDTs */
void esp_panic_handler_disable_timg_wdts(void)
{
wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
#if SOC_TIMER_GROUPS >= 2
wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
#endif
//Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context
//Task WDT is the Main Watchdog Timer of Timer Group 0
wdt_hal_write_protect_disable(&wdt0_context);
wdt_hal_disable(&wdt0_context);
wdt_hal_write_protect_enable(&wdt0_context);
#if SOC_TIMER_GROUPS >= 2
//Interrupt WDT is the Main Watchdog Timer of Timer Group 1
wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
wdt_hal_write_protect_disable(&wdt1_context);
wdt_hal_disable(&wdt1_context);
wdt_hal_write_protect_enable(&wdt1_context);
#endif
#endif /* SOC_TIMER_GROUPS >= 2 */
}
static void print_abort_details(const void *f)
/* This function enables the RTC WDT with the given timeout in milliseconds */
void esp_panic_handler_enable_rtc_wdt(uint32_t timeout_ms)
{
panic_print_str(g_panic_abort_details);
wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false);
uint32_t stage_timeout_ticks = (uint32_t)(timeout_ms * rtc_clk_slow_freq_get_hz() / 1000ULL);
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC);
wdt_hal_enable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
}
/* Feed the watchdogs if they are enabled and if we are not already in the panic handler */
void esp_panic_handler_feed_wdts(void)
{
/* If we have already entered the panic handler multiple times,
* we should not feed the WDTs. This is because we need an
* alternate mechanism to reset the system if we happen to be stuck
* in a panic loop.
*/
if (g_panic_entry_count[esp_cpu_get_core_id()] > PANIC_ENTRY_COUNT_MAX) {
return;
}
// Feed Timer Group 0 WDT
wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
if (wdt_hal_is_enabled(&wdt0_context)) {
wdt_hal_write_protect_disable(&wdt0_context);
wdt_hal_feed(&wdt0_context);
wdt_hal_write_protect_enable(&wdt0_context);
}
#if SOC_TIMER_GROUPS >= 2
// Feed Timer Group 1 WDT
wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
if (wdt_hal_is_enabled(&wdt1_context)) {
wdt_hal_write_protect_disable(&wdt1_context);
wdt_hal_feed(&wdt1_context);
wdt_hal_write_protect_enable(&wdt1_context);
}
#endif /* SOC_TIMER_GROUPS >= 2 */
// Feed RTC WDT
if (wdt_hal_is_enabled(&rtc_wdt_ctx)) {
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_feed(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
}
}
/* This function disables all the watchdogs */
static inline void disable_all_wdts(void)
{
//Disable Timer Group WDTs
esp_panic_handler_disable_timg_wdts();
//Disable RTC WDT
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_disable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
}
/********************** Panic handler functions **********************/
/* This function is called from the panic handler entry point to increment the panic entry count */
void esp_panic_handler_increment_entry_count(void)
{
int core_id = esp_cpu_get_core_id();
g_panic_entry_count[core_id]++;
if (g_panic_entry_count[core_id] > PANIC_ENTRY_COUNT_MAX) {
/* If we have already panicked multiple times, chances are
* that the panic handler itself is broken. In this case, we
* should just reset the system.
*/
panic_print_str("Panic handler entered multiple times. Abort panic handling. Rebooting ...\r\n");
panic_restart();
}
}
// Control arrives from chip-specific panic handler, environment prepared for
@@ -241,8 +285,8 @@ static void print_abort_details(const void *f)
void esp_panic_handler(panic_info_t *info)
{
// The port-level panic handler has already called this, but call it again
// to reset the TG0WDT period
esp_panic_handler_reconfigure_wdts(1000);
// to reset the RTC WDT period
esp_panic_handler_feed_wdts();
// If the exception was due to an abort, override some of the panic info
if (g_panic_abort) {
@@ -253,28 +297,28 @@ void esp_panic_handler(panic_info_t *info)
}
/*
* For any supported chip, the panic handler prints the contents of panic_info_t in the following format:
*
*
* Guru Meditation Error: Core <core> (<exception>). <description>
* <details>
*
* <state>
*
* <elf_info>
*
*
* ----------------------------------------------------------------------------------------
* core - core where exception was triggered
* exception - what kind of exception occurred
* description - a short description regarding the exception that occurred
* details - more details about the exception
* state - processor state like register contents, and backtrace
* elf_info - details about the image currently running
*
* NULL fields in panic_info_t are not printed.
*
* */
* For any supported chip, the panic handler prints the contents of panic_info_t in the following format:
*
*
* Guru Meditation Error: Core <core> (<exception>). <description>
* <details>
*
* <state>
*
* <elf_info>
*
*
* ----------------------------------------------------------------------------------------
* core - core where exception was triggered
* exception - what kind of exception occurred
* description - a short description regarding the exception that occurred
* details - more details about the exception
* state - processor state like register contents, and backtrace
* elf_info - details about the image currently running
*
* NULL fields in panic_info_t are not printed.
*
*/
if (info->reason) {
panic_print_str("Guru Meditation Error: Core ");
panic_print_dec(info->core);
@@ -312,7 +356,6 @@ void esp_panic_handler(panic_info_t *info)
panic_print_str("Setting breakpoint at 0x");
panic_print_hex((uint32_t)info->addr);
panic_print_str(" and returning...\r\n");
disable_all_wdts();
#if CONFIG_APPTRACE_ENABLE
#if CONFIG_APPTRACE_SV_ENABLE
SEGGER_RTT_ESP_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
@@ -322,24 +365,16 @@ void esp_panic_handler(panic_info_t *info)
#endif
#endif
disable_all_wdts();
esp_cpu_set_breakpoint(0, info->addr); // use breakpoint 0
return;
}
#endif //CONFIG_ESP_DEBUG_OCDAWARE
// start panic WDT to restart system if we hang in this handler
if (!wdt_hal_is_enabled(&rtc_wdt_ctx)) {
wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false);
uint32_t stage_timeout_ticks = (uint32_t)(7000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL);
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM);
// 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
// @ 115200 UART speed it will take more than 6 sec to print them out.
wdt_hal_enable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
}
esp_panic_handler_reconfigure_wdts(1000); // Restart WDT again
/* Feed the WDTs here. This is done to fascilitate a "slow" UART
* which might take a longer time to print the state of the processor.
*/
esp_panic_handler_feed_wdts();
PANIC_INFO_DUMP(info, state);
panic_print_str("\r\n");
@@ -361,66 +396,45 @@ void esp_panic_handler(panic_info_t *info)
panic_print_str("\r\n");
#if CONFIG_APPTRACE_ENABLE
disable_all_wdts();
esp_panic_handler_feed_wdts();
#if CONFIG_APPTRACE_SV_ENABLE
SEGGER_RTT_ESP_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
#else
esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH,
APPTRACE_ONPANIC_HOST_FLUSH_TMO);
#endif
esp_panic_handler_reconfigure_wdts(1000); // restore WDT config
#endif // CONFIG_APPTRACE_ENABLE
#if CONFIG_ESP_COREDUMP_ENABLE
static bool s_dumping_core;
esp_panic_handler_feed_wdts();
static bool s_dumping_core = false;
if (s_dumping_core) {
panic_print_str("Re-entered core dump! Exception happened during core dump!\r\n");
} else {
disable_all_wdts();
s_dumping_core = true;
esp_core_dump_write(info);
s_dumping_core = false;
esp_panic_handler_reconfigure_wdts(1000);
}
#endif /* CONFIG_ESP_COREDUMP_ENABLE */
#if CONFIG_ESP_SYSTEM_PANIC_GDBSTUB
disable_all_wdts();
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_disable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
panic_print_str("Entering gdb stub now.\r\n");
disable_all_wdts();
esp_gdbstub_panic_handler((void *)info->frame);
#else
#if CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS
// start RTC WDT if it hasn't been started yet and set the timeout to more than the delay time
wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false);
uint32_t stage_timeout_ticks = (uint32_t)(((CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS + 1) * 1000
* rtc_clk_slow_freq_get_hz()) / 1000ULL);
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM);
// 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
// @ 115200 UART speed it will take more than 6 sec to print them out.
wdt_hal_enable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
esp_panic_handler_reconfigure_wdts((CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS + 1) * 1000);
esp_panic_handler_feed_wdts();
panic_print_str("Rebooting in ");
panic_print_dec(CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS);
panic_print_str(" seconds...\r\n");
esp_rom_delay_us(CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS * 1000000);
esp_panic_handler_reconfigure_wdts(1000);
#endif /* CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS */
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_disable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
#if CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
esp_panic_handler_feed_wdts();
if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) {
switch (info->exception) {
case PANIC_EXCEPTION_IWDT:
@@ -440,9 +454,9 @@ void esp_panic_handler(panic_info_t *info)
panic_print_str("Rebooting...\r\n");
panic_restart();
#else /* CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT */
disable_all_wdts();
panic_print_str("CPU halted.\r\n");
esp_system_reset_modules_on_exit();
disable_all_wdts();
ESP_INFINITE_LOOP();
#endif /* CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT */
#endif /* CONFIG_ESP_SYSTEM_PANIC_GDBSTUB */
+61 -16
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -44,11 +44,15 @@
extern int _invalid_pc_placeholder;
extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms);
extern void esp_panic_handler(panic_info_t *);
static wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
extern void esp_panic_handler_increment_entry_count(void);
extern void esp_panic_handler_feed_wdts(void);
extern void esp_panic_handler_enable_rtc_wdt(uint32_t timeout_ms);
extern void esp_panic_handler_disable_timg_wdts(void);
void *g_exc_frames[SOC_CPU_CORES_NUM] = {NULL};
@@ -132,12 +136,52 @@ void busy_wait(void)
static void panic_handler(void *frame, bool pseudo_excause)
{
/* If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
* an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
* the risk of somehow halting in the panic handler and not resetting.
*
* We have to do this before we do anything that might cause issues in the WDT interrupt handlers,
* for example stalling the other core on ESP32 may cause the ESP32_ECO3_CACHE_LOCK_FIX
* handler to get stuck.
*
* We do this before we increment the panic handler entry count to ensure that the WDTs are fed.
*/
esp_panic_handler_feed_wdts();
/* Increment the panic handler entry count */
esp_panic_handler_increment_entry_count();
/* Configuring the RTC WDT as early as possible in the panic handler
* is critical for system safety.
*
* The RTC WDT is relied upon for a complete system reset, as it is the only
* watchdog timer capable of resetting both the main system and the RTC subsystem.
* In contrast, the Timer Group Watchdog Timers can only reset the main system
* but not the RTC module.
*
* The timeout value for the RTC WDT is set to 10 seconds. The primary reason for
* choosing a 10 second timeout is to allow the panic handler to run to completion
* which may include core dump collection and apptrace flushing.
*
* Explanation for why the core dump takes time:
* 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
* @ 115200 UART speed it will take more than 6 sec to print them out.
*
* TODO: Make the timeout configurable or more intelligent based on the panic reason and the
* config options.
*/
#if CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS
esp_panic_handler_enable_rtc_wdt((CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS + 10) * 1000);
#else
esp_panic_handler_enable_rtc_wdt(10000);
#endif /* CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS */
panic_info_t info = { 0 };
/*
* Setup environment and perform necessary architecture/chip specific
* steps here prior to the system panic handler.
* */
*/
int core_id = esp_cpu_get_core_id();
// If multiple cores arrive at panic handler, save frames for all of them
@@ -178,8 +222,12 @@ static void panic_handler(void *frame, bool pseudo_excause)
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
}
// Need to reconfigure WDTs before we stall any other CPU
esp_panic_handler_reconfigure_wdts(1000);
/* Before we stall the other CPU, we need to disable all WDTs except the RTC WDT.
* This is because the TIMG WDTs cannot reset the RTC subsystem, which stores the CPU stalling
* configuration. If the other CPU is stalled and the TIMG WDTs trigger before we can unstall the
* CPU then we have a chance of locking up the system without rebooting it.
*/
esp_panic_handler_disable_timg_wdts();
esp_rom_delay_us(1);
// Stall all other cores
@@ -188,6 +236,12 @@ static void panic_handler(void *frame, bool pseudo_excause)
esp_cpu_stall(i);
}
}
#else
/* In single core mode, we don't need to disable the TIMG WDTs,
* but we do it anyway to keep the code consistent and to avoid
* managing the state of multiple WDTs.
*/
esp_panic_handler_disable_timg_wdts();
#endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
esp_ipc_isr_stall_abort();
@@ -202,15 +256,6 @@ static void panic_handler(void *frame, bool pseudo_excause)
panic_set_address(frame, (uint32_t)&_invalid_pc_placeholder);
}
#endif
if (panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU0
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|| panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU1
#endif
) {
wdt_hal_write_protect_disable(&wdt0_context);
wdt_hal_handle_intr(&wdt0_context);
wdt_hal_write_protect_enable(&wdt0_context);
}
}
// Convert architecture exception frame into abstracted panic info