feat: enable cpu region protection for esp32s31

This commit is contained in:
nilesh.kale
2026-06-04 14:49:01 +05:30
committed by Mahavir Jain
parent d60155a174
commit b5891edb9b
6 changed files with 371 additions and 38 deletions

View File

@@ -9,42 +9,287 @@
#include "soc/soc.h"
#include "esp_cpu.h"
#include "esp_fault.h"
#include "hal/cache_ll.h"
#include "riscv/csr.h"
#include "esp_macros.h"
#if !BOOTLOADER_BUILD && CONFIG_SPIRAM
#include "esp_private/esp_psram_extram.h"
#endif /* !BOOTLOADER_BUILD && CONFIG_SPIRAM */
#include "esp32s31/rom/rom_layout.h"
#include "pmp_layout.h"
/* TODO: [ESP32S31] IDF-15238 */
#define ALIGN_UP_TO_MMU_PAGE_SIZE(addr) (((addr) + (SOC_MMU_PAGE_SIZE) - 1) & ~((SOC_MMU_PAGE_SIZE) - 1))
#ifdef BOOTLOADER_BUILD
// Without L bit set
#define CONDITIONAL_NONE 0x0
#define CONDITIONAL_R PMP_R
#define CONDITIONAL_RX PMP_R | PMP_X
#define CONDITIONAL_RW PMP_R | PMP_W
#define CONDITIONAL_RWX PMP_R | PMP_W | PMP_X
static void esp_cpu_configure_invalid_regions(void)
{
const unsigned PMA_NONE = PMA_L | PMA_EN;
__attribute__((unused)) const unsigned PMA_RW = PMA_L | PMA_EN | PMA_R | PMA_W;
__attribute__((unused)) const unsigned PMA_RX = PMA_L | PMA_EN | PMA_R | PMA_X;
__attribute__((unused)) const unsigned PMA_RWX = PMA_L | PMA_EN | PMA_R | PMA_W | PMA_X;
// ROM uses some PMA entries, so we need to clear them before using them in ESP-IDF.
// The reset-and-set PMA macros are safe to use even though ESP32-S31 does not tolerate
// overlapping *PMP* regions: PMA configures memory attributes (not locked protection), so
// the transient pmpaddr=0 inside the macro does not raise a fault here (same as ESP32-H4).
// 0. Gap at bottom of address space
PMA_RESET_AND_ENTRY_SET_NAPOT(0, 0, SOC_CPU_SUBSYSTEM_LOW, PMA_NAPOT | PMA_NONE);
// [SOC_CPU_SUBSYSTEM_LOW .. SOC_RTC_IRAM_HIGH) is all valid (CPU subsystem, on-chip
// peripherals and the LP TCM) and is configured using PMP below, so no PMA entry is needed.
// 1. Gap between LP TCM (RTC SRAM) and HP TCM (internal SRAM)
PMA_RESET_AND_ENTRY_SET_TOR(1, SOC_RTC_IRAM_HIGH, PMA_NONE);
PMA_RESET_AND_ENTRY_SET_TOR(2, SOC_IRAM_LOW, PMA_TOR | PMA_NONE);
// 2. Gap between HP TCM (internal SRAM) and ROM-Cache
PMA_RESET_AND_ENTRY_SET_TOR(3, SOC_IRAM_HIGH, PMA_NONE);
PMA_RESET_AND_ENTRY_SET_TOR(4, SOC_IROM_MASK_LOW, PMA_TOR | PMA_NONE);
// 3. ROM has configured the ROM region to be cacheable, lock the configuration as RX.
// Configuring it here (as a valid RX region) lets the I/D-ROM PMP entries below use the
// DROM-split optimization and save a PMP entry.
PMA_RESET_AND_ENTRY_SET_TOR(5, SOC_IROM_MASK_LOW, PMA_NONE);
PMA_RESET_AND_ENTRY_SET_TOR(6, SOC_DROM_MASK_HIGH, PMA_TOR | PMA_RX);
// 4. Gap between ROM-Cache and External flash (I/D-Cache)
PMA_RESET_AND_ENTRY_SET_TOR(7, SOC_DROM_MASK_HIGH, PMA_NONE);
PMA_RESET_AND_ENTRY_SET_TOR(8, SOC_IROM_LOW, PMA_TOR | PMA_NONE);
// 5. ROM has configured the external flash MSPI region with RX permission; lock it as RX and
// make it cacheable. This is a valid region but is configured using PMA (instead of only
// PMP) because the cacheable attribute can only be set through PMA.
PMA_RESET_AND_ENTRY_SET_NAPOT(9, SOC_IROM_LOW, (SOC_IROM_HIGH - SOC_IROM_LOW), PMA_NAPOT | PMA_RX);
// 6. Gap between External flash (I/D-Cache) and External PSRAM
PMA_RESET_AND_ENTRY_SET_TOR(10, SOC_IROM_HIGH, PMA_NONE);
PMA_RESET_AND_ENTRY_SET_TOR(11, SOC_EXTRAM_LOW, PMA_TOR | PMA_NONE);
// 7. ROM has configured the external PSRAM MSPI region with RX permission; add the W attribute
// and lock it, and make it cacheable. As above, this valid region is configured using PMA
// so that it can be marked cacheable (RWX so that PSRAM data and XIP-from-PSRAM both work).
PMA_RESET_AND_ENTRY_SET_NAPOT(12, SOC_EXTRAM_LOW, (SOC_EXTRAM_HIGH - SOC_EXTRAM_LOW), PMA_NAPOT | PMA_RWX);
// 8. Non-cacheable (cache-bypass) alias of External PSRAM at +SOC_NON_CACHEABLE_OFFSET_PSRAM,
// used by GDMA to reach PSRAM-resident descriptors/buffers coherently. Marked RW at a higher
// priority (lower index) than the catch-all below so it stays a valid region.
PMA_RESET_AND_ENTRY_SET_NAPOT(13, (uint32_t)SOC_EXTRAM_LOW + (uint32_t)SOC_NON_CACHEABLE_OFFSET_PSRAM, (SOC_EXTRAM_HIGH - SOC_EXTRAM_LOW), PMA_NAPOT | PMA_RW);
// 9. End of address space (everything above External PSRAM except the non-cacheable alias above)
PMA_RESET_AND_ENTRY_SET_TOR(14, SOC_EXTRAM_HIGH, PMA_NONE);
PMA_RESET_AND_ENTRY_SET_TOR(15, UINT32_MAX, PMA_TOR | PMA_NONE);
}
#ifndef BOOTLOADER_BUILD
static void esp_cpu_configure_valid_regions(void)
{
/* There are 3 configuration scenarios for SRAM
*
* 1. Application build with CONFIG_ESP_SYSTEM_MEMPROT enabled
* - We split the SRAM into IRAM and DRAM such that IRAM region cannot be written to
* and DRAM region cannot be executed. We use the _iram_text_end marker to set the boundary.
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
*
* 2. Application build with CONFIG_ESP_SYSTEM_MEMPROT disabled
* - The IRAM-DRAM split is not enabled so we just need to ensure that access to only valid address ranges are successful
* so for that we set PMP to cover entire valid IRAM and DRAM region.
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
*
* 3. CPU is in OCD debug mode
* - The IRAM-DRAM split is not enabled so that OpenOCD can write and execute from IRAM.
* We set PMP to cover entire valid IRAM and DRAM region.
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
*/
const unsigned NONE = PMP_L;
__attribute__((unused)) const unsigned R = PMP_L | PMP_R;
__attribute__((unused)) const unsigned RW = PMP_L | PMP_R | PMP_W;
__attribute__((unused)) const unsigned RX = PMP_L | PMP_R | PMP_X;
__attribute__((unused)) const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
/* Reset every PMP entry before programming it.
*
* The bootloader no longer configures any PMP entry, so on entry to the application each PMP
* register still holds whatever the ROM left in it. PMP_ENTRY_SET only ORs configuration bits,
* so stale permission bits must be cleared first (e.g. an entry that must end up as NONE would
* otherwise keep any R/W/X bit the ROM set).
*
* ESP32-S31 does not support overlapping PMP regions, so the per-entry PMP_RESET_AND_ENTRY_SET
* macro cannot be used for TOR entries (the transient pmpaddr=0 it writes creates a fleeting
* wrapping overlap that faults on this CPU). Instead every entry is reset to a disabled state
* up front and the entries are then programmed strictly in ascending-address order, so each TOR
* base is already in place before the entry that uses it is enabled, and no overlapping
* intermediate configuration is ever visible.
*/
PMP_ENTRY_CFG_RESET(0);
PMP_ENTRY_CFG_RESET(1);
PMP_ENTRY_CFG_RESET(2);
PMP_ENTRY_CFG_RESET(3);
PMP_ENTRY_CFG_RESET(4);
PMP_ENTRY_CFG_RESET(5);
PMP_ENTRY_CFG_RESET(6);
PMP_ENTRY_CFG_RESET(7);
PMP_ENTRY_CFG_RESET(8);
PMP_ENTRY_CFG_RESET(9);
PMP_ENTRY_CFG_RESET(10);
PMP_ENTRY_CFG_RESET(11);
PMP_ENTRY_CFG_RESET(12);
PMP_ENTRY_CFG_RESET(13);
PMP_ENTRY_CFG_RESET(14);
PMP_ENTRY_CFG_RESET(15);
// 1. CPU Subsystem region - contains debug mode code and interrupt config registers
const uint32_t pmpaddr_cpu_subsystem = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
PMP_ENTRY_SET(PMP_ENTRY_CPU_SUBSYSTEM, pmpaddr_cpu_subsystem, PMP_NAPOT | RWX);
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
// 2. I/D-ROM (ROM-Cache)
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
const uint32_t drom_start = (uint32_t) (ets_rom_layout_p->drom_start);
if ((drom_start & (SOC_CPU_PMP_REGION_GRANULARITY - 1)) == 0) {
// We can skip configuring the PMP entry for the [SOC_IROM_MASK_LOW - drom_start]
// region as RX, as we already have configured a PMA entry with RX permissions for the
// [SOC_IROM_MASK_LOW - SOC_DROM_MASK_HIGH] region that also makes it cacheable. Thus, we
// save on one PMP entry.
PMP_ENTRY_SET(PMP_ENTRY_ROM_LOW, drom_start, NONE);
PMP_ENTRY_SET(PMP_ENTRY_ROM_HIGH, SOC_DROM_MASK_HIGH, PMP_TOR | R);
} else
#endif
{
PMP_ENTRY_SET(PMP_ENTRY_ROM_LOW, SOC_IROM_MASK_LOW, NONE);
PMP_ENTRY_SET(PMP_ENTRY_ROM_HIGH, SOC_IROM_MASK_HIGH, PMP_TOR | RX);
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region");
}
// 3. IRAM and DRAM (HP TCM)
if (esp_cpu_dbgr_is_attached()) {
// Anti-FI check that cpu is really in ocd mode
ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached());
PMP_ENTRY_SET(3, SOC_IRAM_LOW, NONE);
PMP_ENTRY_SET(4, SOC_IRAM_HIGH, PMP_TOR | RWX);
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
} else {
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
extern int _iram_text_end;
PMP_ENTRY_SET(3, SOC_IRAM_LOW, NONE);
PMP_ENTRY_SET(4, (int)&_iram_text_end, PMP_TOR | RX);
PMP_ENTRY_SET(5, SOC_DRAM_HIGH, PMP_TOR | RW);
#else
// With L bit set
#define CONDITIONAL_NONE NONE
#define CONDITIONAL_R R
#define CONDITIONAL_RX RX
#define CONDITIONAL_RW RW
#define CONDITIONAL_RWX RWX
PMP_ENTRY_SET(3, SOC_IRAM_LOW, NONE);
PMP_ENTRY_SET(4, SOC_IRAM_HIGH, PMP_TOR | RWX);
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
#endif
}
// 4. I_Cache / D_Cache (external flash)
// The marker-based split uses _instruction_reserved_end / _rodata_reserved_end, which lie in
// the flash aperture only when .text/.rodata are flash-resident. Under XIP-from-PSRAM they
// move into PSRAM, so this higher-priority flash entry would shadow the PSRAM RWX entry
// (section 5) and make the heap-reused page-alignment gaps read-only. So split only when
// flash-resident; otherwise map the flash aperture as a single RX window and let section 5
// govern the XIP code/rodata/gaps.
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !CONFIG_SPIRAM_FETCH_INSTRUCTIONS && !CONFIG_SPIRAM_RODATA
extern int _instruction_reserved_end;
extern int _rodata_reserved_end;
const uint32_t page_aligned_irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_instruction_reserved_end));
const uint32_t page_aligned_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end));
PMP_ENTRY_SET(6, SOC_IROM_LOW, NONE);
PMP_ENTRY_SET(7, page_aligned_irom_resv_end, PMP_TOR | RX);
PMP_ENTRY_SET(8, page_aligned_drom_resv_end, PMP_TOR | R);
#else
const uint32_t pmpaddr_flash = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
PMP_ENTRY_SET(6, pmpaddr_flash, PMP_NAPOT | RX);
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
#endif
#define ALIGN_UP_TO_MMU_PAGE_SIZE(addr) ESP_ALIGN_UP(addr, SOC_MMU_PAGE_SIZE)
#define ALIGN_DOWN_TO_MMU_PAGE_SIZE(addr) ESP_ALIGN_DOWN(addr, SOC_MMU_PAGE_SIZE)
// 5. I_EXTRAM / D_EXTRAM (external PSRAM). The PMA entry configured above already makes this
// region cacheable; the PSRAM cache-bypass alias is kept valid by PMA (an address unmatched
// by PMP is allowed by PMP in M-mode, so it needs no extra PMP entry).
#if CONFIG_SPIRAM
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && (CONFIG_SPIRAM_FETCH_INSTRUCTIONS || CONFIG_SPIRAM_RODATA)
/* XIP-from-PSRAM: .text is executed directly out of PSRAM, so enforce W^X instead of a single
* RWX window. Map [EXTRAM_LOW, _instruction_reserved_end) as RX (code) and the remainder
* (rodata, the page-alignment gaps and the reclaimed heap) as RW - i.e. non-executable - so an
* execute access into the rodata / alignment-gap region faults (Instruction access fault), as
* the memory-protection tests expect. A full P4-style per-section split (separate R rodata and
* heap-only entries) does not fit the 16-entry PMP budget once the LP split takes 4 entries, but
* this two-region split already enforces W^X. It uses entries 7-8 (left free by the flash
* aperture's single-entry mapping under XIP) plus entry 9, programmed in ascending order. */
extern int _instruction_reserved_end;
PMP_ENTRY_SET(7, SOC_EXTRAM_LOW, NONE);
PMP_ENTRY_SET(8, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
PMP_ENTRY_SET(9, SOC_EXTRAM_HIGH, PMP_TOR | RW);
_Static_assert(SOC_EXTRAM_LOW < SOC_EXTRAM_HIGH, "Invalid I/D_EXTRAM region");
#else
/* PSRAM used as data only (no XIP): a single RWX NAPOT window. */
const uint32_t pmpaddr_extram = PMPADDR_NAPOT(SOC_EXTRAM_LOW, SOC_EXTRAM_HIGH);
PMP_ENTRY_SET(9, pmpaddr_extram, PMP_NAPOT | RWX);
_Static_assert(SOC_EXTRAM_LOW < SOC_EXTRAM_HIGH, "Invalid I/D_EXTRAM region");
#endif
#endif /* CONFIG_SPIRAM */
// 6. LP memory (LP TCM / RTC SRAM)
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
extern int _rtc_text_start;
extern int _rtc_text_end;
/* LP TCM split into three regions (mirroring ESP32-P4 / ESP32-C6):
* [LOW, _rtc_text_start) RW : RTC-reserved mem + ULP/LP-core image (the HP core writes
* the program here, so it must stay writable).
* [_rtc_text_start, _rtc_text_end) RX : HP core rtc.text (e.g. deep-sleep wake stub).
* [_rtc_text_end, HIGH) RW : RTC data.
* Programmed in ascending-address order (S31 faults on overlapping PMP entries); every entry was
* already reset to a disabled state at the top of this function. */
PMP_ENTRY_SET(10, SOC_RTC_IRAM_LOW, NONE);
#if CONFIG_ESP_SYSTEM_MEMPROT_PMP_LP_CORE_RESERVE_MEM_EXEC
PMP_ENTRY_SET(11, (int)&_rtc_text_start, PMP_TOR | RWX);
#else
PMP_ENTRY_SET(11, (int)&_rtc_text_start, PMP_TOR | RW);
#endif
PMP_ENTRY_SET(12, (int)&_rtc_text_end, PMP_TOR | RX);
PMP_ENTRY_SET(13, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
#else
const uint32_t pmpaddr_rtc = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
PMP_ENTRY_SET(10, pmpaddr_rtc, PMP_NAPOT | RWX);
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
#endif
// 7. Peripheral addresses (on-chip peripherals, CPU peripheral, cache-data memory and the
// debug address space). The LP peripherals are contiguous with the rest and are covered by
// this single window as well. Peripherals use the last PMP entries (14-15) so that the entry
// count used by the regions above (which varies with the build configuration) never collides.
// Both indices are frozen by pmp_layout.h.
PMP_ENTRY_SET(PMP_ENTRY_PERIPHERAL_LOW, SOC_PERIPHERAL_LOW, NONE);
PMP_ENTRY_SET(PMP_ENTRY_PERIPHERAL_HIGH, SOC_PERIPHERAL_HIGH, PMP_TOR | RW);
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
}
#endif // BOOTLOADER_BUILD
void esp_cpu_configure_region_protection(void)
{
/* TODO: [ESP32S31] IDF-15238 */
/* Notes on implementation:
*
* 1) Note: ESP32-S31 CPU doesn't support overlapping PMP regions. Hence, like ESP32-H4, we
* must avoid the reset-and-set PMP macros for TOR entries (the transient pmpaddr=0 inside
* them creates a fleeting wrapping overlap that faults on this CPU). We use the non-reset
* PMP_ENTRY_SET and reset the relevant entries up front using PMP_ENTRY_CFG_RESET.
*
* 2) ESP32-S31 supports 16 PMA regions so we use this feature to block all the invalid address
* ranges and to mark the external flash/PSRAM and ROM regions as cacheable.
*
* 3) ESP32-S31 supports 16 PMP regions (writing pmpaddr>=16 raises an illegal-instruction fault,
* confirmed on rev v0.0 silicon). We use a combination of NAPOT (Naturally Aligned Power Of Two)
* and TOR (top of range) entries to map all the valid address space, bottom to top. The whole
* region set must therefore fit within entries 0-15, with the peripherals using the last entry.
*
* 4) Unlike ESP32-P4, the internal memories on ESP32-S31 are not aliased into a cached/uncached
* address pair, so each region needs only a single PMP entry (no CACHED_AND_UNCACHED helper).
*/
__attribute__((unused)) const unsigned PMA_RW = PMA_L | PMA_EN | PMA_R | PMA_W;
__attribute__((unused)) const unsigned PMA_RX = PMA_L | PMA_EN | PMA_R | PMA_X;
__attribute__((unused)) const unsigned PMA_RWX = PMA_L | PMA_EN | PMA_R | PMA_W | PMA_X;
/* The invalid (PMA) regions are configured in both the bootloader and the application. The valid
* (PMP) regions are configured and locked by the application only: an unlocked PMP entry does not
* constrain machine mode anyway, and a bootloader-locked entry could not be reconfigured until the
* next CPU reset - which would freeze the entry layout into a bootloader <-> application ABI. The
* bootloader therefore programs no PMP entry and the application owns and freezes the whole PMP
* layout (see pmp_layout.h). */
esp_cpu_configure_invalid_regions();
//without setting this, psram cannot be reached
PMA_RESET_AND_ENTRY_SET_NAPOT(7, SOC_EXTRAM_LOW, (SOC_EXTRAM_HIGH - SOC_EXTRAM_LOW), PMA_NAPOT | PMA_RWX);
#ifndef BOOTLOADER_BUILD
esp_cpu_configure_valid_regions();
#endif
}

View File

@@ -0,0 +1,56 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc.h"
#include "esp_assert.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* ESP32-S31 PMP entry layout: a bootloader <-> application ABI.
*
* A PMP entry that the (non-updatable) second stage bootloader locks cannot be reconfigured until
* the next CPU reset, so the index of any entry a shipped bootloader locks would be frozen for the
* lifetime of that device. To avoid such drift, the ESP-IDF bootloader for ESP32-S31 configures no
* PMP entry at all (it configures only PMA); the application programs and locks the entire PMP
* layout during early startup (see cpu_region_protect.c).
*
* No bootloader that locks a PMP entry has ever shipped for this target, so today no index is
* constrained by a deployed device. The boundary entries below are nonetheless frozen as a
* forward-compatibility contract and pinned with ESP_STATIC_ASSERTs, so a locked entry a future
* bootloader or a custom (non-ESP-IDF) application might rely on can never be silently renumbered.
*
* Frozen entries:
* 0 : CPU subsystem (NAPOT RWX)
* 1 - 2 : I/D-ROM (ROM-Cache) TOR pair
* 14 - 15 : peripherals TOR pair (on-chip peripherals, CPU peripheral, cache-data memory,
* LP peripherals and the debug address space)
*
* Entries 3 - 13 are application-owned (the SRAM IRAM/DRAM split, the flash I/D-cache split, the
* external PSRAM region and the LP-TCM split). Their count varies with the build configuration,
* they are programmed by plain index in cpu_region_protect.c, and they are NOT part of the ABI -
* they may change between versions.
*/
#define PMP_ENTRY_CPU_SUBSYSTEM 0
#define PMP_ENTRY_ROM_LOW 1
#define PMP_ENTRY_ROM_HIGH 2
#define PMP_ENTRY_PERIPHERAL_LOW 14
#define PMP_ENTRY_PERIPHERAL_HIGH 15
ESP_STATIC_ASSERT(PMP_ENTRY_CPU_SUBSYSTEM == 0
&& PMP_ENTRY_ROM_LOW == 1
&& PMP_ENTRY_ROM_HIGH == 2
&& PMP_ENTRY_PERIPHERAL_LOW == 14
&& PMP_ENTRY_PERIPHERAL_HIGH == 15,
"ESP32-S31 PMP entries that a bootloader may lock are a frozen ABI and must never move");
#ifdef __cplusplus
}
#endif

View File

@@ -193,9 +193,12 @@
#define CPU_PERIPH_LOW 0x2C000000
#define CPU_PERIPH_HIGH 0x2C020000
// Region of address space that holds peripherals, HP APB peripherals
#define SOC_PERIPHERAL_LOW 0x50000000 //TODO need update
#define SOC_PERIPHERAL_HIGH 0x50100000 //TODO need update
// Region of address space that holds the on-chip peripherals (MODEM/HP/LP APB
// peripherals, security peripherals, CPU peripheral, cache-data memory and the
// debug address space). Per the S31 bus address map this spans from the start of
// the "On-Chip Peripherals" aperture up to the base of the LP TCM (SOC_RTC_IRAM_LOW).
#define SOC_PERIPHERAL_LOW 0x20000000
#define SOC_PERIPHERAL_HIGH 0x2E000000
/** LP subsystem from ``LP_SYS`` through ``LP_DAC``*/
#define SOC_LP_PERIPH_LOW DR_REG_LP_SYS_BASE

View File

@@ -625,8 +625,9 @@ CONFIGS_MEMPROT_IDRAM = list(
'memprot_esp32h2',
'memprot_esp32p4',
'memprot_esp32h21',
'memprot_esp32s31',
],
['esp32s2', 'esp32c3', 'esp32c2', 'esp32c5', 'esp32c61', 'esp32h2', 'esp32p4', 'esp32h21'],
['esp32s2', 'esp32c3', 'esp32c2', 'esp32c5', 'esp32c61', 'esp32h2', 'esp32p4', 'esp32h21', 'esp32s31'],
)
) + [
('memprot_esp32p4_rev_less_than_v3', 'esp32p4', P4_REV_LESS_THAN_V3_MARKER),
@@ -646,8 +647,9 @@ CONFIGS_MEMPROT_RTC_FAST_MEM = list(
'memprot_esp32h2',
'memprot_esp32p4',
'memprot_esp32h21',
'memprot_esp32s31',
],
['esp32s2', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32h21'],
['esp32s2', 'esp32c3', 'esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32h21', 'esp32s31'],
)
) + [
('memprot_esp32p4_rev_less_than_v3', 'esp32p4', P4_REV_LESS_THAN_V3_MARKER),
@@ -664,8 +666,9 @@ CONFIGS_MEMPROT_FLASH_IDROM = list(
'memprot_esp32h2',
'memprot_esp32p4',
'memprot_esp32h21',
'memprot_esp32s31',
],
['esp32c5', 'esp32c6', 'esp32c61', 'esp32h2', 'esp32p4', 'esp32h21'],
['esp32c5', 'esp32c6', 'esp32c61', 'esp32h2', 'esp32p4', 'esp32h21', 'esp32s31'],
)
) + [
('memprot_esp32p4_rev_less_than_v3', 'esp32p4', P4_REV_LESS_THAN_V3_MARKER),
@@ -679,8 +682,9 @@ CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP = list(
'memprot_spiram_xip_esp32c5',
'memprot_spiram_xip_esp32c61',
'memprot_spiram_xip_esp32p4',
'memprot_spiram_xip_esp32s31',
],
['esp32c5', 'esp32c61', 'esp32p4'],
['esp32c5', 'esp32c61', 'esp32p4', 'esp32s31'],
)
) + [
('memprot_spiram_xip_esp32p4_rev_less_than_v3', 'esp32p4', P4_REV_LESS_THAN_V3_MARKER),
@@ -701,8 +705,9 @@ CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP = list(
'memprot_spiram_xip_esp32c5',
'memprot_spiram_xip_esp32c61',
'memprot_spiram_xip_esp32p4',
'memprot_spiram_xip_esp32s31',
],
['esp32s3', 'esp32c5', 'esp32c61', 'esp32p4'],
['esp32s3', 'esp32c5', 'esp32c61', 'esp32p4', 'esp32s31'],
)
) + [
('memprot_spiram_xip_esp32p4_rev_less_than_v3', 'esp32p4', P4_REV_LESS_THAN_V3_MARKER),
@@ -724,8 +729,9 @@ CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA = list(
'memprot_esp32h2',
'memprot_esp32p4',
'memprot_esp32h21',
'memprot_esp32s31',
],
['esp32c5', 'esp32c6', 'esp32c61', 'esp32h2', 'esp32p4', 'esp32h21'],
['esp32c5', 'esp32c6', 'esp32c61', 'esp32h2', 'esp32p4', 'esp32h21', 'esp32s31'],
)
) + [
('memprot_esp32p4_rev_less_than_v3', 'esp32p4', P4_REV_LESS_THAN_V3_MARKER),
@@ -972,7 +978,7 @@ def test_rtc_fast_reg1_execute_violation(dut: PanicTestDut, test_func_name: str)
@pytest.mark.generic
@pytest.mark.temp_skip(
targets=['esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32h21'],
targets=['esp32c5', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32h21', 'esp32s31'],
reason='Not a violation condition, no PMS peripheral cases',
)
@idf_parametrize('config, target', CONFIGS_MEMPROT_RTC_FAST_MEM, indirect=['config', 'target'])
@@ -1144,6 +1150,7 @@ def spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func
@pytest.mark.generic
@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='no PSRAM-equipped runner for v0.0 silicon yet')
@idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP, indirect=['config', 'target'])
def test_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
spiram_xip_irom_alignment_reg_execute_violation(dut, test_func_name)
@@ -1168,6 +1175,7 @@ def spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func
@pytest.mark.generic
@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='no PSRAM-equipped runner for v0.0 silicon yet')
@idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP, indirect=['config', 'target'])
def test_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
spiram_xip_drom_alignment_reg_execute_violation(dut, test_func_name)

View File

@@ -0,0 +1,8 @@
# Restricting to ESP32S31
CONFIG_IDF_TARGET="esp32s31"
# Enabling memory protection
CONFIG_ESP_SYSTEM_MEMPROT=y
# Enable memprot test
CONFIG_TEST_MEMPROT=y

View File

@@ -0,0 +1,13 @@
# Restricting to ESP32S31
CONFIG_IDF_TARGET="esp32s31"
# Enabling memory protection
CONFIG_ESP_SYSTEM_MEMPROT=y
# Enable memprot test
CONFIG_TEST_MEMPROT=y
# Enable SPIRAM to check the alignment gap's memory protection
CONFIG_SPIRAM=y
CONFIG_SPIRAM_USE_CAPS_ALLOC=y
CONFIG_SPIRAM_XIP_FROM_PSRAM=y