Merge branch 'fix/panic_handler_reboot_before_halt' into 'master'

fix(panic_handler): Fixed a issue where the system reboots before halt

Closes IDFGH-16214

See merge request espressif/esp-idf!41194
This commit is contained in:
Sudeep Mohanty
2025-08-14 11:00:02 +02:00
6 changed files with 48 additions and 13 deletions

View File

@@ -262,6 +262,14 @@ static inline void disable_all_wdts(void)
wdt_hal_write_protect_enable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx);
} }
/* IRAM-only halt stub: reset modules, then loop */
void IRAM_ATTR esp_panic_handler_reset_modules_on_exit_and_halt(void)
{
// Do not print or call non-IRAM functions beyond this point
esp_system_reset_modules_on_exit();
ESP_INFINITE_LOOP();
}
/********************** Panic handler functions **********************/ /********************** Panic handler functions **********************/
/* This function is called from the panic handler entry point to increment the panic entry count */ /* This function is called from the panic handler entry point to increment the panic entry count */
@@ -455,10 +463,10 @@ 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 */
esp_panic_handler_feed_wdts();
panic_print_str("CPU halted.\r\n"); panic_print_str("CPU halted.\r\n");
esp_system_reset_modules_on_exit();
disable_all_wdts(); disable_all_wdts();
ESP_INFINITE_LOOP(); esp_panic_handler_reset_modules_on_exit_and_halt();
#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 */
} }

View File

@@ -83,6 +83,10 @@ void test_coredump_summary(void);
void test_panic_print_backtrace(void); void test_panic_print_backtrace(void);
#if CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT
void test_panic_halt(void);
#endif /* CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -126,6 +126,9 @@ void app_main(void)
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_stuck0);
HANDLE_TEST(test_name, test_panic_handler_crash0); HANDLE_TEST(test_name, test_panic_handler_crash0);
#if CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT
HANDLE_TEST(test_name, test_panic_halt);
#endif /* CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT */
#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

View File

@@ -445,3 +445,12 @@ void test_panic_print_backtrace(void)
} }
#endif #endif
#if CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT
void test_panic_halt(void)
{
printf("Triggering panic. Device should print 'CPU halted.' and stop.\n");
fflush(stdout);
assert(0);
}
#endif /* CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT */

View File

@@ -2,12 +2,9 @@
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
import itertools import itertools
import re import re
from collections.abc import Sequence
from re import Pattern
from typing import Any from typing import Any
from typing import List
from typing import Optional
from typing import Pattern
from typing import Sequence
from typing import Union
import pexpect import pexpect
import pytest import pytest
@@ -48,6 +45,7 @@ CONFIGS = list(
CONFIG_PANIC = list(itertools.chain(itertools.product(['panic'], ['supported_targets']))) CONFIG_PANIC = list(itertools.chain(itertools.product(['panic'], ['supported_targets'])))
CONFIG_PANIC_DUAL_CORE = list(itertools.chain(itertools.product(['panic'], TARGETS_DUAL_CORE))) CONFIG_PANIC_DUAL_CORE = list(itertools.chain(itertools.product(['panic'], TARGETS_DUAL_CORE)))
CONFIG_PANIC_HALT = list(itertools.chain(itertools.product(['panic_halt'], TARGETS_ALL)))
CONFIGS_BACKTRACE = list( CONFIGS_BACKTRACE = list(
itertools.chain( itertools.chain(
@@ -105,11 +103,11 @@ CONFIG_COREDUMP_SUMMARY_FLASH_ENCRYPTED = list(
PANIC_ABORT_PREFIX = 'Panic reason: ' PANIC_ABORT_PREFIX = 'Panic reason: '
def get_default_backtrace(config: str) -> List[str]: def get_default_backtrace(config: str) -> list[str]:
return [config, 'app_main', 'main_task', 'vPortTaskWrapper'] return [config, 'app_main', 'main_task', 'vPortTaskWrapper']
def expect_coredump_flash_write_logs(dut: PanicTestDut, config: str, check_cpu_reset: Optional[bool] = True) -> None: def expect_coredump_flash_write_logs(dut: PanicTestDut, config: str, check_cpu_reset: bool | None = True) -> None:
dut.expect_exact('Save core dump to flash...') dut.expect_exact('Save core dump to flash...')
if 'extram_stack' in config: if 'extram_stack' in config:
dut.expect_exact('Backing up stack @') dut.expect_exact('Backing up stack @')
@@ -120,7 +118,7 @@ def expect_coredump_flash_write_logs(dut: PanicTestDut, config: str, check_cpu_r
dut.expect_cpu_reset() dut.expect_cpu_reset()
def expect_coredump_uart_write_logs(dut: PanicTestDut, check_cpu_reset: Optional[bool] = True) -> Any: def expect_coredump_uart_write_logs(dut: PanicTestDut, check_cpu_reset: bool | None = True) -> Any:
# ================= CORE DUMP START ================= # ================= CORE DUMP START =================
# B8AAAMAEgAGAAAAXAEAAAAAAABkAAAA # B8AAAMAEgAGAAAAXAEAAAAAAABkAAAA
# ... # ...
@@ -144,9 +142,9 @@ def expect_coredump_uart_write_logs(dut: PanicTestDut, check_cpu_reset: Optional
def common_test( def common_test(
dut: PanicTestDut, dut: PanicTestDut,
config: str, config: str,
expected_backtrace: Optional[List[str]] = None, expected_backtrace: list[str] | None = None,
check_cpu_reset: Optional[bool] = True, check_cpu_reset: bool | None = True,
expected_coredump: Optional[Sequence[Union[str, Pattern[Any]]]] = None, expected_coredump: Sequence[str | Pattern[Any]] | None = None,
) -> None: ) -> None:
if 'gdbstub' in config: if 'gdbstub' in config:
if 'coredump' in config: if 'coredump' in config:
@@ -1245,3 +1243,11 @@ def test_panic_print_backtrace(dut: PanicTestDut, config: str, test_func_name: s
coredump_pattern = re.compile(PANIC_ABORT_PREFIX + regex_pattern.decode('utf-8')) coredump_pattern = re.compile(PANIC_ABORT_PREFIX + regex_pattern.decode('utf-8'))
common_test(dut, config, expected_backtrace=None, expected_coredump=[coredump_pattern]) common_test(dut, config, expected_backtrace=None, expected_coredump=[coredump_pattern])
@pytest.mark.generic
@idf_parametrize('config, target', CONFIG_PANIC_HALT, indirect=['config', 'target'])
def test_panic_halt(dut: PanicTestDut) -> None:
dut.run_test_func('test_panic_halt')
dut.expect_exact('CPU halted.', timeout=30)
dut.expect_none(dut.REBOOT, timeout=3)

View File

@@ -0,0 +1,5 @@
# Panic halt CI config
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=n
CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT=n
CONFIG_ESP_SYSTEM_PANIC_GDBSTUB=n