mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
Merge branch 'bug/xtensa_cpu1_sys_lockup' into 'master'
fix(panic_handler): Updated panic handler to use RTC WDT Closes IDFGH-14379, IDFGH-14221, IDFGH-8665, and DOC-10263 See merge request espressif/esp-idf!36652
This commit is contained in:
commit
e01877ff2e
@ -130,7 +130,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_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 int ble_log_deinit_async(void);
|
||||||
extern void ble_log_async_output_dump_all(bool output);
|
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
|
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
|
||||||
extern int ble_controller_deinit(void);
|
extern int ble_controller_deinit(void);
|
||||||
extern int ble_controller_enable(uint8_t mode);
|
extern int ble_controller_enable(uint8_t mode);
|
||||||
@ -391,7 +391,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
|
|||||||
|
|
||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
ble_log_async_output_dump_all(true);
|
ble_log_async_output_dump_all(true);
|
||||||
stop_write = true;
|
stop_write = true;
|
||||||
esp_bt_ontroller_log_deinit();
|
esp_bt_ontroller_log_deinit();
|
||||||
@ -449,7 +449,7 @@ void esp_ble_controller_log_dump_all(bool output)
|
|||||||
} else {
|
} else {
|
||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
BT_ASSERT_PRINT("\r\n[DUMP_START:");
|
BT_ASSERT_PRINT("\r\n[DUMP_START:");
|
||||||
ble_log_async_output_dump_all(output);
|
ble_log_async_output_dump_all(output);
|
||||||
BT_ASSERT_PRINT(":DUMP_END]\r\n");
|
BT_ASSERT_PRINT(":DUMP_END]\r\n");
|
||||||
|
@ -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 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_select_dump_buffers(uint8_t buffers);
|
||||||
extern void r_ble_log_async_output_dump_all(bool output);
|
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_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);
|
extern int r_ble_ctrl_mod_type(uint16_t mod, uint32_t mod_type_switch);
|
||||||
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
|
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
|
||||||
@ -376,13 +376,13 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
|
|||||||
|
|
||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
r_ble_log_async_output_dump_all(true);
|
r_ble_log_async_output_dump_all(true);
|
||||||
esp_bt_ontroller_log_deinit();
|
esp_bt_ontroller_log_deinit();
|
||||||
stop_write = true;
|
stop_write = true;
|
||||||
|
|
||||||
buffer = (const uint8_t *)mapped_ptr;
|
buffer = (const uint8_t *)mapped_ptr;
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
if (is_filled) {
|
if (is_filled) {
|
||||||
read_index = next_erase_index;
|
read_index = next_erase_index;
|
||||||
} else {
|
} else {
|
||||||
@ -394,7 +394,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
|
|||||||
while (read_index != write_index) {
|
while (read_index != write_index) {
|
||||||
esp_rom_printf("%02x ", buffer[read_index]);
|
esp_rom_printf("%02x ", buffer[read_index]);
|
||||||
if (print_len > max_print_len) {
|
if (print_len > max_print_len) {
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
print_len = 0;
|
print_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1380,7 +1380,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b
|
|||||||
} else {
|
} else {
|
||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(1000);
|
esp_panic_handler_feed_wdts();
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
esp_rom_printf("%02x ", addr[i]);
|
esp_rom_printf("%02x ", addr[i]);
|
||||||
}
|
}
|
||||||
@ -1401,7 +1401,7 @@ void esp_ble_controller_log_dump_all(bool output)
|
|||||||
} else {
|
} else {
|
||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
BT_ASSERT_PRINT("\r\n[DUMP_START:");
|
BT_ASSERT_PRINT("\r\n[DUMP_START:");
|
||||||
r_ble_log_async_output_dump_all(output);
|
r_ble_log_async_output_dump_all(output);
|
||||||
BT_ASSERT_PRINT(":DUMP_END]\r\n");
|
BT_ASSERT_PRINT(":DUMP_END]\r\n");
|
||||||
|
@ -119,7 +119,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 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_select_dump_buffers(uint8_t buffers);
|
||||||
extern void r_ble_log_async_output_dump_all(bool output);
|
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_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);
|
extern int r_ble_ctrl_mod_type(uint16_t mod, uint32_t mod_type_switch);
|
||||||
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
|
#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;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
r_ble_log_async_output_dump_all(true);
|
r_ble_log_async_output_dump_all(true);
|
||||||
esp_bt_ontroller_log_deinit();
|
esp_bt_ontroller_log_deinit();
|
||||||
stop_write = true;
|
stop_write = true;
|
||||||
|
|
||||||
buffer = (const uint8_t *)mapped_ptr;
|
buffer = (const uint8_t *)mapped_ptr;
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
if (is_filled) {
|
if (is_filled) {
|
||||||
read_index = next_erase_index;
|
read_index = next_erase_index;
|
||||||
} else {
|
} else {
|
||||||
@ -397,7 +397,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
|
|||||||
while (read_index != write_index) {
|
while (read_index != write_index) {
|
||||||
esp_rom_printf("%02x ", buffer[read_index]);
|
esp_rom_printf("%02x ", buffer[read_index]);
|
||||||
if (print_len > max_print_len) {
|
if (print_len > max_print_len) {
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
print_len = 0;
|
print_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1401,7 +1401,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b
|
|||||||
} else {
|
} else {
|
||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(1000);
|
esp_panic_handler_feed_wdts();
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
esp_rom_printf("%02x ", addr[i]);
|
esp_rom_printf("%02x ", addr[i]);
|
||||||
}
|
}
|
||||||
@ -1422,7 +1422,7 @@ void esp_ble_controller_log_dump_all(bool output)
|
|||||||
} else {
|
} else {
|
||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
BT_ASSERT_PRINT("\r\n[DUMP_START:");
|
BT_ASSERT_PRINT("\r\n[DUMP_START:");
|
||||||
r_ble_log_async_output_dump_all(output);
|
r_ble_log_async_output_dump_all(output);
|
||||||
BT_ASSERT_PRINT(":DUMP_END]\r\n");
|
BT_ASSERT_PRINT(":DUMP_END]\r\n");
|
||||||
|
@ -114,7 +114,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 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_select_dump_buffers(uint8_t buffers);
|
||||||
extern void r_ble_log_async_output_dump_all(bool output);
|
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_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);
|
extern int r_ble_ctrl_mod_type(uint16_t mod, uint32_t mod_type_switch);
|
||||||
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
|
#endif // CONFIG_BT_LE_CONTROLLER_LOG_ENABLED
|
||||||
@ -377,13 +377,13 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
|
|||||||
|
|
||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
r_ble_log_async_output_dump_all(true);
|
r_ble_log_async_output_dump_all(true);
|
||||||
esp_bt_ontroller_log_deinit();
|
esp_bt_ontroller_log_deinit();
|
||||||
stop_write = true;
|
stop_write = true;
|
||||||
|
|
||||||
buffer = (const uint8_t *)mapped_ptr;
|
buffer = (const uint8_t *)mapped_ptr;
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
if (is_filled) {
|
if (is_filled) {
|
||||||
read_index = next_erase_index;
|
read_index = next_erase_index;
|
||||||
} else {
|
} else {
|
||||||
@ -395,7 +395,7 @@ void esp_bt_read_ctrl_log_from_flash(bool output)
|
|||||||
while (read_index != write_index) {
|
while (read_index != write_index) {
|
||||||
esp_rom_printf("%02x ", buffer[read_index]);
|
esp_rom_printf("%02x ", buffer[read_index]);
|
||||||
if (print_len > max_print_len) {
|
if (print_len > max_print_len) {
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
print_len = 0;
|
print_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,7 +1375,7 @@ static void esp_bt_controller_log_interface(uint32_t len, const uint8_t *addr, b
|
|||||||
} else {
|
} else {
|
||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(1000);
|
esp_panic_handler_feed_wdts();
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
esp_rom_printf("%02x ", addr[i]);
|
esp_rom_printf("%02x ", addr[i]);
|
||||||
}
|
}
|
||||||
@ -1395,7 +1395,7 @@ void esp_ble_controller_log_dump_all(bool output)
|
|||||||
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
portMUX_TYPE spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
portENTER_CRITICAL_SAFE(&spinlock);
|
portENTER_CRITICAL_SAFE(&spinlock);
|
||||||
esp_panic_handler_reconfigure_wdts(5000);
|
esp_panic_handler_feed_wdts();
|
||||||
BT_ASSERT_PRINT("\r\n[DUMP_START:");
|
BT_ASSERT_PRINT("\r\n[DUMP_START:");
|
||||||
r_ble_log_async_output_dump_all(output);
|
r_ble_log_async_output_dump_all(output);
|
||||||
BT_ASSERT_PRINT(":DUMP_END]\r\n");
|
BT_ASSERT_PRINT(":DUMP_END]\r\n");
|
||||||
|
@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -74,13 +74,19 @@
|
|||||||
|
|
||||||
#define MWDT_DEFAULT_TICKS_PER_US 500
|
#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;
|
bool g_panic_abort = false;
|
||||||
char *g_panic_abort_details = NULL;
|
char *g_panic_abort_details = NULL;
|
||||||
|
|
||||||
static wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
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
|
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
|
||||||
|
|
||||||
|
/********************** Panic print functions **********************/
|
||||||
|
|
||||||
#if CONFIG_ESP_CONSOLE_UART
|
#if CONFIG_ESP_CONSOLE_UART
|
||||||
static uart_hal_context_t s_panic_uart = { .dev = CONFIG_ESP_CONSOLE_UART_NUM == 0 ? &UART0 :&UART1 };
|
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
|
#endif // CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
|
||||||
|
|
||||||
/*
|
static void print_abort_details(const void *f)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
|
panic_print_str(g_panic_abort_details);
|
||||||
#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 handler watchdog timer functions **********************/
|
||||||
This disables all the watchdogs for when we call the gdbstub.
|
|
||||||
*/
|
/* This function disables the Timer Group WDTs */
|
||||||
static inline void disable_all_wdts(void)
|
void esp_panic_handler_disable_timg_wdts(void)
|
||||||
{
|
{
|
||||||
wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
|
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_write_protect_disable(&wdt0_context);
|
||||||
wdt_hal_disable(&wdt0_context);
|
wdt_hal_disable(&wdt0_context);
|
||||||
wdt_hal_write_protect_enable(&wdt0_context);
|
wdt_hal_write_protect_enable(&wdt0_context);
|
||||||
|
|
||||||
#if SOC_TIMER_GROUPS >= 2
|
#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_write_protect_disable(&wdt1_context);
|
||||||
wdt_hal_disable(&wdt1_context);
|
wdt_hal_disable(&wdt1_context);
|
||||||
wdt_hal_write_protect_enable(&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
|
// 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)
|
void esp_panic_handler(panic_info_t *info)
|
||||||
{
|
{
|
||||||
// The port-level panic handler has already called this, but call it again
|
// The port-level panic handler has already called this, but call it again
|
||||||
// to reset the TG0WDT period
|
// to reset the RTC WDT period
|
||||||
esp_panic_handler_reconfigure_wdts(1000);
|
esp_panic_handler_feed_wdts();
|
||||||
|
|
||||||
// If the exception was due to an abort, override some of the panic info
|
// If the exception was due to an abort, override some of the panic info
|
||||||
if (g_panic_abort) {
|
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:
|
* 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>
|
* Guru Meditation Error: Core <core> (<exception>). <description>
|
||||||
* <details>
|
* <details>
|
||||||
*
|
*
|
||||||
* <state>
|
* <state>
|
||||||
*
|
*
|
||||||
* <elf_info>
|
* <elf_info>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------------------
|
||||||
* core - core where exception was triggered
|
* core - core where exception was triggered
|
||||||
* exception - what kind of exception occurred
|
* exception - what kind of exception occurred
|
||||||
* description - a short description regarding the exception that occurred
|
* description - a short description regarding the exception that occurred
|
||||||
* details - more details about the exception
|
* details - more details about the exception
|
||||||
* state - processor state like register contents, and backtrace
|
* state - processor state like register contents, and backtrace
|
||||||
* elf_info - details about the image currently running
|
* elf_info - details about the image currently running
|
||||||
*
|
*
|
||||||
* NULL fields in panic_info_t are not printed.
|
* NULL fields in panic_info_t are not printed.
|
||||||
*
|
*
|
||||||
* */
|
*/
|
||||||
if (info->reason) {
|
if (info->reason) {
|
||||||
panic_print_str("Guru Meditation Error: Core ");
|
panic_print_str("Guru Meditation Error: Core ");
|
||||||
panic_print_dec(info->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_str("Setting breakpoint at 0x");
|
||||||
panic_print_hex((uint32_t)info->addr);
|
panic_print_hex((uint32_t)info->addr);
|
||||||
panic_print_str(" and returning...\r\n");
|
panic_print_str(" and returning...\r\n");
|
||||||
disable_all_wdts();
|
|
||||||
#if CONFIG_APPTRACE_ENABLE
|
#if CONFIG_APPTRACE_ENABLE
|
||||||
#if CONFIG_APPTRACE_SV_ENABLE
|
#if CONFIG_APPTRACE_SV_ENABLE
|
||||||
SEGGER_RTT_ESP_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
|
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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
disable_all_wdts();
|
||||||
esp_cpu_set_breakpoint(0, info->addr); // use breakpoint 0
|
esp_cpu_set_breakpoint(0, info->addr); // use breakpoint 0
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif //CONFIG_ESP_DEBUG_OCDAWARE
|
#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);
|
|
||||||
|
|
||||||
}
|
/* 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_reconfigure_wdts(1000); // Restart WDT again
|
*/
|
||||||
|
esp_panic_handler_feed_wdts();
|
||||||
|
|
||||||
PANIC_INFO_DUMP(info, state);
|
PANIC_INFO_DUMP(info, state);
|
||||||
panic_print_str("\r\n");
|
panic_print_str("\r\n");
|
||||||
@ -361,66 +396,45 @@ void esp_panic_handler(panic_info_t *info)
|
|||||||
panic_print_str("\r\n");
|
panic_print_str("\r\n");
|
||||||
|
|
||||||
#if CONFIG_APPTRACE_ENABLE
|
#if CONFIG_APPTRACE_ENABLE
|
||||||
disable_all_wdts();
|
esp_panic_handler_feed_wdts();
|
||||||
#if CONFIG_APPTRACE_SV_ENABLE
|
#if CONFIG_APPTRACE_SV_ENABLE
|
||||||
SEGGER_RTT_ESP_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
|
SEGGER_RTT_ESP_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
|
||||||
#else
|
#else
|
||||||
esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH,
|
esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH,
|
||||||
APPTRACE_ONPANIC_HOST_FLUSH_TMO);
|
APPTRACE_ONPANIC_HOST_FLUSH_TMO);
|
||||||
#endif
|
#endif
|
||||||
esp_panic_handler_reconfigure_wdts(1000); // restore WDT config
|
|
||||||
#endif // CONFIG_APPTRACE_ENABLE
|
#endif // CONFIG_APPTRACE_ENABLE
|
||||||
|
|
||||||
#if CONFIG_ESP_COREDUMP_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) {
|
if (s_dumping_core) {
|
||||||
panic_print_str("Re-entered core dump! Exception happened during core dump!\r\n");
|
panic_print_str("Re-entered core dump! Exception happened during core dump!\r\n");
|
||||||
} else {
|
} else {
|
||||||
disable_all_wdts();
|
|
||||||
s_dumping_core = true;
|
s_dumping_core = true;
|
||||||
esp_core_dump_write(info);
|
esp_core_dump_write(info);
|
||||||
s_dumping_core = false;
|
s_dumping_core = false;
|
||||||
esp_panic_handler_reconfigure_wdts(1000);
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_ESP_COREDUMP_ENABLE */
|
#endif /* CONFIG_ESP_COREDUMP_ENABLE */
|
||||||
|
|
||||||
#if CONFIG_ESP_SYSTEM_PANIC_GDBSTUB
|
#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");
|
panic_print_str("Entering gdb stub now.\r\n");
|
||||||
|
disable_all_wdts();
|
||||||
esp_gdbstub_panic_handler((void *)info->frame);
|
esp_gdbstub_panic_handler((void *)info->frame);
|
||||||
#else
|
#else
|
||||||
#if CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS
|
#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
|
esp_panic_handler_feed_wdts();
|
||||||
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);
|
|
||||||
|
|
||||||
panic_print_str("Rebooting in ");
|
panic_print_str("Rebooting in ");
|
||||||
panic_print_dec(CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS);
|
panic_print_dec(CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS);
|
||||||
panic_print_str(" seconds...\r\n");
|
panic_print_str(" seconds...\r\n");
|
||||||
|
|
||||||
esp_rom_delay_us(CONFIG_ESP_SYSTEM_PANIC_REBOOT_DELAY_SECONDS * 1000000);
|
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 */
|
#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
|
#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) {
|
if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) {
|
||||||
switch (info->exception) {
|
switch (info->exception) {
|
||||||
case PANIC_EXCEPTION_IWDT:
|
case PANIC_EXCEPTION_IWDT:
|
||||||
@ -440,9 +454,9 @@ void esp_panic_handler(panic_info_t *info)
|
|||||||
panic_print_str("Rebooting...\r\n");
|
panic_print_str("Rebooting...\r\n");
|
||||||
panic_restart();
|
panic_restart();
|
||||||
#else /* CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT */
|
#else /* CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT */
|
||||||
disable_all_wdts();
|
|
||||||
panic_print_str("CPU halted.\r\n");
|
panic_print_str("CPU halted.\r\n");
|
||||||
esp_system_reset_modules_on_exit();
|
esp_system_reset_modules_on_exit();
|
||||||
|
disable_all_wdts();
|
||||||
ESP_INFINITE_LOOP();
|
ESP_INFINITE_LOOP();
|
||||||
#endif /* CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT */
|
#endif /* CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT */
|
||||||
#endif /* CONFIG_ESP_SYSTEM_PANIC_GDBSTUB */
|
#endif /* CONFIG_ESP_SYSTEM_PANIC_GDBSTUB */
|
||||||
|
@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -42,11 +42,15 @@
|
|||||||
#include "esp_private/hw_stack_guard.h"
|
#include "esp_private/hw_stack_guard.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void esp_panic_handler_reconfigure_wdts(uint32_t timeout_ms);
|
|
||||||
|
|
||||||
extern void esp_panic_handler(panic_info_t *);
|
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};
|
void *g_exc_frames[SOC_CPU_CORES_NUM] = {NULL};
|
||||||
|
|
||||||
@ -130,12 +134,52 @@ void busy_wait(void)
|
|||||||
|
|
||||||
static void panic_handler(void *frame, bool pseudo_excause)
|
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 };
|
panic_info_t info = { 0 };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup environment and perform necessary architecture/chip specific
|
* Setup environment and perform necessary architecture/chip specific
|
||||||
* steps here prior to the system panic handler.
|
* steps here prior to the system panic handler.
|
||||||
* */
|
*/
|
||||||
int core_id = esp_cpu_get_core_id();
|
int core_id = esp_cpu_get_core_id();
|
||||||
|
|
||||||
// If multiple cores arrive at panic handler, save frames for all of them
|
// If multiple cores arrive at panic handler, save frames for all of them
|
||||||
@ -176,8 +220,12 @@ static void panic_handler(void *frame, bool pseudo_excause)
|
|||||||
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to reconfigure WDTs before we stall any other CPU
|
/* Before we stall the other CPU, we need to disable all WDTs except the RTC WDT.
|
||||||
esp_panic_handler_reconfigure_wdts(1000);
|
* 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);
|
esp_rom_delay_us(1);
|
||||||
// Stall all other cores
|
// Stall all other cores
|
||||||
@ -186,6 +234,12 @@ static void panic_handler(void *frame, bool pseudo_excause)
|
|||||||
esp_cpu_stall(i);
|
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
|
#endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
|
||||||
|
|
||||||
esp_ipc_isr_stall_abort();
|
esp_ipc_isr_stall_abort();
|
||||||
@ -201,15 +255,6 @@ static void panic_handler(void *frame, bool pseudo_excause)
|
|||||||
panic_set_address(frame, (uint32_t)&_invalid_pc_placeholder);
|
panic_set_address(frame, (uint32_t)&_invalid_pc_placeholder);
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
// Convert architecture exception frame into abstracted panic info
|
||||||
|
@ -29,6 +29,8 @@ In certain situations, the execution of the program can not be continued in a we
|
|||||||
|
|
||||||
This guide explains the procedure used in ESP-IDF for handling these errors, and provides suggestions on troubleshooting the errors.
|
This guide explains the procedure used in ESP-IDF for handling these errors, and provides suggestions on troubleshooting the errors.
|
||||||
|
|
||||||
|
.. _Panic-Handler:
|
||||||
|
|
||||||
Panic Handler
|
Panic Handler
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
@ -306,6 +308,8 @@ The RTC watchdog is used in the startup code to keep track of execution time and
|
|||||||
|
|
||||||
The RTC watchdog covers the execution time from the first stage (ROM) bootloader to application startup. It is initially set in the first stage (ROM) bootloader, then configured in the bootloader with the :ref:`CONFIG_BOOTLOADER_WDT_TIME_MS` option (9000 ms by default). During the application initialization stage, it is reconfigured because the source of the slow clock may have changed, and finally disabled right before the ``app_main()`` call. There is an option :ref:`CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE` which prevents the RTC watchdog from being disabled before ``app_main``. Instead, the RTC watchdog remains active and must be fed periodically in your application's code.
|
The RTC watchdog covers the execution time from the first stage (ROM) bootloader to application startup. It is initially set in the first stage (ROM) bootloader, then configured in the bootloader with the :ref:`CONFIG_BOOTLOADER_WDT_TIME_MS` option (9000 ms by default). During the application initialization stage, it is reconfigured because the source of the slow clock may have changed, and finally disabled right before the ``app_main()`` call. There is an option :ref:`CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE` which prevents the RTC watchdog from being disabled before ``app_main``. Instead, the RTC watchdog remains active and must be fed periodically in your application's code.
|
||||||
|
|
||||||
|
The RTC watchdog is also used by the system :ref:`panic handler <Panic-Handler>` to protect the system from hanging during a panic. The RTC watchdog is reconfigured in the panic handler to have a timeout of 10 seconds. If the panic handler takes longer than 10 seconds to execute, the system will be reset by the RTC watchdog.
|
||||||
|
|
||||||
.. _Guru-Meditation-Errors:
|
.. _Guru-Meditation-Errors:
|
||||||
|
|
||||||
Guru Meditation Errors
|
Guru Meditation Errors
|
||||||
|
@ -29,10 +29,12 @@
|
|||||||
|
|
||||||
本指南会介绍 ESP-IDF 中这类错误的处理流程,并给出对应的解决建议。
|
本指南会介绍 ESP-IDF 中这类错误的处理流程,并给出对应的解决建议。
|
||||||
|
|
||||||
|
.. _Panic-Handler:
|
||||||
|
|
||||||
紧急处理程序
|
紧急处理程序
|
||||||
------------
|
------------
|
||||||
|
|
||||||
:ref:`Overview` 中列举的所有错误都会由 *紧急处理程序 (Panic Handler)* 负责处理。
|
:ref:`Overview` 中列举的所有出错原因都会由 *紧急处理程序 (Panic Handler)* 处理。
|
||||||
|
|
||||||
紧急处理程序首先会将出错原因打印到控制台,例如 CPU 异常的错误信息通常会类似于
|
紧急处理程序首先会将出错原因打印到控制台,例如 CPU 异常的错误信息通常会类似于
|
||||||
|
|
||||||
@ -46,7 +48,7 @@
|
|||||||
|
|
||||||
Guru Meditation Error: Core 0 panic'ed (|CACHE_ERR_MSG|). Exception was unhandled.
|
Guru Meditation Error: Core 0 panic'ed (|CACHE_ERR_MSG|). Exception was unhandled.
|
||||||
|
|
||||||
不管哪种情况,错误原因都会被打印在括号中。请参阅 :ref:`Guru-Meditation-Errors` 以查看所有可能的出错原因。
|
不管哪种情况,出错原因都会以括号形式打印出来。请参阅 :ref:`Guru-Meditation-Errors` 以查看所有可能的出错原因。
|
||||||
|
|
||||||
紧急处理程序接下来的行为将取决于 :ref:`CONFIG_ESP_SYSTEM_PANIC` 的设置,支持的选项包括:
|
紧急处理程序接下来的行为将取决于 :ref:`CONFIG_ESP_SYSTEM_PANIC` 的设置,支持的选项包括:
|
||||||
|
|
||||||
@ -306,6 +308,8 @@ RTC 看门狗在启动代码中用于跟踪执行时间,也有助于防止由
|
|||||||
|
|
||||||
RTC 看门狗涵盖了从一级 (ROM) 引导加载程序到应用程序启动的执行时间,最初在一级 (ROM) 引导加载程序中设置,而后在引导加载程序中使用 :ref:`CONFIG_BOOTLOADER_WDT_TIME_MS` 选项进行配置(默认 9000 ms)。在应用初始化阶段,由于慢速时钟源可能已更改,RTC 看门狗将被重新配置,最后在调用 ``app_main()`` 之前被禁用。可以使用选项 :ref:`CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE` 以保证 RTC 看门狗在调用 ``app_main`` 之前不被禁用,而是保持运行状态,用户需要在应用代码中定期“喂狗”。
|
RTC 看门狗涵盖了从一级 (ROM) 引导加载程序到应用程序启动的执行时间,最初在一级 (ROM) 引导加载程序中设置,而后在引导加载程序中使用 :ref:`CONFIG_BOOTLOADER_WDT_TIME_MS` 选项进行配置(默认 9000 ms)。在应用初始化阶段,由于慢速时钟源可能已更改,RTC 看门狗将被重新配置,最后在调用 ``app_main()`` 之前被禁用。可以使用选项 :ref:`CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE` 以保证 RTC 看门狗在调用 ``app_main`` 之前不被禁用,而是保持运行状态,用户需要在应用代码中定期“喂狗”。
|
||||||
|
|
||||||
|
:ref:`紧急处理程序 <Panic-Handler>` 通过 RTC 看门狗保护机制,确保系统在遇到严重错误时不会陷入死循环。紧急处理程序会重新配置 RTC 看门狗的超时时间为 10 秒。如果 10 秒内紧急处理程序没有完成,RTC 看门狗将会强制复位系统。
|
||||||
|
|
||||||
.. _Guru-Meditation-Errors:
|
.. _Guru-Meditation-Errors:
|
||||||
|
|
||||||
Guru Meditation 错误
|
Guru Meditation 错误
|
||||||
|
@ -7,6 +7,8 @@ if((IDF_TARGET STREQUAL "esp32s2") OR (IDF_TARGET STREQUAL "esp32c3") OR (IDF_TA
|
|||||||
|
|
||||||
target_link_libraries(${project_elf} PRIVATE
|
target_link_libraries(${project_elf} PRIVATE
|
||||||
"-Wl,--wrap=esp_panic_handler"
|
"-Wl,--wrap=esp_panic_handler"
|
||||||
"-Wl,--wrap=esp_panic_handler_reconfigure_wdts"
|
"-Wl,--wrap=esp_panic_handler_feed_wdts"
|
||||||
|
"-Wl,--wrap=esp_panic_handler_enable_rtc_wdt"
|
||||||
|
"-Wl,--wrap=esp_panic_handler_increment_entry_count"
|
||||||
"-Wl,--wrap=esp_cpu_stall")
|
"-Wl,--wrap=esp_cpu_stall")
|
||||||
endif()
|
endif()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -7,14 +7,45 @@
|
|||||||
#include "riscv/rvruntime-frames.h"
|
#include "riscv/rvruntime-frames.h"
|
||||||
#include "esp_private/panic_internal.h"
|
#include "esp_private/panic_internal.h"
|
||||||
#include "esp_private/panic_reason.h"
|
#include "esp_private/panic_reason.h"
|
||||||
|
#include "hal/wdt_hal.h"
|
||||||
|
|
||||||
|
|
||||||
extern void esp_panic_handler(panic_info_t *info);
|
extern void esp_panic_handler(panic_info_t *info);
|
||||||
volatile bool g_override_illegal_instruction = false;
|
volatile bool g_override_illegal_instruction = false;
|
||||||
|
|
||||||
void __real_esp_panic_handler(panic_info_t *info);
|
void __real_esp_panic_handler(panic_info_t *info);
|
||||||
|
void __real_esp_panic_handler_feed_wdts(void);
|
||||||
|
void __real_esp_panic_handler_enable_rtc_wdt(uint32_t timeout_ms);
|
||||||
|
void __real_esp_panic_handler_increment_entry_count(void);
|
||||||
void __real_esp_cpu_stall(int core_id);
|
void __real_esp_cpu_stall(int core_id);
|
||||||
|
|
||||||
|
static void disable_all_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_write_protect_disable(&wdt1_context);
|
||||||
|
wdt_hal_disable(&wdt1_context);
|
||||||
|
wdt_hal_write_protect_enable(&wdt1_context);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Disable RTC WDT
|
||||||
|
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
||||||
|
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||||
|
wdt_hal_disable(&rtc_wdt_ctx);
|
||||||
|
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
void return_from_panic_handler(RvExcFrame *frm) __attribute__((noreturn));
|
void return_from_panic_handler(RvExcFrame *frm) __attribute__((noreturn));
|
||||||
|
|
||||||
/* Memprot test specific IllegalInstruction exception handler:
|
/* Memprot test specific IllegalInstruction exception handler:
|
||||||
@ -44,6 +75,34 @@ void __wrap_esp_panic_handler(panic_info_t *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __wrap_esp_panic_handler_feed_wdts(void)
|
||||||
|
{
|
||||||
|
if ( g_override_illegal_instruction == true ) {
|
||||||
|
disable_all_wdts();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
__real_esp_panic_handler_feed_wdts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_esp_panic_handler_enable_rtc_wdt(uint32_t timeout_ms)
|
||||||
|
{
|
||||||
|
if ( g_override_illegal_instruction == true ) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
__real_esp_panic_handler_enable_rtc_wdt(timeout_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_esp_panic_handler_increment_entry_count(void)
|
||||||
|
{
|
||||||
|
if ( g_override_illegal_instruction == true ) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
__real_esp_panic_handler_increment_entry_count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void __wrap_esp_cpu_stall(int core_id)
|
void __wrap_esp_cpu_stall(int core_id)
|
||||||
{
|
{
|
||||||
if ( g_override_illegal_instruction == true ) {
|
if ( g_override_illegal_instruction == true ) {
|
||||||
|
@ -1,18 +1,49 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xtensa_context.h"
|
#include "xtensa_context.h"
|
||||||
#include "esp_private/panic_internal.h"
|
#include "esp_private/panic_internal.h"
|
||||||
|
#include "hal/wdt_hal.h"
|
||||||
|
|
||||||
extern void esp_panic_handler(panic_info_t *info);
|
extern void esp_panic_handler(panic_info_t *info);
|
||||||
extern volatile bool g_override_illegal_instruction;
|
extern volatile bool g_override_illegal_instruction;
|
||||||
|
|
||||||
void __real_esp_panic_handler(panic_info_t *info);
|
void __real_esp_panic_handler(panic_info_t *info);
|
||||||
|
void __real_esp_panic_handler_feed_wdts(void);
|
||||||
|
void __real_esp_panic_handler_enable_rtc_wdt(uint32_t timeout_ms);
|
||||||
|
void __real_esp_panic_handler_increment_entry_count(void);
|
||||||
void __real_esp_cpu_stall(int core_id);
|
void __real_esp_cpu_stall(int core_id);
|
||||||
|
|
||||||
|
static void disable_all_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_write_protect_disable(&wdt1_context);
|
||||||
|
wdt_hal_disable(&wdt1_context);
|
||||||
|
wdt_hal_write_protect_enable(&wdt1_context);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Disable RTC WDT
|
||||||
|
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
||||||
|
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||||
|
wdt_hal_disable(&rtc_wdt_ctx);
|
||||||
|
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/* Memprot test specific IllegalInstruction exception handler:
|
/* Memprot test specific IllegalInstruction exception handler:
|
||||||
* when testing the protection against a code execution, sample code
|
* when testing the protection against a code execution, sample code
|
||||||
* is being injected into various memory regions which produces
|
* is being injected into various memory regions which produces
|
||||||
@ -35,6 +66,34 @@ void __wrap_esp_panic_handler(panic_info_t *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void __wrap_esp_panic_handler_feed_wdts(void)
|
||||||
|
{
|
||||||
|
if ( g_override_illegal_instruction == true ) {
|
||||||
|
disable_all_wdts();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
__real_esp_panic_handler_feed_wdts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_esp_panic_handler_enable_rtc_wdt(uint32_t timeout_ms)
|
||||||
|
{
|
||||||
|
if ( g_override_illegal_instruction == true ) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
__real_esp_panic_handler_enable_rtc_wdt(timeout_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_esp_panic_handler_increment_entry_count(void)
|
||||||
|
{
|
||||||
|
if ( g_override_illegal_instruction == true ) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
__real_esp_panic_handler_increment_entry_count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void __wrap_esp_cpu_stall(int core_id)
|
void __wrap_esp_cpu_stall(int core_id)
|
||||||
{
|
{
|
||||||
if (g_override_illegal_instruction == true) {
|
if (g_override_illegal_instruction == true) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -12,10 +12,11 @@ extern void esp_panic_handler(panic_info_t *info);
|
|||||||
extern volatile bool g_override_illegal_instruction;
|
extern volatile bool g_override_illegal_instruction;
|
||||||
|
|
||||||
void __real_esp_panic_handler(panic_info_t *info);
|
void __real_esp_panic_handler(panic_info_t *info);
|
||||||
void __real_esp_panic_handler_reconfigure_wdts(void);
|
void __real_esp_panic_handler_feed_wdts(void);
|
||||||
|
void __real_esp_panic_handler_enable_rtc_wdt(uint32_t timeout_ms);
|
||||||
|
void __real_esp_panic_handler_increment_entry_count(void);
|
||||||
void __real_esp_cpu_stall(int core_id);
|
void __real_esp_cpu_stall(int core_id);
|
||||||
|
|
||||||
|
|
||||||
static void disable_all_wdts(void)
|
static void disable_all_wdts(void)
|
||||||
{
|
{
|
||||||
wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
|
wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
|
||||||
@ -30,11 +31,17 @@ static void disable_all_wdts(void)
|
|||||||
wdt_hal_write_protect_enable(&wdt0_context);
|
wdt_hal_write_protect_enable(&wdt0_context);
|
||||||
|
|
||||||
#if SOC_TIMER_GROUPS >= 2
|
#if SOC_TIMER_GROUPS >= 2
|
||||||
//Interupt WDT is the Main Watchdog Timer of Timer Group 1
|
//Interrupt WDT is the Main Watchdog Timer of Timer Group 1
|
||||||
wdt_hal_write_protect_disable(&wdt1_context);
|
wdt_hal_write_protect_disable(&wdt1_context);
|
||||||
wdt_hal_disable(&wdt1_context);
|
wdt_hal_disable(&wdt1_context);
|
||||||
wdt_hal_write_protect_enable(&wdt1_context);
|
wdt_hal_write_protect_enable(&wdt1_context);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//Disable RTC WDT
|
||||||
|
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
|
||||||
|
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
|
||||||
|
wdt_hal_disable(&rtc_wdt_ctx);
|
||||||
|
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Memprot test specific IllegalInstruction exception handler:
|
/* Memprot test specific IllegalInstruction exception handler:
|
||||||
@ -59,13 +66,31 @@ void __wrap_esp_panic_handler(panic_info_t *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void __wrap_esp_panic_handler_reconfigure_wdts(void)
|
void __wrap_esp_panic_handler_feed_wdts(void)
|
||||||
{
|
{
|
||||||
if ( g_override_illegal_instruction == true ) {
|
if ( g_override_illegal_instruction == true ) {
|
||||||
disable_all_wdts();
|
disable_all_wdts();
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
__real_esp_panic_handler_reconfigure_wdts();
|
__real_esp_panic_handler_feed_wdts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_esp_panic_handler_enable_rtc_wdt(uint32_t timeout_ms)
|
||||||
|
{
|
||||||
|
if ( g_override_illegal_instruction == true ) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
__real_esp_panic_handler_enable_rtc_wdt(timeout_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_esp_panic_handler_increment_entry_count(void)
|
||||||
|
{
|
||||||
|
if ( g_override_illegal_instruction == true ) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
__real_esp_panic_handler_increment_entry_count();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,4 +44,6 @@ if(NOT CONFIG_TEST_MEMPROT AND NOT CONFIG_ESP_COREDUMP_CAPTURE_DRAM)
|
|||||||
idf_component_get_property(lib ${component} COMPONENT_LIB)
|
idf_component_get_property(lib ${component} COMPONENT_LIB)
|
||||||
target_compile_options(${lib} PRIVATE ${ubsan_options})
|
target_compile_options(${lib} PRIVATE ${ubsan_options})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
target_link_libraries(${project_elf} PRIVATE "-Wl,--wrap=esp_panic_handler")
|
||||||
endif()
|
endif()
|
||||||
|
@ -9,6 +9,8 @@ if(CONFIG_TEST_MEMPROT)
|
|||||||
list(APPEND srcs "panic_utils/memprot_panic_utils_riscv.c")
|
list(APPEND srcs "panic_utils/memprot_panic_utils_riscv.c")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
else()
|
||||||
|
list(APPEND srcs "panic_utils/panic_utils.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS "${srcs}"
|
idf_component_register(SRCS "${srcs}"
|
||||||
|
@ -40,8 +40,14 @@ void test_panic_extram_stack_bss(void);
|
|||||||
|
|
||||||
#if !CONFIG_FREERTOS_UNICORE
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
void test_task_wdt_cpu1(void);
|
void test_task_wdt_cpu1(void);
|
||||||
|
void test_panic_handler_stuck1(void);
|
||||||
|
void test_panic_handler_crash1(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void test_panic_handler_stuck0(void);
|
||||||
|
|
||||||
|
void test_panic_handler_crash0(void);
|
||||||
|
|
||||||
void test_loadprohibited(void);
|
void test_loadprohibited(void);
|
||||||
|
|
||||||
void test_storeprohibited(void);
|
void test_storeprohibited(void);
|
||||||
|
51
tools/test_apps/system/panic/main/panic_utils/panic_utils.c
Normal file
51
tools/test_apps/system/panic/main/panic_utils/panic_utils.c
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include "esp_cpu.h"
|
||||||
|
#include "esp_private/panic_internal.h"
|
||||||
|
#include "esp_rom_sys.h"
|
||||||
|
|
||||||
|
extern volatile uint32_t g_panic_handler_stuck;
|
||||||
|
extern volatile uint32_t g_panic_handler_crash;
|
||||||
|
extern void __real_esp_panic_handler(panic_info_t *info);
|
||||||
|
|
||||||
|
void __wrap_esp_panic_handler(panic_info_t *info)
|
||||||
|
{
|
||||||
|
if (g_panic_handler_stuck) {
|
||||||
|
/* Override the panic handler for the panic handler stuck test */
|
||||||
|
|
||||||
|
/* Stall the other core */
|
||||||
|
int core_id = esp_cpu_get_core_id();
|
||||||
|
for (uint32_t i = 0; i < SOC_CPU_CORES_NUM; i++) {
|
||||||
|
if (i != core_id) {
|
||||||
|
esp_cpu_stall(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the panic handler to loop */
|
||||||
|
esp_rom_printf("Panic handler stuck\n");
|
||||||
|
while (1) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
} else if (g_panic_handler_crash) {
|
||||||
|
/* Override the panic handler for the panic handler crash test */
|
||||||
|
|
||||||
|
static int crash_count = 0;
|
||||||
|
esp_rom_printf("Panic handler crashed %d times\n", ++crash_count);
|
||||||
|
|
||||||
|
/* We just return from the panic handler to cause a crash again
|
||||||
|
* since the offending program counter is not reset. Forcing
|
||||||
|
* a crash here via another illegal instruction can cause some
|
||||||
|
* RISC-V cores (such as esp32c5, esp32c61) to take evasive action
|
||||||
|
* due to a CPU LOCKUP type exception and reboot without the panic
|
||||||
|
* handler being called again.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
/* Fall back to the default panic handler for all other tests */
|
||||||
|
__real_esp_panic_handler(info);
|
||||||
|
}
|
||||||
|
}
|
@ -106,6 +106,8 @@ void app_main(void)
|
|||||||
#endif
|
#endif
|
||||||
#if !CONFIG_FREERTOS_UNICORE
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
HANDLE_TEST(test_name, test_task_wdt_cpu1);
|
HANDLE_TEST(test_name, test_task_wdt_cpu1);
|
||||||
|
HANDLE_TEST(test_name, test_panic_handler_stuck1);
|
||||||
|
HANDLE_TEST(test_name, test_panic_handler_crash1);
|
||||||
#endif
|
#endif
|
||||||
HANDLE_TEST(test_name, test_loadprohibited);
|
HANDLE_TEST(test_name, test_loadprohibited);
|
||||||
HANDLE_TEST(test_name, test_storeprohibited);
|
HANDLE_TEST(test_name, test_storeprohibited);
|
||||||
@ -119,6 +121,8 @@ void app_main(void)
|
|||||||
HANDLE_TEST(test_name, test_assert_cache_disabled);
|
HANDLE_TEST(test_name, test_assert_cache_disabled);
|
||||||
HANDLE_TEST(test_name, test_assert_cache_write_back_error_can_print_backtrace);
|
HANDLE_TEST(test_name, test_assert_cache_write_back_error_can_print_backtrace);
|
||||||
HANDLE_TEST(test_name, test_tcb_corrupted);
|
HANDLE_TEST(test_name, test_tcb_corrupted);
|
||||||
|
HANDLE_TEST(test_name, test_panic_handler_stuck0);
|
||||||
|
HANDLE_TEST(test_name, test_panic_handler_crash0);
|
||||||
#if CONFIG_ESP_SYSTEM_USE_FRAME_POINTER
|
#if CONFIG_ESP_SYSTEM_USE_FRAME_POINTER
|
||||||
HANDLE_TEST(test_name, test_panic_print_backtrace);
|
HANDLE_TEST(test_name, test_panic_print_backtrace);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
*/
|
*/
|
||||||
@ -25,6 +25,9 @@
|
|||||||
#include "hal/mpu_hal.h"
|
#include "hal/mpu_hal.h"
|
||||||
#include "rom/cache.h"
|
#include "rom/cache.h"
|
||||||
|
|
||||||
|
volatile uint32_t g_panic_handler_stuck = 0;
|
||||||
|
volatile uint32_t g_panic_handler_crash = 0;
|
||||||
|
|
||||||
/* Test utility function */
|
/* Test utility function */
|
||||||
|
|
||||||
extern void esp_restart_noos(void) __attribute__ ((noreturn));
|
extern void esp_restart_noos(void) __attribute__ ((noreturn));
|
||||||
@ -132,6 +135,34 @@ void test_panic_extram_stack_bss(void)
|
|||||||
#endif // ESP_COREDUMP_ENABLE_TO_FLASH && FREERTOS_TASK_CREATE_ALLOW_EXT_MEM
|
#endif // ESP_COREDUMP_ENABLE_TO_FLASH && FREERTOS_TASK_CREATE_ALLOW_EXT_MEM
|
||||||
|
|
||||||
|
|
||||||
|
void __attribute__((no_sanitize_undefined)) test_panic_handler_stuck(void *arg)
|
||||||
|
{
|
||||||
|
g_panic_handler_stuck = 1;
|
||||||
|
|
||||||
|
/* Cause a panic */
|
||||||
|
#ifdef __XTENSA__
|
||||||
|
asm("ill"); // should be an invalid operation on xtensa targets
|
||||||
|
#elif __riscv
|
||||||
|
asm("unimp"); // should be an invalid operation on RISC-V targets
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((no_sanitize_undefined)) test_panic_handler_crash(void *arg)
|
||||||
|
{
|
||||||
|
g_panic_handler_crash = 1;
|
||||||
|
|
||||||
|
/* Cause a panic */
|
||||||
|
#ifdef __XTENSA__
|
||||||
|
asm("ill");
|
||||||
|
#elif __riscv
|
||||||
|
asm("unimp");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#if !CONFIG_FREERTOS_UNICORE
|
#if !CONFIG_FREERTOS_UNICORE
|
||||||
static void infinite_loop(void* arg) {
|
static void infinite_loop(void* arg) {
|
||||||
(void) arg;
|
(void) arg;
|
||||||
@ -148,8 +179,47 @@ void test_task_wdt_cpu1(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_panic_handler_stuck1(void)
|
||||||
|
{
|
||||||
|
/* Cause the panic on core 1 */
|
||||||
|
xTaskCreatePinnedToCore(test_panic_handler_stuck, "panic_handler_stuck", 2048, NULL, 1, NULL, 1);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
vTaskDelay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_panic_handler_crash1(void)
|
||||||
|
{
|
||||||
|
/* Cause the panic on core 1 */
|
||||||
|
xTaskCreatePinnedToCore(test_panic_handler_crash, "panic_handler_crash", 2048, NULL, 1, NULL, 1);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
vTaskDelay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void test_panic_handler_stuck0(void)
|
||||||
|
{
|
||||||
|
/* Cause the panic on core 0 */
|
||||||
|
xTaskCreatePinnedToCore(test_panic_handler_stuck, "panic_handler_stuck", 2048, NULL, 1, NULL, 0);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
vTaskDelay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_panic_handler_crash0(void)
|
||||||
|
{
|
||||||
|
/* Cause the panic on core 0 */
|
||||||
|
xTaskCreatePinnedToCore(test_panic_handler_crash, "panic_handler_crash", 2048, NULL, 1, NULL, 0);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
vTaskDelay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void __attribute__((no_sanitize_undefined)) test_storeprohibited(void)
|
void __attribute__((no_sanitize_undefined)) test_storeprohibited(void)
|
||||||
{
|
{
|
||||||
*(int*) 0x4 = 0;
|
*(int*) 0x4 = 0;
|
||||||
|
@ -641,6 +641,74 @@ def test_panic_delay(dut: PanicTestDut) -> None:
|
|||||||
dut.expect_exact('rst:0xc (SW_CPU_RESET)')
|
dut.expect_exact('rst:0xc (SW_CPU_RESET)')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('config', ['panic'], indirect=True)
|
||||||
|
@pytest.mark.supported_targets
|
||||||
|
@pytest.mark.generic
|
||||||
|
def test_panic_handler_stuck0(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
||||||
|
dut.run_test_func(test_func_name)
|
||||||
|
|
||||||
|
# Expect a panic handler stuck message
|
||||||
|
dut.expect_exact('Panic handler stuck')
|
||||||
|
|
||||||
|
# Expect a reboot
|
||||||
|
dut.expect_cpu_reset()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('config', ['panic'], indirect=True)
|
||||||
|
@pytest.mark.esp32
|
||||||
|
@pytest.mark.esp32s3
|
||||||
|
@pytest.mark.esp32p4
|
||||||
|
@pytest.mark.generic
|
||||||
|
def test_panic_handler_stuck1(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
||||||
|
dut.run_test_func(test_func_name)
|
||||||
|
|
||||||
|
# Expect a panic handler stuck message
|
||||||
|
dut.expect_exact('Panic handler stuck')
|
||||||
|
|
||||||
|
# Expect a reboot
|
||||||
|
dut.expect_cpu_reset()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('config', ['panic'], indirect=True)
|
||||||
|
@pytest.mark.supported_targets
|
||||||
|
@pytest.mark.generic
|
||||||
|
def test_panic_handler_crash0(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
||||||
|
dut.run_test_func(test_func_name)
|
||||||
|
|
||||||
|
# Expect a panic handler crash message
|
||||||
|
dut.expect_exact('Panic handler crashed 1 times')
|
||||||
|
|
||||||
|
# Expect a the second panic handler crash message
|
||||||
|
dut.expect_exact('Panic handler crashed 2 times')
|
||||||
|
|
||||||
|
# Expect bailout message
|
||||||
|
dut.expect_exact('Panic handler entered multiple times. Abort panic handling. Rebooting ...')
|
||||||
|
|
||||||
|
# Expect a reboot
|
||||||
|
dut.expect_cpu_reset()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('config', ['panic'], indirect=True)
|
||||||
|
@pytest.mark.esp32
|
||||||
|
@pytest.mark.esp32s3
|
||||||
|
@pytest.mark.esp32p4
|
||||||
|
@pytest.mark.generic
|
||||||
|
def test_panic_handler_crash1(dut: PanicTestDut, config: str, test_func_name: str) -> None:
|
||||||
|
dut.run_test_func(test_func_name)
|
||||||
|
|
||||||
|
# Expect a panic handler crash message
|
||||||
|
dut.expect_exact('Panic handler crashed 1 times')
|
||||||
|
|
||||||
|
# Expect a the second panic handler crash message
|
||||||
|
dut.expect_exact('Panic handler crashed 2 times')
|
||||||
|
|
||||||
|
# Expect bailout message
|
||||||
|
dut.expect_exact('Panic handler entered multiple times. Abort panic handling. Rebooting ...')
|
||||||
|
|
||||||
|
# Expect a reboot
|
||||||
|
dut.expect_cpu_reset()
|
||||||
|
|
||||||
|
|
||||||
#########################
|
#########################
|
||||||
# for memprot test only #
|
# for memprot test only #
|
||||||
#########################
|
#########################
|
||||||
|
@ -32,7 +32,7 @@ class PanicTestDut(IdfDut):
|
|||||||
COREDUMP_UART_END = r'================= CORE DUMP END ================='
|
COREDUMP_UART_END = r'================= CORE DUMP END ================='
|
||||||
COREDUMP_CHECKSUM = r"Coredump checksum='([a-fA-F0-9]+)'"
|
COREDUMP_CHECKSUM = r"Coredump checksum='([a-fA-F0-9]+)'"
|
||||||
REBOOT = r'.*Rebooting\.\.\.'
|
REBOOT = r'.*Rebooting\.\.\.'
|
||||||
CPU_RESET = r'.*rst:.*(RTC_SW_CPU_RST|SW_CPU_RESET|SW_CPU)\b'
|
CPU_RESET = r'.*rst:.*(RTC_SW_CPU_RST|SW_CPU_RESET|SW_CPU|RTCWDT_RTC_RESET|LP_WDT_SYS|RTCWDT_RTC_RST|CHIP_LP_WDT_RESET|RTC_WDT_SYS)\b'
|
||||||
|
|
||||||
app: IdfApp
|
app: IdfApp
|
||||||
serial: IdfSerial
|
serial: IdfSerial
|
||||||
|
Loading…
x
Reference in New Issue
Block a user