Merge branch 'fix/s3_memprot_panic_report' into 'master'

Report ESP32-S3 PMS violations as memory protection faults

See merge request espressif/esp-idf!52109
This commit is contained in:
Mahavir Jain
2026-09-02 13:41:24 +05:30
7 changed files with 179 additions and 99 deletions
@@ -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
*
@@ -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})
@@ -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
}
@@ -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;
}
}
@@ -0,0 +1,97 @@
/*
* 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)
{
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 = violation_pending ? s_memp_intr.core : -1;
return true;
}