From 1b59698bde6237c4228dad317dac7eada3e56036 Mon Sep 17 00:00:00 2001 From: Marco Casaroli Date: Tue, 11 Aug 2026 20:09:28 +0200 Subject: [PATCH] xtensa/esp32s3: Report an access through an invalid MMU entry. The PMS grants and refuses physical addresses, so it never sees an access that no MMU entry translates. The cache answered such an access with zeros and raised nothing, and the task carried on with a value it never should have had. Enable EXTMEM_MMU_ENTRY_FAULT and route the Cache Invalid Access interrupt to the handler that already serves the PMS monitors. An unprivileged task that makes the access is terminated with SIGSEGV; a privileged one still panics. The latch is level triggered, so it is cleared with the others. Read the cause before the clear, so the log tells the two apart: a PMS violation is a refused translation, an MMU entry fault is an access that was never translated. Give the kernel_oct configuration the addresses that examples/sandbox needs to name its targets. Assisted-by: Claude Opus 5 (1M context) Signed-off-by: Marco Casaroli --- arch/xtensa/src/esp32s3/esp32s3_isolation.c | 40 +++++++++++++++++-- arch/xtensa/src/esp32s3/esp32s3_user.c | 9 +++-- .../configs/kernel_oct/defconfig | 4 ++ 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/arch/xtensa/src/esp32s3/esp32s3_isolation.c b/arch/xtensa/src/esp32s3/esp32s3_isolation.c index abd421de6f0..e5e99534277 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_isolation.c +++ b/arch/xtensa/src/esp32s3/esp32s3_isolation.c @@ -146,6 +146,16 @@ static void IRAM_ATTR pms_clear_violations(void) modifyreg32(EXTMEM_CORE0_ACS_CACHE_INT_CLR_REG, EXTMEM_CORE0_IBUS_REJECT_INT_CLR_M | EXTMEM_CORE0_DBUS_REJECT_INT_CLR_M, 0); + + /* The invalid MMU entry monitor. An access that no entry translates never + * reaches the PMS, which checks physical addresses, so without this the + * cache answers it with zeros and nothing is reported. + */ + + modifyreg32(EXTMEM_CACHE_ILG_INT_CLR_REG, 0, + EXTMEM_MMU_ENTRY_FAULT_INT_CLR_M); + modifyreg32(EXTMEM_CACHE_ILG_INT_CLR_REG, + EXTMEM_MMU_ENTRY_FAULT_INT_CLR_M, 0); } #endif @@ -171,6 +181,16 @@ static int IRAM_ATTR pms_violation_isr(int cpuint, void *context, void *arg) { #ifdef CONFIG_ESP32S3_USERFAULT_ABORT uint32_t *regs = (uint32_t *)context; + const char *cause; + + /* Read why before acknowledging, because the clear below drops the latch. + * The two causes are answered the same way and are worth telling apart in + * the log: a PMS violation is a refused translation, an MMU entry fault + * is an access that was never translated at all. + */ + + cause = (getreg32(EXTMEM_CACHE_ILG_INT_ST_REG) & + EXTMEM_MMU_ENTRY_FAULT_ST_M) != 0 ? "MMU entry" : "PMS"; /* Acknowledge and re-arm the monitors first so the level-triggered * interrupt does not immediately re-fire while we handle it. @@ -190,8 +210,8 @@ static int IRAM_ATTR pms_violation_isr(int cpuint, void *context, void *arg) struct tcb_s *tcb = this_task(); siginfo_t info; - _alert("SIGSEGV (PMS) task %s: PC=%08x\n", - get_task_name(tcb), (unsigned)regs[REG_PC]); + _alert("SIGSEGV (%s) task %s: PC=%08x\n", + cause, get_task_name(tcb), (unsigned)regs[REG_PC]); info.si_signo = SIGSEGV; info.si_code = SI_USER; @@ -603,7 +623,8 @@ void esp32s3_isolation_permissions(void) * Name: esp32s3_pmsirqinitialize * * Description: - * Install the handler that reports a permission violation. + * Install the handlers that report a permission violation and an access + * that no MMU entry translates. * * Returned Value: * None. @@ -621,8 +642,21 @@ void esp32s3_pmsirqinitialize(void) VERIFY(esp_setup_irq(ESP32S3_PERIPH_CORE_0_PIF_PMS_MONITOR_VIOLATE, 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); + /* Report an access that no MMU entry translates. The PMS grants and + * refuses physical addresses, so an untranslated access is invisible to + * it: the cache returns zeros and the task carries on with a value it + * never should have had. This monitor is what turns that into a fault. + */ + + VERIFY(esp_setup_irq(ESP32S3_PERIPH_CACHE_IA, + 1, ESP_IRQ_TRIGGER_LEVEL, pms_violation_isr, NULL)); + + modifyreg32(EXTMEM_CACHE_ILG_INT_ENA_REG, 0, + EXTMEM_MMU_ENTRY_FAULT_INT_ENA_M); + up_enable_irq(ESP32S3_IRQ_CORE_0_IRAM0_PMS_MONITOR_VIOLATE); up_enable_irq(ESP32S3_IRQ_CORE_0_DRAM0_PMS_MONITOR_VIOLATE); up_enable_irq(ESP32S3_IRQ_CACHE_CORE0_ACS); up_enable_irq(ESP32S3_IRQ_CORE_0_PIF_PMS_MONITOR_VIOLATE); + up_enable_irq(ESP32S3_IRQ_CACHE_IA); } diff --git a/arch/xtensa/src/esp32s3/esp32s3_user.c b/arch/xtensa/src/esp32s3/esp32s3_user.c index 4a4183feb89..df0c8431e5e 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_user.c +++ b/arch/xtensa/src/esp32s3/esp32s3_user.c @@ -86,9 +86,12 @@ uint32_t *xtensa_user(int exccause, uint32_t *regs) * these to the dispatcher; if serviced, return the register frame so that * the RFE in the exception vector re-executes the faulting instruction. * - * Note: ESP32-S3 PMS (World Controller) memory-protection violations are - * NOT delivered as these precise causes; they raise the asynchronous - * DRAM0/IRAM0 PMS-monitor interrupt instead (handled elsewhere). + * A PMS permission violation does not arrive as one of these causes. It + * raises the asynchronous DRAM0/IRAM0 PMS monitor interrupt, which + * pms_violation_isr() in esp32s3_isolation.c serves. So does an access + * that no MMU entry translates, which the cache reports separately. Both + * are installed by esp32s3_pmsirqinitialize(), in a protected build and in + * a kernel build alike. */ if (exccause == EXCCAUSE_LOAD_PROHIBITED || diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/configs/kernel_oct/defconfig b/boards/xtensa/esp32s3/esp32s3-devkit/configs/kernel_oct/defconfig index 0e515654878..975ecb9fbf3 100644 --- a/boards/xtensa/esp32s3/esp32s3-devkit/configs/kernel_oct/defconfig +++ b/boards/xtensa/esp32s3/esp32s3-devkit/configs/kernel_oct/defconfig @@ -58,6 +58,10 @@ CONFIG_ESP32S3_SPIRAM_MODE_OCT=y CONFIG_ESP32S3_UART0=y CONFIG_ESP32S3_WCL=y CONFIG_EXAMPLES_PFFAULT=y +CONFIG_EXAMPLES_SANDBOX=y +CONFIG_EXAMPLES_SANDBOX_KERNEL_ADDR=0x3fc98000 +CONFIG_EXAMPLES_SANDBOX_PERIPH_ADDR=0x600c5000 +CONFIG_EXAMPLES_SANDBOX_UNMAPPED_ADDR=0x3d800000 CONFIG_FS_PROCFS=y CONFIG_FS_ROMFS=y CONFIG_HAVE_CXX=y