From 9a201cdd1ebd4a49f26d6da8f93bfb74a57641f7 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Wed, 26 Aug 2026 15:04:50 +0530 Subject: [PATCH 1/3] refactor(esp_system): factor the memprot panic report out of panic_arch.c Move print_memprot_err_details() and its state out of the RISC-V panic_arch.c into port/panic_memprot.c behind panic_memprot_fill_info(), so the report can be shared with the Xtensa PMS targets. No functional change. --- .../include/esp_private/panic_internal.h | 4 + components/esp_system/port/CMakeLists.txt | 4 + .../esp_system/port/arch/riscv/panic_arch.c | 78 +---------------- components/esp_system/port/panic_memprot.c | 87 +++++++++++++++++++ 4 files changed, 96 insertions(+), 77 deletions(-) create mode 100644 components/esp_system/port/panic_memprot.c diff --git a/components/esp_system/include/esp_private/panic_internal.h b/components/esp_system/include/esp_private/panic_internal.h index 170ee3fd65d..6fd164ae817 100644 --- a/components/esp_system/include/esp_private/panic_internal.h +++ b/components/esp_system/include/esp_private/panic_internal.h @@ -90,6 +90,10 @@ void panic_prepare_frame_from_ctx(void* frame); void panic_clear_active_interrupts(const void* frame); +#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS && !CONFIG_IDF_TARGET_ESP32S2 +bool panic_memprot_fill_info(panic_info_t *info); +#endif + /** * @brief Disable all watchdog timers * diff --git a/components/esp_system/port/CMakeLists.txt b/components/esp_system/port/CMakeLists.txt index 0aa682d0561..cadbf920c26 100644 --- a/components/esp_system/port/CMakeLists.txt +++ b/components/esp_system/port/CMakeLists.txt @@ -45,6 +45,10 @@ elseif(CONFIG_IDF_TARGET_ARCH_RISCV) "arch/riscv/debug_stubs.c") endif() +if(CONFIG_ESP_SYSTEM_MEMPROT AND CONFIG_ESP_SYSTEM_MEMPROT_PMS AND NOT CONFIG_IDF_TARGET_ESP32S2) + list(APPEND srcs "panic_memprot.c") +endif() + add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/arch/riscv/panic_arch.c b/components/esp_system/port/arch/riscv/panic_arch.c index 0d38d14212a..a64fc742bf2 100644 --- a/components/esp_system/port/arch/riscv/panic_arch.c +++ b/components/esp_system/port/arch/riscv/panic_arch.c @@ -13,11 +13,6 @@ #include "riscv/rv_utils.h" #include "esp_private/cache_err_int.h" -#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS -#include "esp_private/esp_memprot_internal.h" -#include "esp_memprot.h" -#endif - #if CONFIG_ESP_SYSTEM_USE_EH_FRAME #include "esp_private/eh_frame_parser.h" #include "esp_private/cache_utils.h" @@ -83,75 +78,6 @@ static inline void print_assist_debug_details(const void *frame) } #endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD -/** - * Function called when a memory protection error occurs (PMS). It prints details such as the - * explanation of why the panic occurred. - */ -#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS - -static esp_memp_intr_source_t s_memp_intr = {MEMPROT_TYPE_INVALID, -1}; - -#define PRINT_MEMPROT_ERROR(err) \ - do { \ - panic_print_str("N/A (error "); \ - panic_print_str(esp_err_to_name(err)); \ - panic_print_str(")"); \ - } while(0) - -static inline void print_memprot_err_details(const void *frame __attribute__((unused))) -{ - if (s_memp_intr.mem_type == MEMPROT_TYPE_INVALID && s_memp_intr.core == -1) { - panic_print_str(" - no details available -\r\n"); - return; - } - - //common memprot fault info - panic_print_str(" memory type: "); - panic_print_str(esp_mprot_mem_type_to_str(s_memp_intr.mem_type)); - - panic_print_str("\r\n faulting address: "); - void *faulting_addr; - esp_err_t res = esp_mprot_get_violate_addr(s_memp_intr.mem_type, &faulting_addr, s_memp_intr.core); - if (res == ESP_OK) { - panic_print_str("0x"); - panic_print_hex((int)faulting_addr); - } else { - PRINT_MEMPROT_ERROR(res); - } - - panic_print_str("\r\n world: "); - esp_mprot_pms_world_t world; - res = esp_mprot_get_violate_world(s_memp_intr.mem_type, &world, s_memp_intr.core); - if (res == ESP_OK) { - panic_print_str(esp_mprot_pms_world_to_str(world)); - } else { - PRINT_MEMPROT_ERROR(res); - } - - panic_print_str("\r\n operation type: "); - uint32_t operation; - res = esp_mprot_get_violate_operation(s_memp_intr.mem_type, &operation, s_memp_intr.core); - if (res == ESP_OK) { - panic_print_str(esp_mprot_oper_type_to_str(operation)); - } else { - PRINT_MEMPROT_ERROR(res); - } - - if (esp_mprot_has_byte_enables(s_memp_intr.mem_type)) { - panic_print_str("\r\n byte-enables: "); - uint32_t byte_enables; - res = esp_mprot_get_violate_byte_enables(s_memp_intr.mem_type, &byte_enables, s_memp_intr.core); - if (res == ESP_OK) { - panic_print_hex(byte_enables); - } else { - PRINT_MEMPROT_ERROR(res); - } - } - - panic_print_str("\r\n"); -} -#endif //CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS - static void panic_print_register_array(const char* names[], const uint32_t* regs, int size) { const int regs_per_line = 4; @@ -257,9 +183,7 @@ void panic_soc_fill_info(void *f, panic_info_t *info) #endif #if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS else if (frame->mcause == ETS_MEMPROT_ERR_INUM) { - info->reason = "Memory protection fault"; - info->details = print_memprot_err_details; - info->core = esp_mprot_get_active_intr(&s_memp_intr) == ESP_OK ? s_memp_intr.core : -1; + panic_memprot_fill_info(info); } #endif //CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS } diff --git a/components/esp_system/port/panic_memprot.c b/components/esp_system/port/panic_memprot.c new file mode 100644 index 00000000000..be321ad6900 --- /dev/null +++ b/components/esp_system/port/panic_memprot.c @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" + +#include "esp_err.h" +#include "esp_private/panic_internal.h" +#include "esp_private/esp_memprot_internal.h" +#include "esp_memprot.h" + +static esp_memp_intr_source_t s_memp_intr = {MEMPROT_TYPE_INVALID, -1}; + +#define PRINT_MEMPROT_ERROR(err) \ + do { \ + panic_print_str("N/A (error "); \ + panic_print_str(esp_err_to_name(err)); \ + panic_print_str(")"); \ + } while(0) + +/** + * Function called when a memory protection error occurs (PMS). It prints details such as the + * explanation of why the panic occurred. + */ +static void print_memprot_err_details(const void *frame __attribute__((unused))) +{ + if (s_memp_intr.mem_type == MEMPROT_TYPE_INVALID && s_memp_intr.core == -1) { + panic_print_str(" - no details available -\r\n"); + return; + } + + //common memprot fault info + panic_print_str(" memory type: "); + panic_print_str(esp_mprot_mem_type_to_str(s_memp_intr.mem_type)); + + panic_print_str("\r\n faulting address: "); + void *faulting_addr; + esp_err_t res = esp_mprot_get_violate_addr(s_memp_intr.mem_type, &faulting_addr, s_memp_intr.core); + if (res == ESP_OK) { + panic_print_str("0x"); + panic_print_hex((int)faulting_addr); + } else { + PRINT_MEMPROT_ERROR(res); + } + + panic_print_str("\r\n world: "); + esp_mprot_pms_world_t world; + res = esp_mprot_get_violate_world(s_memp_intr.mem_type, &world, s_memp_intr.core); + if (res == ESP_OK) { + panic_print_str(esp_mprot_pms_world_to_str(world)); + } else { + PRINT_MEMPROT_ERROR(res); + } + + panic_print_str("\r\n operation type: "); + uint32_t operation; + res = esp_mprot_get_violate_operation(s_memp_intr.mem_type, &operation, s_memp_intr.core); + if (res == ESP_OK) { + panic_print_str(esp_mprot_oper_type_to_str(operation)); + } else { + PRINT_MEMPROT_ERROR(res); + } + + if (esp_mprot_has_byte_enables(s_memp_intr.mem_type)) { + panic_print_str("\r\n byte-enables: "); + uint32_t byte_enables; + res = esp_mprot_get_violate_byte_enables(s_memp_intr.mem_type, &byte_enables, s_memp_intr.core); + if (res == ESP_OK) { + panic_print_hex(byte_enables); + } else { + PRINT_MEMPROT_ERROR(res); + } + } + + panic_print_str("\r\n"); +} + +bool panic_memprot_fill_info(panic_info_t *info) +{ + info->reason = "Memory protection fault"; + info->details = print_memprot_err_details; + info->core = esp_mprot_get_active_intr(&s_memp_intr) == ESP_OK ? s_memp_intr.core : -1; + + return true; +} From 73dd203204a9fafbd823ab0530ea3dfe93cba4d8 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Wed, 26 Aug 2026 15:05:02 +0530 Subject: [PATCH 2/3] fix(esp_system): report ESP32-S3 PMS violations as memory protection faults On Xtensa the PMS violation shares ETS_MEMACCESS_ERR_INUM with the cache error and arrives as PANIC_RSN_CACHEERR. ESP32-S2 tells the two apart, ESP32-S3 never did (//MV note in dd938eb95), so PMS faults were reported as "Cache error". panic_memprot_fill_info() now claims the panic only when esp_mprot_get_active_intr() reports a pending violation, and the ESP32-S3 cache error path consults it, falling back to the cache error report as before. RISC-V has a dedicated interrupt, so its reporting stays unconditional. ESP32-S2 and ESP32 are untouched. --- .../esp_system/port/arch/xtensa/panic_arch.c | 19 ++++++++++--------- components/esp_system/port/panic_memprot.c | 12 +++++++++++- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/components/esp_system/port/arch/xtensa/panic_arch.c b/components/esp_system/port/arch/xtensa/panic_arch.c index 078e1609a2d..b09a744cfa6 100644 --- a/components/esp_system/port/arch/xtensa/panic_arch.c +++ b/components/esp_system/port/arch/xtensa/panic_arch.c @@ -20,12 +20,8 @@ #if !CONFIG_IDF_TARGET_ESP32 #include "soc/rtc_cntl_reg.h" -#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS -#ifdef CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS && CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/memprot.h" -#else -#include "esp_memprot.h" -#endif #endif #endif // CONFIG_IDF_TARGET_ESP32 @@ -302,15 +298,20 @@ void panic_soc_fill_info(void *f, panic_info_t *info) info->exception = PANIC_EXCEPTION_DEBUG; } - //MV note: ESP32S3 PMS handling? if (frame->exccause == PANIC_RSN_CACHEERR) { -#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS && CONFIG_IDF_TARGET_ESP32S2 + bool memprot_fault = false; +#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMS +#if CONFIG_IDF_TARGET_ESP32S2 if (esp_memprot_is_intr_ena_any()) { info->details = print_memprot_err_details; info->reason = "Memory protection fault"; - } else + memprot_fault = true; + } +#else + memprot_fault = panic_memprot_fill_info(info); #endif - { +#endif + if (!memprot_fault) { info->details = print_cache_err_details; } } diff --git a/components/esp_system/port/panic_memprot.c b/components/esp_system/port/panic_memprot.c index be321ad6900..43f0919f37b 100644 --- a/components/esp_system/port/panic_memprot.c +++ b/components/esp_system/port/panic_memprot.c @@ -79,9 +79,19 @@ static void print_memprot_err_details(const void *frame __attribute__((unused))) bool panic_memprot_fill_info(panic_info_t *info) { + const bool violation_pending = esp_mprot_get_active_intr(&s_memp_intr) == ESP_OK && + s_memp_intr.mem_type != MEMPROT_TYPE_NONE && + s_memp_intr.mem_type != MEMPROT_TYPE_INVALID; + +#if CONFIG_IDF_TARGET_ARCH_XTENSA + if (!violation_pending) { + return false; + } +#endif + info->reason = "Memory protection fault"; info->details = print_memprot_err_details; - info->core = esp_mprot_get_active_intr(&s_memp_intr) == ESP_OK ? s_memp_intr.core : -1; + info->core = violation_pending ? s_memp_intr.core : -1; return true; } From 8daab867b759cc222a9d4c67d064eaf1b87c6ac8 Mon Sep 17 00:00:00 2001 From: "harshal.patil" Date: Wed, 26 Aug 2026 14:46:42 +0530 Subject: [PATCH 3/3] test(panic): enable the memprot panic tests for ESP32-S3 sdkconfig.ci.memprot_esp32s3 was built but listed in no CONFIGS_MEMPROT_*, so the S3 PMS panic path was never exercised. expect_gme() takes an optional core, for panics with no attributable core. --- .../system/panic/panic_base/pytest_panic.py | 63 ++++++++++++++++--- .../panic_base/test_panic_util/panic_dut.py | 13 +++- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/tools/test_apps/system/panic/panic_base/pytest_panic.py b/tools/test_apps/system/panic/panic_base/pytest_panic.py index 470807134ea..f6508d3b216 100644 --- a/tools/test_apps/system/panic/panic_base/pytest_panic.py +++ b/tools/test_apps/system/panic/panic_base/pytest_panic.py @@ -35,11 +35,13 @@ def configs_for_app(app_path: str, configs: Sequence[str]) -> list[tuple[str, st return [(app_path, config) for config in configs] -def configs_with_esp32s2_xfail( - configs: Sequence[tuple[str, str] | tuple[str, str, Any]], reason: str +def configs_with_xfail( + configs: Sequence[tuple[str, str] | tuple[str, str, Any]], + reason: str, + targets: Sequence[str] = ('esp32s2',), ) -> list[tuple[str, str] | tuple[str, str, Any]]: return [ - (entry[0], entry[1], pytest.mark.xfail(reason=reason, run=False)) if entry[1] == 'esp32s2' else entry + (entry[0], entry[1], pytest.mark.xfail(reason=reason, run=False)) if entry[1] in targets else entry for entry in configs ] @@ -618,7 +620,8 @@ def test_panic_handler_crash1(dut: PanicTestDut, config: str, test_func_name: st ######################### # Memprot-related tests are supported only on targets with PMS/PMA peripheral; -# currently ESP32-S2, ESP32-C3, ESP32-C2, ESP32-H2, ESP32-H21, ESP32-C6, ESP32-P4, ESP32-C5 and ESP32-C61 are supported +# currently ESP32-S2, ESP32-S3, ESP32-C3, ESP32-C2, ESP32-H2, ESP32-H21, ESP32-C6, ESP32-P4, +# ESP32-C5, ESP32-C61, ESP32-H4 are supported # ESP32-P4 rev < 3.0 runs on a dedicated rev 1.x runner (its binary is built for # and only boots on rev < 3.0 silicon), so its configs carry the esp32p4_rev1 marker. P4_REV_LESS_THAN_V3_MARKER = pytest.mark.esp32p4_rev1 @@ -627,6 +630,7 @@ CONFIGS_MEMPROT_IDRAM = list( zip( [ 'memprot_esp32s2', + 'memprot_esp32s3', 'memprot_esp32c3', 'memprot_esp32c2', 'memprot_esp32c5', @@ -639,6 +643,7 @@ CONFIGS_MEMPROT_IDRAM = list( ], [ 'esp32s2', + 'esp32s3', 'esp32c3', 'esp32c2', 'esp32c5', @@ -662,6 +667,7 @@ CONFIGS_MEMPROT_RTC_FAST_MEM = list( zip( [ 'memprot_esp32s2', + 'memprot_esp32s3', 'memprot_esp32c3', 'memprot_esp32c5', 'memprot_esp32c6', @@ -670,7 +676,7 @@ CONFIGS_MEMPROT_RTC_FAST_MEM = list( 'memprot_esp32h21', 'memprot_esp32s31', ], - ['esp32s2', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32h21', 'esp32s31'], + ['esp32s2', 'esp32s3', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32h21', 'esp32s31'], ) ) + [ ('memprot_esp32p4_rev_less_than_v3', 'esp32p4', P4_REV_LESS_THAN_V3_MARKER), @@ -792,6 +798,13 @@ def iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None: dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)') dut.expect_reg_dump(0) dut.expect_backtrace() + elif dut.target == 'esp32s3': + dut.expect_gme('Memory protection fault') + dut.expect(r' memory type: (\S+)') + dut.expect(r' faulting address: [0-9xa-f]+') + dut.expect(r' operation type: (\S+)') + dut.expect_reg_dump(0) + dut.expect_backtrace() elif dut.target == 'esp32c3': dut.expect_exact(r'Test error: Test function has returned') else: @@ -824,6 +837,13 @@ def iram_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None: dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)') dut.expect_reg_dump(0) dut.expect_backtrace() + elif dut.target == 'esp32s3': + dut.expect_gme('Memory protection fault') + dut.expect(r' memory type: (\S+)') + dut.expect(r' faulting address: [0-9xa-f]+') + dut.expect(r' operation type: (\S+)') + dut.expect_reg_dump(0) + dut.expect_backtrace() elif dut.target == 'esp32c3': dut.expect_gme('Memory protection fault') dut.expect(r' memory type: (\S+)') @@ -915,10 +935,10 @@ def iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None: @pytest.mark.generic @pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners') -# TODO: IDF-6820: ESP32-S2 -> Fix incorrect panic reason: Unhandled debug exception +# TODO: IDF-6820: ESP32-S2 / ESP32-S3 -> Fix incorrect panic reason: Unhandled debug exception @idf_parametrize( 'config,target,markers', - configs_with_esp32s2_xfail(CONFIGS_MEMPROT_IDRAM, 'Incorrect panic reason may be observed'), + configs_with_xfail(CONFIGS_MEMPROT_IDRAM, 'Incorrect panic reason may be observed', targets=('esp32s2', 'esp32s3')), indirect=['config', 'target'], ) def test_iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None: @@ -940,6 +960,11 @@ def dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: dut.expect(r'Unknown operation at address [0-9xa-f]+ not permitted \((\S+)\)') dut.expect_reg_dump(0) dut.expect_backtrace(corrupted=True) + elif dut.target == 'esp32s3': + dut.expect_gme('Cache error', core=None) + dut.expect_exact('MMU entry fault error') + dut.expect_reg_dump(0) + dut.expect_backtrace() else: dut.expect_gme('Instruction access fault') dut.expect_reg_dump(0) @@ -953,7 +978,7 @@ def dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: # TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs @idf_parametrize( 'config,target,markers', - configs_with_esp32s2_xfail(CONFIGS_MEMPROT_IDRAM, 'Multiple panic reasons for the same test may surface'), + configs_with_xfail(CONFIGS_MEMPROT_IDRAM, 'Multiple panic reasons for the same test may surface'), indirect=['config', 'target'], ) def test_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: @@ -974,6 +999,11 @@ def dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: dut.expect_gme('InstructionFetchError') dut.expect_reg_dump(0) dut.expect_backtrace(corrupted=True) + elif dut.target == 'esp32s3': + dut.expect_gme('Cache error', core=None) + dut.expect_exact('MMU entry fault error') + dut.expect_reg_dump(0) + dut.expect_backtrace(corrupted=True) else: dut.expect_gme('Instruction access fault') dut.expect_reg_dump(0) @@ -987,7 +1017,7 @@ def dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: # TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs @idf_parametrize( 'config,target,markers', - configs_with_esp32s2_xfail(CONFIGS_MEMPROT_IDRAM, 'Multiple panic reasons for the same test may surface'), + configs_with_xfail(CONFIGS_MEMPROT_IDRAM, 'Multiple panic reasons for the same test may surface'), indirect=['config', 'target'], ) def test_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: @@ -1024,6 +1054,12 @@ def test_rtc_fast_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) dut.expect(r'Read operation at address [0-9xa-f]+ not permitted \((\S+)\)') dut.expect_reg_dump(0) dut.expect_backtrace() + elif dut.target == 'esp32s3': + dut.expect(r' memory type: (\S+)') + dut.expect(r' faulting address: [0-9xa-f]+') + dut.expect(r' operation type: (\S+)') + dut.expect_reg_dump(0) + dut.expect_backtrace() elif dut.target == 'esp32c3': dut.expect(r' memory type: (\S+)') dut.expect(r' faulting address: [0-9xa-f]+') @@ -1039,7 +1075,7 @@ def test_rtc_fast_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) # TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs @idf_parametrize( 'config,target,markers', - configs_with_esp32s2_xfail(CONFIGS_MEMPROT_RTC_FAST_MEM, 'Multiple panic reasons for the same test may surface'), + configs_with_xfail(CONFIGS_MEMPROT_RTC_FAST_MEM, 'Multiple panic reasons for the same test may surface'), indirect=['config', 'target'], ) def test_rtc_fast_reg3_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: @@ -1050,6 +1086,13 @@ def test_rtc_fast_reg3_execute_violation(dut: PanicTestDut, test_func_name: str) dut.expect(r'Unknown operation at address [0-9xa-f]+ not permitted \((\S+)\)') dut.expect_reg_dump(0) dut.expect_backtrace() + elif dut.target == 'esp32s3': + dut.expect_gme('Memory protection fault') + dut.expect(r' memory type: (\S+)') + dut.expect(r' faulting address: [0-9xa-f]+') + dut.expect(r' operation type: (\S+)') + dut.expect_reg_dump(0) + dut.expect_backtrace() elif dut.target == 'esp32c3': dut.expect_gme('Memory protection fault') dut.expect(r' memory type: (\S+)') diff --git a/tools/test_apps/system/panic/panic_base/test_panic_util/panic_dut.py b/tools/test_apps/system/panic/panic_base/test_panic_util/panic_dut.py index fac02e09fe6..a358cf79933 100644 --- a/tools/test_apps/system/panic/panic_base/test_panic_util/panic_dut.py +++ b/tools/test_apps/system/panic/panic_base/test_panic_util/panic_dut.py @@ -104,9 +104,16 @@ class PanicTestDut(IdfDut): result = self.expect(pattern, return_what_before_match=True).decode('utf-8') return result.strip() - def expect_gme(self, reason: str) -> None: - """Expect method for Guru Meditation Errors""" - self.expect_exact(f"Guru Meditation Error: Core 0 panic'ed ({reason})") + def expect_gme(self, reason: str, core: int | None = 0) -> None: + """Expect method for Guru Meditation Errors + + Pass core=None to accept any core id, including the -1 reported for + faults which cannot be attributed to a single core. + """ + if core is None: + self.expect(rf"Guru Meditation Error: Core\s+\S+ panic'ed \({re.escape(reason)}\)") + else: + self.expect_exact(f"Guru Meditation Error: Core {core} panic'ed ({reason})") def expect_reg_dump(self, core: int | None = None) -> None: if core is None: