mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
Merge branch 'feat/pma_pmp_lock_policy' into 'master'
Stop locking PMP in the bootloader and freeze the entry layout See merge request espressif/esp-idf!50326
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -14,19 +14,7 @@
|
||||
#include "esp_private/esp_psram_extram.h"
|
||||
#endif /* !BOOTLOADER_BUILD && CONFIG_SPIRAM */
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
// Without L bit set
|
||||
#define CONDITIONAL_NONE 0x0
|
||||
#define CONDITIONAL_RX PMP_R | PMP_X
|
||||
#define CONDITIONAL_RW PMP_R | PMP_W
|
||||
#define CONDITIONAL_RWX PMP_R | PMP_W | PMP_X
|
||||
#else
|
||||
// With L bit set
|
||||
#define CONDITIONAL_NONE NONE
|
||||
#define CONDITIONAL_RX RX
|
||||
#define CONDITIONAL_RW RW
|
||||
#define CONDITIONAL_RWX RWX
|
||||
#endif
|
||||
#include "pmp_layout.h"
|
||||
|
||||
#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)
|
||||
@@ -92,39 +80,22 @@ static void esp_cpu_configure_invalid_regions(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
static void esp_cpu_configure_valid_regions(void)
|
||||
{
|
||||
/* Notes on implementation:
|
||||
/* There are 3 configuration scenarios for SRAM in the application
|
||||
*
|
||||
* 1) Note: ESP32-C5 CPU support overlapping PMP regions
|
||||
*
|
||||
* 2) ESP32-C5 supports 16 PMA regions so we use this feature to block all the invalid address ranges
|
||||
*
|
||||
* 3) We use combination of NAPOT (Naturally Aligned Power Of Two) and TOR (top of range)
|
||||
* entries to map all the valid address space, bottom to top. This leaves us with some extra PMP entries
|
||||
* which can be used to provide more granular access
|
||||
*
|
||||
* 4) Entries are grouped in order with some static asserts to try and verify everything is
|
||||
* correct.
|
||||
*/
|
||||
|
||||
/* There are 4 configuration scenarios for SRAM
|
||||
*
|
||||
* 1. Bootloader build:
|
||||
* - We cannot set the lock bit as we need to reconfigure it again for the application.
|
||||
* We configure PMP to cover entire valid IRAM and DRAM range.
|
||||
*
|
||||
* 2. Application build with CONFIG_ESP_SYSTEM_MEMPROT enabled
|
||||
* 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 _iram_text_end and _data_start markers to set the boundaries.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*
|
||||
* 3. Application build with CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP disabled
|
||||
* 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
|
||||
*
|
||||
* 4. CPU is in OCD debug 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
|
||||
@@ -135,43 +106,33 @@ void esp_cpu_configure_region_protection(void)
|
||||
__attribute__((unused)) const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
__attribute__((unused)) const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
//
|
||||
// Configure all the invalid address regions using PMA
|
||||
//
|
||||
esp_cpu_configure_invalid_regions();
|
||||
|
||||
/* NOTE: When ESP-TEE is active, only configure invalid memory regions in bootloader
|
||||
* to prevent errors before TEE initialization. TEE will handle all other
|
||||
* memory protection.
|
||||
*/
|
||||
#if CONFIG_SECURE_ENABLE_TEE && BOOTLOADER_BUILD
|
||||
return;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Configure all the valid address regions using PMP
|
||||
//
|
||||
|
||||
// 1. CPU Subsystem region - contains interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
PMP_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_CPU_SUBSYSTEM, pmpaddr0, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
|
||||
|
||||
// 2. I/D-ROM
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
#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 helps us to also configure
|
||||
// the region as cacheable. Thus, we save on one PMP entry.
|
||||
PMP_ENTRY_SET(1, drom_start, NONE);
|
||||
PMP_ENTRY_SET(2, SOC_DROM_MASK_HIGH, PMP_TOR | R);
|
||||
/* No cfg reset on the two ROM entries, deliberately: v6.0/v6.1
|
||||
* bootloaders lock PMP_ENTRY_ROM_LOW at SOC_IROM_MASK_LOW, so on such
|
||||
* devices the TOR region below spans the ROM text and must keep the X
|
||||
* bit those bootloaders left in PMP_ENTRY_ROM_HIGH. PMP_ENTRY_SET only
|
||||
* ORs cfg bits and cannot clear it; on newer bootloaders (no PMP
|
||||
* writes) the entries are clean and ROM data gets the intended R.
|
||||
*/
|
||||
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(1, SOC_IROM_MASK_LOW, NONE);
|
||||
PMP_ENTRY_SET(2, SOC_IROM_MASK_HIGH, PMP_TOR | CONDITIONAL_RX);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_ROM_LOW, SOC_IROM_MASK_LOW, NONE);
|
||||
PMP_RESET_AND_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");
|
||||
}
|
||||
|
||||
@@ -180,38 +141,31 @@ void esp_cpu_configure_region_protection(void)
|
||||
// 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);
|
||||
PMP_RESET_AND_ENTRY_SET(3, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_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 && !BOOTLOADER_BUILD
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _iram_text_end;
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
* Bootloader might have given extra permissions and those won't be cleared
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(3);
|
||||
PMP_ENTRY_CFG_RESET(4);
|
||||
PMP_ENTRY_CFG_RESET(5);
|
||||
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);
|
||||
PMP_RESET_AND_ENTRY_SET(3, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(4, (int)&_iram_text_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(5, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
PMP_ENTRY_SET(3, SOC_IRAM_LOW, CONDITIONAL_NONE);
|
||||
PMP_ENTRY_SET(4, SOC_IRAM_HIGH, PMP_TOR | CONDITIONAL_RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(3, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_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 (flash)
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
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));
|
||||
__attribute__((unused)) const uint32_t page_aligned_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end));
|
||||
|
||||
PMP_ENTRY_CFG_RESET(6);
|
||||
PMP_ENTRY_SET(6, SOC_IROM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(6, SOC_IROM_LOW, NONE);
|
||||
|
||||
/**
|
||||
Virtual space layout:
|
||||
@@ -238,68 +192,85 @@ void esp_cpu_configure_region_protection(void)
|
||||
if CONFIG_SPIRAM: [_rodata_reserved_end, page_aligned_drom_resv_end + available_psram_heap] in heap / reserved for mapping (RW)
|
||||
*/
|
||||
|
||||
PMP_ENTRY_CFG_RESET(7);
|
||||
PMP_ENTRY_CFG_RESET(8);
|
||||
PMP_ENTRY_CFG_RESET(9);
|
||||
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
PMP_ENTRY_SET(7, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(8, page_aligned_irom_resv_end, PMP_TOR | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(7, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(8, page_aligned_irom_resv_end, PMP_TOR | RW);
|
||||
#else
|
||||
PMP_ENTRY_SET(7, page_aligned_irom_resv_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(8, page_aligned_irom_resv_end, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(7, page_aligned_irom_resv_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(8, page_aligned_irom_resv_end, NONE);
|
||||
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION */
|
||||
|
||||
#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
PMP_ENTRY_SET(9, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
|
||||
PMP_RESET_AND_ENTRY_SET(9, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
|
||||
#else
|
||||
PMP_ENTRY_SET(9, page_aligned_drom_resv_end, PMP_TOR | R);
|
||||
PMP_RESET_AND_ENTRY_SET(9, page_aligned_drom_resv_end, PMP_TOR | R);
|
||||
#endif /* CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION */
|
||||
|
||||
#if CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
size_t available_psram_heap = esp_psram_get_heap_size_to_protect();
|
||||
PMP_ENTRY_CFG_RESET(10);
|
||||
PMP_ENTRY_SET(10, ESP_ALIGN_UP(page_aligned_drom_resv_end + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(10, ESP_ALIGN_UP(page_aligned_drom_resv_end + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
#endif /* CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION */
|
||||
#else
|
||||
const uint32_t pmpaddr6 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
// Add the W attribute in the case of PSRAM
|
||||
PMP_ENTRY_SET(6, pmpaddr6, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(6, pmpaddr6, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
#endif
|
||||
|
||||
// 5. LP memory
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _rtc_text_start;
|
||||
extern int _rtc_text_end;
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
* Bootloader might have given extra permissions and those won't be cleared
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(11);
|
||||
PMP_ENTRY_CFG_RESET(12);
|
||||
PMP_ENTRY_CFG_RESET(13);
|
||||
PMP_ENTRY_CFG_RESET(14);
|
||||
|
||||
PMP_ENTRY_SET(11, SOC_RTC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(11, SOC_RTC_IRAM_LOW, NONE);
|
||||
|
||||
// First part of LP mem is reserved for ULP coprocessor
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_PMP_LP_CORE_RESERVE_MEM_EXEC
|
||||
PMP_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RWX);
|
||||
#else
|
||||
PMP_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RW);
|
||||
#endif
|
||||
|
||||
PMP_ENTRY_SET(13, (int)&_rtc_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(14, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(13, (int)&_rtc_text_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(14, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
const uint32_t pmpaddr11 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
|
||||
PMP_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
|
||||
#endif
|
||||
|
||||
// 6. Peripheral addresses
|
||||
PMP_ENTRY_CFG_RESET(15);
|
||||
const uint32_t pmpaddr15 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_ENTRY_SET(15, pmpaddr15, PMP_NAPOT | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_PERIPHERAL, pmpaddr15, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
{
|
||||
/* Notes on implementation:
|
||||
*
|
||||
* 1) Note: ESP32-C5 CPU support overlapping PMP regions
|
||||
*
|
||||
* 2) ESP32-C5 supports 16 PMA regions so we use this feature to block all the invalid address ranges
|
||||
*
|
||||
* 3) We use combination of NAPOT (Naturally Aligned Power Of Two) and TOR (top of range)
|
||||
* entries to map all the valid address space, bottom to top. This leaves us with some extra PMP entries
|
||||
* which can be used to provide more granular access
|
||||
*
|
||||
* 4) Entries are grouped in order with some static asserts to try and verify everything is
|
||||
* correct.
|
||||
*/
|
||||
|
||||
/* 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 apply to M-mode, and a
|
||||
* locked one would survive into the application with no way to reconfigure
|
||||
* it until the next CPU reset). */
|
||||
esp_cpu_configure_invalid_regions();
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
esp_cpu_configure_valid_regions();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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-C5 PMP entry layout: a bootloader<->application ABI. An entry the
|
||||
* (non-updatable) bootloader locks cannot be reconfigured until CPU reset, so
|
||||
* the index of any entry a shipped bootloader locks is frozen.
|
||||
*
|
||||
* Entries locked by shipped bootloader generations (MP baseline v5.5):
|
||||
* v5.5 : 0, 1-2 (ROM), 15 (peripherals)
|
||||
* v6.0 / v6.1 : 0, 1 (ROM), 15 (peripherals)
|
||||
* >= v6.2 : none
|
||||
*/
|
||||
#define PMP_ENTRY_CPU_SUBSYSTEM 0 /* NAPOT RWX */
|
||||
#define PMP_ENTRY_ROM_LOW 1 /* TOR base */
|
||||
#define PMP_ENTRY_ROM_HIGH 2 /* TOR R or RX */
|
||||
/* 3..14: application-owned SRAM/flash/LP-RAM split, programmed by plain index
|
||||
* in cpu_region_protect.c; not part of the ABI, not frozen here. */
|
||||
#define PMP_ENTRY_PERIPHERAL 15 /* NAPOT RW */
|
||||
|
||||
ESP_STATIC_ASSERT(PMP_ENTRY_CPU_SUBSYSTEM == 0
|
||||
&& PMP_ENTRY_ROM_LOW == 1 && PMP_ENTRY_ROM_HIGH == 2
|
||||
&& PMP_ENTRY_PERIPHERAL == 15,
|
||||
"Entries locked by shipped bootloaders are a frozen ABI and must never move");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -10,22 +10,7 @@
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_fault.h"
|
||||
#include "esp_macros.h"
|
||||
|
||||
#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
|
||||
#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
|
||||
#endif
|
||||
#include "pmp_layout.h"
|
||||
|
||||
#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)
|
||||
@@ -69,6 +54,125 @@ static void esp_cpu_configure_invalid_regions(void)
|
||||
PMA_ENTRY_CFG_RESET(15);
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
static void esp_cpu_configure_valid_regions(void)
|
||||
{
|
||||
/* There are 3 configuration scenarios for SRAM in the application
|
||||
*
|
||||
* 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 _iram_text_end and _data_start markers to set the boundaries.
|
||||
* 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;
|
||||
const unsigned RW = PMP_L | PMP_R | PMP_W;
|
||||
const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
// 1. CPU Subsystem region - contains debug mode code and interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_CPU_SUBSYSTEM, pmpaddr0, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
|
||||
|
||||
// 2.1 I-ROM
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_IROM_LOW, SOC_IROM_MASK_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_IROM_HIGH, SOC_IROM_MASK_HIGH, PMP_TOR | RX);
|
||||
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I-ROM region");
|
||||
|
||||
/* 2.2 D-ROM - redundant with the I-ROM entry above (same range, already
|
||||
* locked RX); kept as a separate pair only to pin the app's IRAM/DRAM split
|
||||
* to entries 5-7.
|
||||
*
|
||||
* C6's ROM mask is not a power of two, so ROM needs a TOR pair on entries
|
||||
* 1-2. Commit d4167fea60c (v6.0) dropped this D-ROM pair and moved the split
|
||||
* down onto entries 3-4 - which bootloaders up to v5.2.1 lock as D-ROM. A
|
||||
* locked PMP entry can't be reconfigured until CPU reset, so such an app
|
||||
* can't gain IRAM execute permission and resets before app_main().
|
||||
* v5.2.2 freed 3-4, so only pre-v5.2.2 C6 bootloaders break.
|
||||
*/
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_DROM_LOW, SOC_DROM_MASK_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_DROM_HIGH, SOC_DROM_MASK_HIGH, PMP_TOR | R);
|
||||
_Static_assert(SOC_DROM_MASK_LOW < SOC_DROM_MASK_HIGH, "Invalid D-ROM region");
|
||||
|
||||
if (esp_cpu_dbgr_is_attached()) {
|
||||
// Anti-FI check that cpu is really in ocd mode
|
||||
ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached());
|
||||
|
||||
// 3. IRAM and DRAM
|
||||
const uint32_t pmpaddr5 = PMPADDR_NAPOT(SOC_IRAM_LOW, SOC_IRAM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(5, pmpaddr5, PMP_NAPOT | 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;
|
||||
// 3. IRAM and DRAM
|
||||
PMP_RESET_AND_ENTRY_SET(5, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(6, (int)&_iram_text_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(7, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
// 3. IRAM and DRAM
|
||||
const uint32_t pmpaddr5 = PMPADDR_NAPOT(SOC_IRAM_LOW, SOC_IRAM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(5, pmpaddr5, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _instruction_reserved_end;
|
||||
extern int _rodata_reserved_end;
|
||||
|
||||
const uint32_t irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_instruction_reserved_end));
|
||||
const uint32_t drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end));
|
||||
|
||||
// 4. I_Cache / D_Cache (flash)
|
||||
PMP_RESET_AND_ENTRY_SET(8, SOC_IROM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(9, irom_resv_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(10, drom_resv_end, PMP_TOR | R);
|
||||
#else
|
||||
// 4. I_Cache / D_Cache (flash)
|
||||
const uint32_t pmpaddr8 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(8, pmpaddr8, PMP_NAPOT | RX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
#endif
|
||||
|
||||
// 5. LP memory
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _rtc_text_start;
|
||||
extern int _rtc_text_end;
|
||||
PMP_RESET_AND_ENTRY_SET(11, SOC_RTC_IRAM_LOW, NONE);
|
||||
|
||||
// First part of LP mem is reserved for ULP coprocessor
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_PMP_LP_CORE_RESERVE_MEM_EXEC
|
||||
PMP_RESET_AND_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RWX);
|
||||
#else
|
||||
PMP_RESET_AND_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RW);
|
||||
#endif
|
||||
PMP_RESET_AND_ENTRY_SET(13, (int)&_rtc_text_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(14, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
const uint32_t pmpaddr11 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
|
||||
#endif
|
||||
|
||||
// 6. Peripheral addresses
|
||||
const uint32_t pmpaddr15 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_PERIPHERAL, pmpaddr15, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
{
|
||||
/* Notes on implementation:
|
||||
@@ -85,162 +189,14 @@ void esp_cpu_configure_region_protection(void)
|
||||
* correct.
|
||||
*/
|
||||
|
||||
/* There are 4 configuration scenarios for SRAM
|
||||
*
|
||||
* 1. Bootloader build:
|
||||
* - We cannot set the lock bit as we need to reconfigure it again for the application.
|
||||
* We configure PMP to cover entire valid IRAM and DRAM range.
|
||||
*
|
||||
* 2. 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 _iram_text_end and _data_start markers to set the boundaries.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*
|
||||
* 3. 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
|
||||
*
|
||||
* 4. 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;
|
||||
const unsigned RW = PMP_L | PMP_R | PMP_W;
|
||||
const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
//
|
||||
// Configure all the invalid address regions using PMA
|
||||
//
|
||||
/* 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 apply to M-mode, and a
|
||||
* locked one would survive into the application with no way to reconfigure
|
||||
* it until the next CPU reset). */
|
||||
esp_cpu_configure_invalid_regions();
|
||||
|
||||
/* NOTE: When ESP-TEE is active, only configure invalid memory regions in bootloader
|
||||
* to prevent errors before TEE initialization. TEE will handle all other
|
||||
* memory protection.
|
||||
*/
|
||||
#if CONFIG_SECURE_ENABLE_TEE && BOOTLOADER_BUILD
|
||||
return;
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
esp_cpu_configure_valid_regions();
|
||||
#endif
|
||||
|
||||
//
|
||||
// Configure all the valid address regions using PMP
|
||||
//
|
||||
|
||||
// 1. CPU Subsystem region - contains debug mode code and interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
PMP_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
|
||||
|
||||
// 2.1 I-ROM
|
||||
PMP_ENTRY_SET(1, SOC_IROM_MASK_LOW, NONE);
|
||||
PMP_ENTRY_SET(2, SOC_IROM_MASK_HIGH, PMP_TOR | RX);
|
||||
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I-ROM region");
|
||||
|
||||
/* 2.2 D-ROM - redundant with the I-ROM entry above (same range, already
|
||||
* locked RX); kept as a separate pair only to pin the app's IRAM/DRAM split
|
||||
* to entries 5-7.
|
||||
*
|
||||
* C6's ROM mask is not a power of two, so ROM needs a TOR pair on entries
|
||||
* 1-2. Commit d4167fea60c (v6.0) dropped this D-ROM pair and moved the split
|
||||
* down onto entries 3-4 - which bootloaders up to v5.2.1 lock as D-ROM. A
|
||||
* locked PMP entry can't be reconfigured until CPU reset, so such an app
|
||||
* can't gain IRAM execute permission and resets before app_main() (GitHub
|
||||
* #18769). v5.2.2 freed 3-4, so only pre-v5.2.2 C6 bootloaders break.
|
||||
*
|
||||
* CFG_RESET clears stale config a v6.0/v6.0.1 bootloader left here
|
||||
* (PMP_ENTRY_SET only ORs bits); no-op once 3-4 are locked. CONDITIONAL_*
|
||||
* keeps 3-4 locked in the app but unlocked in the bootloader (redundant, so
|
||||
* no protection lost), letting a future app reclaim them once pre-v5.2.2
|
||||
* bootloaders are out of support.
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(3);
|
||||
PMP_ENTRY_CFG_RESET(4);
|
||||
PMP_ENTRY_SET(3, SOC_DROM_MASK_LOW, CONDITIONAL_NONE);
|
||||
PMP_ENTRY_SET(4, SOC_DROM_MASK_HIGH, PMP_TOR | CONDITIONAL_R);
|
||||
_Static_assert(SOC_DROM_MASK_LOW < SOC_DROM_MASK_HIGH, "Invalid D-ROM region");
|
||||
|
||||
if (esp_cpu_dbgr_is_attached()) {
|
||||
// Anti-FI check that cpu is really in ocd mode
|
||||
ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached());
|
||||
|
||||
// 3. IRAM and DRAM
|
||||
const uint32_t pmpaddr5 = PMPADDR_NAPOT(SOC_IRAM_LOW, SOC_IRAM_HIGH);
|
||||
PMP_ENTRY_SET(5, pmpaddr5, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
} else {
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
extern int _iram_text_end;
|
||||
// 3. IRAM and DRAM
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
* Bootloader might have given extra permissions and those won't be cleared
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(5);
|
||||
PMP_ENTRY_CFG_RESET(6);
|
||||
PMP_ENTRY_CFG_RESET(7);
|
||||
PMP_ENTRY_SET(5, SOC_IRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET(6, (int)&_iram_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(7, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
// 3. IRAM and DRAM
|
||||
const uint32_t pmpaddr5 = PMPADDR_NAPOT(SOC_IRAM_LOW, SOC_IRAM_HIGH);
|
||||
PMP_ENTRY_SET(5, pmpaddr5, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
extern int _instruction_reserved_end;
|
||||
extern int _rodata_reserved_end;
|
||||
|
||||
const uint32_t irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_instruction_reserved_end));
|
||||
const uint32_t drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end));
|
||||
|
||||
// 4. I_Cache / D_Cache (flash)
|
||||
PMP_ENTRY_CFG_RESET(8);
|
||||
PMP_ENTRY_CFG_RESET(9);
|
||||
PMP_ENTRY_CFG_RESET(10);
|
||||
PMP_ENTRY_SET(8, SOC_IROM_LOW, NONE);
|
||||
PMP_ENTRY_SET(9, irom_resv_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(10, drom_resv_end, PMP_TOR | R);
|
||||
#else
|
||||
// 4. I_Cache / D_Cache (flash)
|
||||
const uint32_t pmpaddr8 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
PMP_ENTRY_SET(8, pmpaddr8, PMP_NAPOT | CONDITIONAL_RX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
#endif
|
||||
|
||||
// 5. LP memory
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
extern int _rtc_text_start;
|
||||
extern int _rtc_text_end;
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
* Bootloader might have given extra permissions and those won't be cleared
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(11);
|
||||
PMP_ENTRY_CFG_RESET(12);
|
||||
PMP_ENTRY_CFG_RESET(13);
|
||||
PMP_ENTRY_CFG_RESET(14);
|
||||
PMP_ENTRY_SET(11, SOC_RTC_IRAM_LOW, NONE);
|
||||
|
||||
// First part of LP mem is reserved for ULP coprocessor
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_PMP_LP_CORE_RESERVE_MEM_EXEC
|
||||
PMP_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RWX);
|
||||
#else
|
||||
PMP_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RW);
|
||||
#endif
|
||||
PMP_ENTRY_SET(13, (int)&_rtc_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(14, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
const uint32_t pmpaddr11 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
|
||||
PMP_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
|
||||
#endif
|
||||
|
||||
// 6. Peripheral addresses
|
||||
const uint32_t pmpaddr15 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_ENTRY_SET(15, pmpaddr15, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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-C6 PMP entry layout: a bootloader<->application ABI. An entry the
|
||||
* (non-updatable) bootloader locks cannot be reconfigured until CPU reset, so
|
||||
* the index of any entry a shipped bootloader locks is frozen.
|
||||
* The layout below matches v5.2.2..v5.5; older generations that locked a
|
||||
* different value on a shared index cannot be helped (their lock wins).
|
||||
*
|
||||
* Entries locked by shipped bootloader generations:
|
||||
* <= v5.2.1 : 0, 1-2 (I-ROM), 3-4 (D-ROM), 8-9 (cache), 14 (periph)
|
||||
* v5.2.2 .. v5.5 : 0, 1-2 (I-ROM), 15 (peripherals)
|
||||
* v6.0 / v6.1 : 0, 1-2 (I-ROM), 13 (peripherals)
|
||||
* >= v6.2 : none
|
||||
*/
|
||||
#define PMP_ENTRY_CPU_SUBSYSTEM 0 /* NAPOT RWX */
|
||||
#define PMP_ENTRY_IROM_LOW 1 /* TOR base */
|
||||
#define PMP_ENTRY_IROM_HIGH 2 /* TOR RX */
|
||||
#define PMP_ENTRY_DROM_LOW 3 /* TOR base (locked by <= v5.2.1) */
|
||||
#define PMP_ENTRY_DROM_HIGH 4 /* TOR R (locked by <= v5.2.1) */
|
||||
/* 5..14: application-owned SRAM/flash/LP-RAM split, programmed by plain index
|
||||
* in cpu_region_protect.c; not part of the ABI, not frozen here. */
|
||||
#define PMP_ENTRY_PERIPHERAL 15 /* NAPOT RW */
|
||||
|
||||
ESP_STATIC_ASSERT(PMP_ENTRY_CPU_SUBSYSTEM == 0
|
||||
&& PMP_ENTRY_IROM_LOW == 1 && PMP_ENTRY_IROM_HIGH == 2
|
||||
&& PMP_ENTRY_DROM_LOW == 3 && PMP_ENTRY_DROM_HIGH == 4
|
||||
&& PMP_ENTRY_PERIPHERAL == 15,
|
||||
"Entries locked by shipped bootloaders are a frozen ABI and must never move");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -15,19 +15,7 @@
|
||||
#include "esp_private/esp_psram_extram.h"
|
||||
#endif /* !BOOTLOADER_BUILD && CONFIG_SPIRAM */
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
// Without L bit set
|
||||
#define CONDITIONAL_NONE 0x0
|
||||
#define CONDITIONAL_RX PMP_R | PMP_X
|
||||
#define CONDITIONAL_RW PMP_R | PMP_W
|
||||
#define CONDITIONAL_RWX PMP_R | PMP_W | PMP_X
|
||||
#else
|
||||
// With L bit set
|
||||
#define CONDITIONAL_NONE NONE
|
||||
#define CONDITIONAL_RX RX
|
||||
#define CONDITIONAL_RW RW
|
||||
#define CONDITIONAL_RWX RWX
|
||||
#endif
|
||||
#include "pmp_layout.h"
|
||||
|
||||
#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)
|
||||
@@ -76,39 +64,22 @@ static void esp_cpu_configure_invalid_regions(void)
|
||||
PMA_ENTRY_CFG_RESET(15);
|
||||
}
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
static void esp_cpu_configure_valid_regions(void)
|
||||
{
|
||||
/* Notes on implementation:
|
||||
/* There are 3 configuration scenarios for SRAM in the application
|
||||
*
|
||||
* 1) Note: ESP32-C61 CPU supports overlapping PMP regions
|
||||
*
|
||||
* 2) ESP32-C61 supports 16 PMA regions so we use this feature to block all the invalid address ranges
|
||||
*
|
||||
* 3) We use combination of NAPOT (Naturally Aligned Power Of Two) and TOR (top of range)
|
||||
* entries to map all the valid address space, bottom to top. This leaves us with some extra PMP entries
|
||||
* which can be used to provide more granular access
|
||||
*
|
||||
* 4) Entries are grouped in order with some static asserts to try and verify everything is
|
||||
* correct.
|
||||
*/
|
||||
|
||||
/* There are 4 configuration scenarios for SRAM
|
||||
*
|
||||
* 1. Bootloader build:
|
||||
* - We cannot set the lock bit as we need to reconfigure it again for the application.
|
||||
* We configure PMP to cover entire valid IRAM and DRAM range.
|
||||
*
|
||||
* 2. Application build with CONFIG_ESP_SYSTEM_MEMPROT enabled
|
||||
* 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 _iram_text_end and _data_start markers to set the boundaries.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*
|
||||
* 3. Application build with CONFIG_ESP_SYSTEM_MEMPROT disabled
|
||||
* 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
|
||||
*
|
||||
* 4. CPU is in OCD debug 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
|
||||
@@ -119,40 +90,23 @@ void esp_cpu_configure_region_protection(void)
|
||||
__attribute__((unused)) const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
__attribute__((unused)) const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
//
|
||||
// Configure all the invalid address regions using PMA
|
||||
//
|
||||
esp_cpu_configure_invalid_regions();
|
||||
|
||||
/* NOTE: When ESP-TEE is active, only configure invalid memory regions in bootloader
|
||||
* to prevent errors before TEE initialization. TEE will handle all other
|
||||
* memory protection.
|
||||
*/
|
||||
#if CONFIG_SECURE_ENABLE_TEE && BOOTLOADER_BUILD
|
||||
return;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Configure all the valid address regions using PMP
|
||||
//
|
||||
|
||||
// 1. CPU Subsystem region - contains interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
PMP_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_CPU_SUBSYSTEM, pmpaddr0, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
|
||||
|
||||
// 2. I/D-ROM
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
#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) {
|
||||
PMP_ENTRY_SET(1, SOC_IROM_MASK_LOW, NONE);
|
||||
PMP_ENTRY_SET(2, drom_start, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(3, SOC_DROM_MASK_HIGH, PMP_TOR | R);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_ROM_LOW, SOC_IROM_MASK_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_ROM_TEXT_HIGH, drom_start, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_ROM_HIGH, SOC_DROM_MASK_HIGH, PMP_TOR | R);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
const uint32_t pmpaddr1 = PMPADDR_NAPOT(SOC_IROM_MASK_LOW, SOC_IROM_MASK_HIGH);
|
||||
PMP_ENTRY_SET(1, pmpaddr1, PMP_NAPOT | CONDITIONAL_RX);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_ROM_LOW, pmpaddr1, PMP_NAPOT | RX);
|
||||
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region");
|
||||
}
|
||||
|
||||
@@ -161,38 +115,31 @@ void esp_cpu_configure_region_protection(void)
|
||||
// Anti-FI check that cpu is really in ocd mode
|
||||
ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached());
|
||||
|
||||
PMP_ENTRY_SET(4, SOC_IRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET(5, SOC_IRAM_HIGH, PMP_TOR | RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(4, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(5, 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 && !BOOTLOADER_BUILD
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _iram_text_end;
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
* Bootloader might have given extra permissions and those won't be cleared
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(4);
|
||||
PMP_ENTRY_CFG_RESET(5);
|
||||
PMP_ENTRY_CFG_RESET(6);
|
||||
PMP_ENTRY_SET(4, SOC_IRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET(5, (int)&_iram_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(6, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(4, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(5, (int)&_iram_text_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(6, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
PMP_ENTRY_SET(4, SOC_IRAM_LOW, CONDITIONAL_NONE);
|
||||
PMP_ENTRY_SET(5, SOC_IRAM_HIGH, PMP_TOR | CONDITIONAL_RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(4, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(5, SOC_IRAM_HIGH, PMP_TOR | RWX);
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
#endif
|
||||
}
|
||||
|
||||
// 4. I_Cache / D_Cache (flash)
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
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));
|
||||
__attribute__((unused)) const uint32_t page_aligned_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end));
|
||||
|
||||
PMP_ENTRY_CFG_RESET(7);
|
||||
PMP_ENTRY_SET(7, SOC_IROM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(7, SOC_IROM_LOW, NONE);
|
||||
|
||||
/**
|
||||
Virtual space layout:
|
||||
@@ -219,38 +166,63 @@ void esp_cpu_configure_region_protection(void)
|
||||
if CONFIG_SPIRAM: [_rodata_reserved_end, page_aligned_drom_resv_end + available_psram_heap] in heap / reserved for mapping (RW)
|
||||
*/
|
||||
|
||||
PMP_ENTRY_CFG_RESET(8);
|
||||
PMP_ENTRY_CFG_RESET(9);
|
||||
PMP_ENTRY_CFG_RESET(10);
|
||||
|
||||
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
PMP_ENTRY_SET(8, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(9, page_aligned_irom_resv_end, PMP_TOR | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(8, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(9, page_aligned_irom_resv_end, PMP_TOR | RW);
|
||||
#else
|
||||
PMP_ENTRY_SET(8, page_aligned_irom_resv_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(9, page_aligned_irom_resv_end, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(8, page_aligned_irom_resv_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(9, page_aligned_irom_resv_end, NONE);
|
||||
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION */
|
||||
|
||||
#if CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
PMP_ENTRY_SET(10, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
|
||||
PMP_RESET_AND_ENTRY_SET(10, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
|
||||
#else
|
||||
PMP_ENTRY_SET(10, page_aligned_drom_resv_end, PMP_TOR | R);
|
||||
PMP_RESET_AND_ENTRY_SET(10, page_aligned_drom_resv_end, PMP_TOR | R);
|
||||
#endif /* CONFIG_SPIRAM_RODATA && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION*/
|
||||
|
||||
#if CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
size_t available_psram_heap = esp_psram_get_heap_size_to_protect();
|
||||
PMP_ENTRY_CFG_RESET(11);
|
||||
PMP_ENTRY_SET(11, ESP_ALIGN_UP(page_aligned_drom_resv_end + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(11, ESP_ALIGN_UP(page_aligned_drom_resv_end + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
#endif /* CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION */
|
||||
#else
|
||||
const uint32_t pmpaddr7 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
// Add the W attribute in the case of PSRAM
|
||||
PMP_ENTRY_SET(7, pmpaddr7, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(7, pmpaddr7, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
#endif
|
||||
|
||||
// 5. Peripheral addresses
|
||||
const uint32_t pmpaddr12 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_ENTRY_SET(12, pmpaddr12, PMP_NAPOT | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_PERIPHERAL, pmpaddr12, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
{
|
||||
/* Notes on implementation:
|
||||
*
|
||||
* 1) Note: ESP32-C61 CPU supports overlapping PMP regions
|
||||
*
|
||||
* 2) ESP32-C61 supports 16 PMA regions so we use this feature to block all the invalid address ranges
|
||||
*
|
||||
* 3) We use combination of NAPOT (Naturally Aligned Power Of Two) and TOR (top of range)
|
||||
* entries to map all the valid address space, bottom to top. This leaves us with some extra PMP entries
|
||||
* which can be used to provide more granular access
|
||||
*
|
||||
* 4) Entries are grouped in order with some static asserts to try and verify everything is
|
||||
* correct.
|
||||
*/
|
||||
|
||||
/* 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 apply to M-mode, and a
|
||||
* locked one would survive into the application with no way to reconfigure
|
||||
* it until the next CPU reset). */
|
||||
esp_cpu_configure_invalid_regions();
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
esp_cpu_configure_valid_regions();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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-C61 PMP entry layout: a bootloader<->application ABI. An entry the
|
||||
* (non-updatable) bootloader locks cannot be reconfigured until CPU reset, so
|
||||
* the index of any entry a shipped bootloader locks is frozen.
|
||||
*
|
||||
* Entries locked by shipped bootloader generations (MP baseline v5.5):
|
||||
* v5.5 : 0, 1-3 (ROM), 12 (peripherals)
|
||||
* v6.0 / v6.1 : 0, 12 (peripherals)
|
||||
* >= v6.2 : none
|
||||
*/
|
||||
#define PMP_ENTRY_CPU_SUBSYSTEM 0 /* NAPOT RWX */
|
||||
#define PMP_ENTRY_ROM_LOW 1 /* TOR base, or NAPOT RX (unaligned branch) */
|
||||
#define PMP_ENTRY_ROM_TEXT_HIGH 2 /* TOR RX (aligned branch) */
|
||||
#define PMP_ENTRY_ROM_HIGH 3 /* TOR R (aligned branch) */
|
||||
/* 4..11: application-owned SRAM/flash split, programmed by plain index in
|
||||
* cpu_region_protect.c; not part of the ABI, not frozen here. */
|
||||
#define PMP_ENTRY_PERIPHERAL 12 /* NAPOT RW */
|
||||
|
||||
ESP_STATIC_ASSERT(PMP_ENTRY_CPU_SUBSYSTEM == 0
|
||||
&& PMP_ENTRY_ROM_LOW == 1 && PMP_ENTRY_ROM_TEXT_HIGH == 2
|
||||
&& PMP_ENTRY_ROM_HIGH == 3
|
||||
&& PMP_ENTRY_PERIPHERAL == 12,
|
||||
"Entries locked by shipped bootloaders are a frozen ABI and must never move");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -10,22 +10,7 @@
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_fault.h"
|
||||
#include "esp_macros.h"
|
||||
|
||||
#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
|
||||
#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
|
||||
#endif
|
||||
#include "pmp_layout.h"
|
||||
|
||||
#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)
|
||||
@@ -69,6 +54,118 @@ static void esp_cpu_configure_invalid_regions(void)
|
||||
PMA_ENTRY_CFG_RESET(15);
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
static void esp_cpu_configure_valid_regions(void)
|
||||
{
|
||||
/* There are 3 configuration scenarios for SRAM in the application
|
||||
*
|
||||
* 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 _iram_text_end and _data_start markers to set the boundaries.
|
||||
* 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;
|
||||
const unsigned RW = PMP_L | PMP_R | PMP_W;
|
||||
const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
// 1. CPU Subsystem region - contains debug mode code and interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_CPU_SUBSYSTEM, pmpaddr0, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
|
||||
|
||||
// 2.1 I-ROM
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_IROM_LOW, SOC_IROM_MASK_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_IROM_HIGH, SOC_IROM_MASK_HIGH, PMP_TOR | RX);
|
||||
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I-ROM region");
|
||||
|
||||
/* 2.2 D-ROM - redundant with the I-ROM entry above (same range, already
|
||||
* locked RX); kept as a separate pair only to pin the app's IRAM/DRAM split
|
||||
* to entries 5-7.
|
||||
*
|
||||
* H2's ROM mask is a power of two, so commit d4167fea60c (v6.0) folded ROM
|
||||
* into a single NAPOT entry (1) and moved the split down onto entry 2 -
|
||||
* which every pre-v6.0 bootloader locks as the I-ROM TOR top. A locked PMP
|
||||
* entry can't be reconfigured until CPU reset, so such an app can't gain
|
||||
* IRAM execute permission and resets before app_main().
|
||||
* ROM was never a single NAPOT before v6.0, so ALL pre-v6.0 bootloaders
|
||||
* break (unlike C6, where only pre-v5.2.2 do).
|
||||
*/
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_DROM_LOW, SOC_DROM_MASK_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_DROM_HIGH, SOC_DROM_MASK_HIGH, PMP_TOR | R);
|
||||
_Static_assert(SOC_DROM_MASK_LOW < SOC_DROM_MASK_HIGH, "Invalid D-ROM region");
|
||||
|
||||
if (esp_cpu_dbgr_is_attached()) {
|
||||
// Anti-FI check that cpu is really in ocd mode
|
||||
ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached());
|
||||
|
||||
// 3. IRAM and DRAM
|
||||
PMP_RESET_AND_ENTRY_SET(5, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(6, 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;
|
||||
// 3. IRAM and DRAM
|
||||
PMP_RESET_AND_ENTRY_SET(5, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(6, (int)&_iram_text_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(7, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
// 3. IRAM and DRAM
|
||||
PMP_RESET_AND_ENTRY_SET(5, SOC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(6, SOC_IRAM_HIGH, PMP_TOR | RWX);
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _instruction_reserved_end;
|
||||
extern int _rodata_reserved_end;
|
||||
|
||||
const uint32_t irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_instruction_reserved_end));
|
||||
const uint32_t drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end));
|
||||
|
||||
// 4. I_Cache / D_Cache (flash)
|
||||
PMP_RESET_AND_ENTRY_SET(8, SOC_IROM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(9, irom_resv_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(10, drom_resv_end, PMP_TOR | R);
|
||||
#else
|
||||
// 4. I_Cache / D_Cache (flash)
|
||||
const uint32_t pmpaddr8 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(8, pmpaddr8, PMP_NAPOT | RX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
#endif
|
||||
|
||||
// 5. LP memory
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _rtc_text_end;
|
||||
PMP_RESET_AND_ENTRY_SET(11, SOC_RTC_IRAM_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(12, (int)&_rtc_text_end, PMP_TOR | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(13, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
const uint32_t pmpaddr11 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
|
||||
#endif
|
||||
|
||||
// 6. Peripheral addresses
|
||||
const uint32_t pmpaddr14 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_PERIPHERAL, pmpaddr14, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
{
|
||||
/* Notes on implementation:
|
||||
@@ -85,155 +182,14 @@ void esp_cpu_configure_region_protection(void)
|
||||
* correct.
|
||||
*/
|
||||
|
||||
/* There are 4 configuration scenarios for SRAM
|
||||
*
|
||||
* 1. Bootloader build:
|
||||
* - We cannot set the lock bit as we need to reconfigure it again for the application.
|
||||
* We configure PMP to cover entire valid IRAM and DRAM range.
|
||||
*
|
||||
* 2. 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 _iram_text_end and _data_start markers to set the boundaries.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*
|
||||
* 3. 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
|
||||
*
|
||||
* 4. 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;
|
||||
const unsigned RW = PMP_L | PMP_R | PMP_W;
|
||||
const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
//
|
||||
// Configure all the invalid address regions using PMA
|
||||
//
|
||||
/* 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 apply to M-mode, and a
|
||||
* locked one would survive into the application with no way to reconfigure
|
||||
* it until the next CPU reset). */
|
||||
esp_cpu_configure_invalid_regions();
|
||||
|
||||
/* NOTE: When ESP-TEE is active, only configure invalid memory regions in bootloader
|
||||
* to prevent errors before TEE initialization. TEE will handle all other
|
||||
* memory protection.
|
||||
*/
|
||||
#if CONFIG_SECURE_ENABLE_TEE && BOOTLOADER_BUILD
|
||||
return;
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
esp_cpu_configure_valid_regions();
|
||||
#endif
|
||||
|
||||
//
|
||||
// Configure all the valid address regions using PMP
|
||||
//
|
||||
|
||||
// 1. CPU Subsystem region - contains debug mode code and interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
PMP_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
|
||||
|
||||
// 2.1 I-ROM
|
||||
PMP_ENTRY_SET(1, SOC_IROM_MASK_LOW, NONE);
|
||||
PMP_ENTRY_SET(2, SOC_IROM_MASK_HIGH, PMP_TOR | RX);
|
||||
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I-ROM region");
|
||||
|
||||
/* 2.2 D-ROM - redundant with the I-ROM entry above (same range, already
|
||||
* locked RX); kept as a separate pair only to pin the app's IRAM/DRAM split
|
||||
* to entries 5-7.
|
||||
*
|
||||
* H2's ROM mask is a power of two, so commit d4167fea60c (v6.0) folded ROM
|
||||
* into a single NAPOT entry (1) and moved the split down onto entry 2 -
|
||||
* which every pre-v6.0 bootloader locks as the I-ROM TOR top. A locked PMP
|
||||
* entry can't be reconfigured until CPU reset, so such an app can't gain
|
||||
* IRAM execute permission and resets before app_main() (GitHub #18769).
|
||||
* ROM was never a single NAPOT before v6.0, so ALL pre-v6.0 bootloaders
|
||||
* break (unlike C6, where only pre-v5.2.2 do).
|
||||
*
|
||||
* CFG_RESET clears stale config a v6.0/v6.0.1 bootloader left here
|
||||
* (PMP_ENTRY_SET only ORs bits); no-op once these are locked. CONDITIONAL_*
|
||||
* keeps 3-4 locked in the app but unlocked in the bootloader (redundant, so
|
||||
* no protection lost), letting a future app reclaim them once pre-v5.2.3
|
||||
* bootloaders are out of support.
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(3);
|
||||
PMP_ENTRY_CFG_RESET(4);
|
||||
PMP_ENTRY_SET(3, SOC_DROM_MASK_LOW, CONDITIONAL_NONE);
|
||||
PMP_ENTRY_SET(4, SOC_DROM_MASK_HIGH, PMP_TOR | CONDITIONAL_R);
|
||||
_Static_assert(SOC_DROM_MASK_LOW < SOC_DROM_MASK_HIGH, "Invalid D-ROM region");
|
||||
|
||||
if (esp_cpu_dbgr_is_attached()) {
|
||||
// Anti-FI check that cpu is really in ocd mode
|
||||
ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached());
|
||||
|
||||
// 3. IRAM and DRAM
|
||||
PMP_ENTRY_SET(5, SOC_IRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET(6, 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 && !BOOTLOADER_BUILD
|
||||
extern int _iram_text_end;
|
||||
// 3. IRAM and DRAM
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
* Bootloader might have given extra permissions and those won't be cleared
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(5);
|
||||
PMP_ENTRY_CFG_RESET(6);
|
||||
PMP_ENTRY_CFG_RESET(7);
|
||||
PMP_ENTRY_SET(5, SOC_IRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET(6, (int)&_iram_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(7, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
// 3. IRAM and DRAM
|
||||
PMP_ENTRY_SET(5, SOC_IRAM_LOW, CONDITIONAL_NONE);
|
||||
PMP_ENTRY_SET(6, SOC_IRAM_HIGH, PMP_TOR | CONDITIONAL_RWX);
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
extern int _instruction_reserved_end;
|
||||
extern int _rodata_reserved_end;
|
||||
|
||||
const uint32_t irom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_instruction_reserved_end));
|
||||
const uint32_t drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end));
|
||||
|
||||
// 4. I_Cache / D_Cache (flash)
|
||||
PMP_ENTRY_CFG_RESET(8);
|
||||
PMP_ENTRY_CFG_RESET(9);
|
||||
PMP_ENTRY_CFG_RESET(10);
|
||||
PMP_ENTRY_SET(8, SOC_IROM_LOW, NONE);
|
||||
PMP_ENTRY_SET(9, irom_resv_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(10, drom_resv_end, PMP_TOR | R);
|
||||
#else
|
||||
// 4. I_Cache / D_Cache (flash)
|
||||
const uint32_t pmpaddr8 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
PMP_ENTRY_SET(8, pmpaddr8, PMP_NAPOT | CONDITIONAL_RX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
#endif
|
||||
|
||||
// 5. LP memory
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
extern int _rtc_text_end;
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
* Bootloader might have given extra permissions and those won't be cleared
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(11);
|
||||
PMP_ENTRY_CFG_RESET(12);
|
||||
PMP_ENTRY_CFG_RESET(13);
|
||||
PMP_ENTRY_SET(11, SOC_RTC_IRAM_LOW, NONE);
|
||||
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 pmpaddr11 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
|
||||
PMP_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
|
||||
#endif
|
||||
|
||||
// 6. Peripheral addresses
|
||||
PMP_ENTRY_CFG_RESET(14);
|
||||
const uint32_t pmpaddr14 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_ENTRY_SET(14, pmpaddr14, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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-H2 PMP entry layout: a bootloader<->application ABI. An entry the
|
||||
* (non-updatable) bootloader locks cannot be reconfigured until CPU reset, so
|
||||
* the index of any entry a shipped bootloader locks is frozen.
|
||||
* The layout below matches v5.2.2..v5.5; older generations that locked a
|
||||
* different value on a shared index cannot be helped (their lock wins).
|
||||
*
|
||||
* Entries locked by shipped bootloader generations:
|
||||
* <= v5.2.1 : 0, 1-2 (I-ROM), 3-4 (D-ROM), 8-9 (cache), 13 (periph)
|
||||
* v5.2.2 .. v5.5 : 0, 1-2 (I-ROM), 14 (peripherals)
|
||||
* v6.0 / v6.1 : 0, 1 (ROM), 11 (peripherals)
|
||||
* >= v6.2 : none
|
||||
*/
|
||||
#define PMP_ENTRY_CPU_SUBSYSTEM 0 /* NAPOT RWX */
|
||||
#define PMP_ENTRY_IROM_LOW 1 /* TOR base */
|
||||
#define PMP_ENTRY_IROM_HIGH 2 /* TOR RX */
|
||||
#define PMP_ENTRY_DROM_LOW 3 /* TOR base (locked by <= v5.2.1) */
|
||||
#define PMP_ENTRY_DROM_HIGH 4 /* TOR R (locked by <= v5.2.1) */
|
||||
/* 5..13: application-owned SRAM/flash/LP-RAM split, programmed by plain index
|
||||
* in cpu_region_protect.c; not part of the ABI, not frozen here. */
|
||||
#define PMP_ENTRY_PERIPHERAL 14 /* NAPOT RW */
|
||||
|
||||
ESP_STATIC_ASSERT(PMP_ENTRY_CPU_SUBSYSTEM == 0
|
||||
&& PMP_ENTRY_IROM_LOW == 1 && PMP_ENTRY_IROM_HIGH == 2
|
||||
&& PMP_ENTRY_DROM_LOW == 3 && PMP_ENTRY_DROM_HIGH == 4
|
||||
&& PMP_ENTRY_PERIPHERAL == 14,
|
||||
"Entries locked by shipped bootloaders are a frozen ABI and must never move");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -18,22 +18,7 @@
|
||||
|
||||
#include "soc/chip_revision.h"
|
||||
#include "hal/config.h"
|
||||
|
||||
#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
|
||||
#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
|
||||
#endif
|
||||
#include "pmp_layout.h"
|
||||
|
||||
#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)
|
||||
@@ -85,6 +70,7 @@ static void esp_cpu_configure_invalid_regions(void)
|
||||
PMA_RESET_AND_ENTRY_SET_TOR(15, UINT32_MAX, PMA_TOR | PMA_NONE);
|
||||
}
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
// Helper macro to set both cached and non-cached PMP entries with the same permissions
|
||||
#define PMP_ENTRY_SET_CACHED_AND_UNCACHED(cached_entry, non_cached_entry, addr, perm) \
|
||||
@@ -103,7 +89,7 @@ static void esp_cpu_configure_region_protection_rev_v3(void)
|
||||
|
||||
// 1. CPU Subsystem region - contains debug mode code and interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_CPU_SUBSYSTEM, pmpaddr0, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
|
||||
|
||||
// 2. HP-CPU SPM
|
||||
@@ -111,15 +97,15 @@ static void esp_cpu_configure_region_protection_rev_v3(void)
|
||||
|
||||
// 3. CPU Peripherals
|
||||
const uint32_t pmpaddr1 = PMPADDR_NAPOT(CPU_PERIPH_LOW, CPU_PERIPH_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(1, pmpaddr1, PMP_NAPOT | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_CPU_PERIPHERAL, pmpaddr1, PMP_NAPOT | RW);
|
||||
_Static_assert(CPU_PERIPH_LOW < CPU_PERIPH_HIGH, "Invalid CPU peripheral region");
|
||||
|
||||
// 4. I/D-ROM
|
||||
const uint32_t pmpaddr2 = PMPADDR_NAPOT(SOC_IROM_MASK_LOW, SOC_IROM_MASK_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(2, pmpaddr2, PMP_NAPOT | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_ROM, pmpaddr2, PMP_NAPOT | RX);
|
||||
|
||||
const uint32_t pmpaddr3 = PMPADDR_NAPOT(CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_IROM_MASK_LOW), CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_IROM_MASK_HIGH));
|
||||
PMP_RESET_AND_ENTRY_SET(3, pmpaddr3, PMP_NAPOT | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_ROM_UNCACHED_REV_V3, pmpaddr3, PMP_NAPOT | RX);
|
||||
|
||||
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region");
|
||||
|
||||
@@ -133,20 +119,20 @@ static void esp_cpu_configure_region_protection_rev_v3(void)
|
||||
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
} else {
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _iram_text_end;
|
||||
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(4, 7, SOC_IRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(5, 8, (int)&_iram_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(6, 9, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(4, 6, SOC_IRAM_LOW, CONDITIONAL_NONE);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(5, 7, SOC_IRAM_HIGH, PMP_TOR | CONDITIONAL_RWX);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(4, 6, SOC_IRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(5, 7, SOC_IRAM_HIGH, PMP_TOR | RWX);
|
||||
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _instruction_reserved_end;
|
||||
extern int _rodata_reserved_end;
|
||||
|
||||
@@ -198,30 +184,30 @@ static void esp_cpu_configure_region_protection_rev_v3(void)
|
||||
PMP_ENTRY_SET_CACHED_AND_UNCACHED(22, 26, page_aligned_drom_resv_end, PMP_TOR | R);
|
||||
|
||||
#else
|
||||
#if !BOOTLOADER_BUILD && CONFIG_SPIRAM
|
||||
#if CONFIG_SPIRAM
|
||||
const uint32_t pmpaddr10 = PMPADDR_NAPOT(SOC_EXTRAM_LOW, SOC_EXTRAM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(10, pmpaddr10, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(10, pmpaddr10, PMP_NAPOT | RWX);
|
||||
|
||||
const uint32_t pmpaddr11 = PMPADDR_NAPOT(CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_EXTRAM_LOW), CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_EXTRAM_HIGH));
|
||||
PMP_RESET_AND_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_EXTRAM_LOW < SOC_EXTRAM_HIGH, "Invalid I/D_EXTRAM region");
|
||||
#endif /* !BOOTLOADER_BUILD && CONFIG_SPIRAM */
|
||||
#endif /* CONFIG_SPIRAM */
|
||||
|
||||
const uint32_t pmpaddr12 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(12, pmpaddr12, PMP_NAPOT | CONDITIONAL_RX);
|
||||
PMP_RESET_AND_ENTRY_SET(12, pmpaddr12, PMP_NAPOT | RX);
|
||||
|
||||
const uint32_t pmpaddr13 = PMPADDR_NAPOT(CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_IROM_LOW), CACHE_LL_L2MEM_NON_CACHE_ADDR(SOC_IROM_HIGH));
|
||||
PMP_RESET_AND_ENTRY_SET(13, pmpaddr13, PMP_NAPOT | CONDITIONAL_RX);
|
||||
PMP_RESET_AND_ENTRY_SET(13, pmpaddr13, PMP_NAPOT | RX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
#endif
|
||||
|
||||
// 8. Peripheral addresses
|
||||
const uint32_t pmpaddr27 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(27, pmpaddr27, PMP_NAPOT | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_PERIPHERAL_REV_V3, pmpaddr27, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
|
||||
// 9. LP memory and LP peripherals
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _rtc_text_start;
|
||||
extern int _rtc_text_end;
|
||||
|
||||
@@ -239,35 +225,152 @@ static void esp_cpu_configure_region_protection_rev_v3(void)
|
||||
PMP_RESET_AND_ENTRY_SET(31, SOC_LP_PERIPH_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
const uint32_t pmpaddr28 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(28, pmpaddr28, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
PMP_RESET_AND_ENTRY_SET(28, pmpaddr28, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
|
||||
|
||||
PMP_RESET_AND_ENTRY_SET(29, SOC_LP_PERIPH_LOW, NONE);
|
||||
PMP_RESET_AND_ENTRY_SET(30, SOC_LP_PERIPH_HIGH, PMP_TOR | CONDITIONAL_RW);
|
||||
PMP_RESET_AND_ENTRY_SET(30, SOC_LP_PERIPH_HIGH, PMP_TOR | RW);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
// Default rev < 3.0 layout: flash 6-8, LP-RAM 9-12, peripheral 13. Used on a
|
||||
// v5.3/v5.4 bootloader (peripheral locked at 13) or when PSRAM protection is off.
|
||||
static void esp_cpu_configure_region_protection_rev_less_than_v3_default(void)
|
||||
{
|
||||
__attribute__((unused)) const unsigned NONE = PMP_L;
|
||||
__attribute__((unused)) const unsigned R = PMP_L | PMP_R;
|
||||
const unsigned RW = PMP_L | PMP_R | PMP_W;
|
||||
const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
__attribute__((unused)) const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
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));
|
||||
|
||||
// 5. I_Cache / D_Cache (flash)
|
||||
PMP_ENTRY_CFG_RESET(6);
|
||||
PMP_ENTRY_CFG_RESET(7);
|
||||
PMP_ENTRY_CFG_RESET(8);
|
||||
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
|
||||
// 5. I_Cache / D_Cache (flash)
|
||||
const uint32_t pmpaddr6 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
PMP_ENTRY_SET(6, pmpaddr6, PMP_NAPOT | RX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
#endif
|
||||
|
||||
// 6. LP memory
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _rtc_text_start;
|
||||
extern int _rtc_text_end;
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
* Bootloader might have given extra permissions and those won't be cleared
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(9);
|
||||
PMP_ENTRY_CFG_RESET(10);
|
||||
PMP_ENTRY_CFG_RESET(11);
|
||||
PMP_ENTRY_CFG_RESET(12);
|
||||
PMP_ENTRY_SET(9, SOC_RTC_IRAM_LOW, NONE);
|
||||
// First part of LP mem is reserved for RTC reserved mem (shared between bootloader and app)
|
||||
// as well as memory for ULP coprocessor
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_PMP_LP_CORE_RESERVE_MEM_EXEC
|
||||
PMP_ENTRY_SET(10, (int)&_rtc_text_start, PMP_TOR | RWX);
|
||||
#else
|
||||
PMP_ENTRY_SET(10, (int)&_rtc_text_start, PMP_TOR | RW);
|
||||
#endif
|
||||
PMP_ENTRY_SET(11, (int)&_rtc_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(12, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
const uint32_t pmpaddr9 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
|
||||
PMP_ENTRY_SET(9, pmpaddr9, PMP_NAPOT | RWX);
|
||||
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
|
||||
#endif
|
||||
|
||||
// 7. Peripheral addresses
|
||||
const uint32_t pmpaddr13 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_PERIPHERAL_REV_LESS_THAN_V3, pmpaddr13, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && CONFIG_SPIRAM_XIP_FROM_PSRAM && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
// PSRAM-protected rev < 3.0 layout: flash/ext-RAM 6-10, LP-RAM 11-14, peripheral
|
||||
// 15. Fits only when the bootloader left entry 13 free (v5.5+).
|
||||
static void esp_cpu_configure_region_protection_rev_less_than_v3_psram(void)
|
||||
{
|
||||
const unsigned NONE = PMP_L;
|
||||
const unsigned R = PMP_L | PMP_R;
|
||||
const unsigned RW = PMP_L | PMP_R | PMP_W;
|
||||
const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
__attribute__((unused)) const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
extern int _instruction_reserved_end;
|
||||
extern int _rodata_reserved_end;
|
||||
extern int _rtc_text_start;
|
||||
extern int _rtc_text_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));
|
||||
|
||||
// 5. I_Cache / D_Cache (flash) and external RAM
|
||||
PMP_ENTRY_CFG_RESET(6);
|
||||
PMP_ENTRY_CFG_RESET(7);
|
||||
PMP_ENTRY_CFG_RESET(8);
|
||||
PMP_ENTRY_CFG_RESET(9);
|
||||
PMP_ENTRY_SET(6, SOC_EXTRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET(7, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(8, page_aligned_irom_resv_end, PMP_TOR | RW);
|
||||
PMP_ENTRY_SET(9, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
|
||||
|
||||
const size_t available_psram_heap = esp_psram_get_heap_size_to_protect();
|
||||
PMP_ENTRY_CFG_RESET(10);
|
||||
PMP_ENTRY_SET(10, ESP_ALIGN_UP(page_aligned_drom_resv_end + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
|
||||
// 6. LP memory
|
||||
PMP_ENTRY_CFG_RESET(11);
|
||||
PMP_ENTRY_CFG_RESET(12);
|
||||
PMP_ENTRY_CFG_RESET(13);
|
||||
PMP_ENTRY_CFG_RESET(14);
|
||||
PMP_ENTRY_SET(11, SOC_RTC_IRAM_LOW, NONE);
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_PMP_LP_CORE_RESERVE_MEM_EXEC
|
||||
PMP_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RWX);
|
||||
#else
|
||||
PMP_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RW);
|
||||
#endif
|
||||
PMP_ENTRY_SET(13, (int)&_rtc_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(14, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
|
||||
|
||||
// 7. Peripheral addresses
|
||||
const uint32_t pmpaddr15 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_PERIPHERAL_REV_LESS_THAN_V3_SPIRAM_MEMPROT_EN, pmpaddr15, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void esp_cpu_configure_region_protection_rev_less_than_v3(void)
|
||||
{
|
||||
const unsigned NONE = PMP_L;
|
||||
__attribute__((unused)) const unsigned R = PMP_L | PMP_R;
|
||||
const unsigned RW = PMP_L | PMP_R | PMP_W;
|
||||
const unsigned RX = PMP_L | PMP_R | PMP_X;
|
||||
const unsigned RWX = PMP_L | PMP_R | PMP_W | PMP_X;
|
||||
|
||||
// 1. CPU Subsystem region - contains debug mode code and interrupt config registers
|
||||
const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
|
||||
PMP_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_CPU_SUBSYSTEM, pmpaddr0, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
|
||||
|
||||
// 2. CPU Peripherals
|
||||
const uint32_t pmpaddr1 = PMPADDR_NAPOT(CPU_PERIPH_LOW, CPU_PERIPH_HIGH);
|
||||
PMP_ENTRY_SET(1, pmpaddr1, PMP_NAPOT | RW);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_CPU_PERIPHERAL, pmpaddr1, PMP_NAPOT | RW);
|
||||
_Static_assert(CPU_PERIPH_LOW < CPU_PERIPH_HIGH, "Invalid CPU peripheral region");
|
||||
|
||||
// 3. I/D-ROM
|
||||
const uint32_t pmpaddr2 = PMPADDR_NAPOT(SOC_IROM_MASK_LOW, SOC_IROM_MASK_HIGH);
|
||||
PMP_ENTRY_SET(2, pmpaddr2, PMP_NAPOT | RX);
|
||||
PMP_RESET_AND_ENTRY_SET(PMP_ENTRY_ROM, pmpaddr2, PMP_NAPOT | RX);
|
||||
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region");
|
||||
|
||||
if (esp_cpu_dbgr_is_attached()) {
|
||||
@@ -279,7 +382,7 @@ static void esp_cpu_configure_region_protection_rev_less_than_v3(void)
|
||||
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 && !BOOTLOADER_BUILD
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP
|
||||
extern int _iram_text_end;
|
||||
// 4. IRAM and DRAM
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
@@ -293,85 +396,36 @@ static void esp_cpu_configure_region_protection_rev_less_than_v3(void)
|
||||
PMP_ENTRY_SET(5, SOC_DRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
// 4. IRAM and DRAM
|
||||
PMP_ENTRY_SET(3, SOC_IRAM_LOW, CONDITIONAL_NONE);
|
||||
PMP_ENTRY_SET(4, SOC_IRAM_HIGH, PMP_TOR | CONDITIONAL_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
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
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));
|
||||
__attribute__((unused)) const uint32_t page_aligned_drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end));
|
||||
|
||||
// 5. I_Cache / D_Cache (flash)
|
||||
#if CONFIG_SPIRAM_XIP_FROM_PSRAM && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
// We could have split CONFIG_SPIRAM_XIP_FROM_PSRAM into CONFIG_SPIRAM_FETCH_INSTRUCTIONS and CONFIG_SPIRAM_RODATA
|
||||
// but we don't have enough PMP entries to do so thus not allowing us finer control over the memory regions
|
||||
PMP_ENTRY_CFG_RESET(6);
|
||||
PMP_ENTRY_CFG_RESET(7);
|
||||
PMP_ENTRY_CFG_RESET(8);
|
||||
PMP_ENTRY_CFG_RESET(9);
|
||||
|
||||
PMP_ENTRY_SET(6, SOC_EXTRAM_LOW, NONE);
|
||||
PMP_ENTRY_SET(7, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(8, page_aligned_irom_resv_end, PMP_TOR | RW);
|
||||
PMP_ENTRY_SET(9, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
|
||||
|
||||
size_t available_psram_heap = esp_psram_get_heap_size_to_protect();
|
||||
PMP_ENTRY_CFG_RESET(10);
|
||||
PMP_ENTRY_SET(10, ESP_ALIGN_UP(page_aligned_drom_resv_end + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
|
||||
#else
|
||||
PMP_ENTRY_CFG_RESET(6);
|
||||
PMP_ENTRY_CFG_RESET(7);
|
||||
PMP_ENTRY_CFG_RESET(8);
|
||||
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);
|
||||
#endif /* CONFIG_SPIRAM_XIP_FROM_PSRAM && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION */
|
||||
#else
|
||||
// 5. I_Cache / D_Cache (flash)
|
||||
const uint32_t pmpaddr6 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH);
|
||||
PMP_ENTRY_SET(6, pmpaddr6, PMP_NAPOT | CONDITIONAL_RX);
|
||||
_Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I/D_Cache region");
|
||||
/* The flash, LP memory and peripheral entries have two layouts. The PSRAM
|
||||
* layout needs all 16 entries and only fits when the bootloader left entry 13
|
||||
* free; a v5.3/v5.4 bootloader locks the peripheral there, so fall back to the
|
||||
* default layout (no PSRAM protection) on those devices. */
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && CONFIG_SPIRAM_XIP_FROM_PSRAM && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
|
||||
if (!(PMP_ENTRY_CFG_READ(PMP_ENTRY_PERIPHERAL_REV_LESS_THAN_V3) & PMP_L)) {
|
||||
esp_cpu_configure_region_protection_rev_less_than_v3_psram();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 6. LP memory
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT && CONFIG_ESP_SYSTEM_MEMPROT_PMP && !BOOTLOADER_BUILD
|
||||
extern int _rtc_text_start;
|
||||
extern int _rtc_text_end;
|
||||
/* Reset the corresponding PMP config because PMP_ENTRY_SET only sets the given bits
|
||||
* Bootloader might have given extra permissions and those won't be cleared
|
||||
*/
|
||||
PMP_ENTRY_CFG_RESET(11);
|
||||
PMP_ENTRY_CFG_RESET(12);
|
||||
PMP_ENTRY_CFG_RESET(13);
|
||||
PMP_ENTRY_CFG_RESET(14);
|
||||
PMP_ENTRY_SET(11, SOC_RTC_IRAM_LOW, NONE);
|
||||
// First part of LP mem is reserved for RTC reserved mem (shared between bootloader and app)
|
||||
// as well as memory for ULP coprocessor
|
||||
#if CONFIG_ESP_SYSTEM_MEMPROT_PMP_LP_CORE_RESERVE_MEM_EXEC
|
||||
PMP_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RWX);
|
||||
#else
|
||||
PMP_ENTRY_SET(12, (int)&_rtc_text_start, PMP_TOR | RW);
|
||||
#endif
|
||||
PMP_ENTRY_SET(13, (int)&_rtc_text_end, PMP_TOR | RX);
|
||||
PMP_ENTRY_SET(14, SOC_RTC_IRAM_HIGH, PMP_TOR | RW);
|
||||
#else
|
||||
const uint32_t pmpaddr11 = PMPADDR_NAPOT(SOC_RTC_IRAM_LOW, SOC_RTC_IRAM_HIGH);
|
||||
PMP_ENTRY_SET(11, pmpaddr11, PMP_NAPOT | CONDITIONAL_RWX);
|
||||
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
|
||||
#endif
|
||||
|
||||
// 7. Peripheral addresses
|
||||
const uint32_t pmpaddr15 = PMPADDR_NAPOT(SOC_PERIPHERAL_LOW, SOC_PERIPHERAL_HIGH);
|
||||
PMP_ENTRY_SET(15, pmpaddr15, PMP_NAPOT | RW);
|
||||
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
|
||||
esp_cpu_configure_region_protection_rev_less_than_v3_default();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void esp_cpu_configure_valid_regions(void)
|
||||
{
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
esp_cpu_configure_region_protection_rev_v3();
|
||||
#else
|
||||
esp_cpu_configure_region_protection_rev_less_than_v3();
|
||||
#endif
|
||||
}
|
||||
#endif // BOOTLOADER_BUILD
|
||||
|
||||
void esp_cpu_configure_region_protection(void)
|
||||
{
|
||||
/* Notes on implementation:
|
||||
@@ -401,40 +455,14 @@ void esp_cpu_configure_region_protection(void)
|
||||
* c. External flash, External RAM, HP ROM, HP L2MEM (direct access)
|
||||
*/
|
||||
|
||||
/* There are 4 configuration scenarios for SRAM
|
||||
*
|
||||
* 1. Bootloader build:
|
||||
* - We cannot set the lock bit as we need to reconfigure it again for the application.
|
||||
* We configure PMP to cover entire valid IRAM and DRAM range.
|
||||
*
|
||||
* 2. 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 _iram_text_end and _data_start markers to set the boundaries.
|
||||
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
|
||||
*
|
||||
* 3. 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
|
||||
*
|
||||
* 4. 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
|
||||
*/
|
||||
//
|
||||
// Configure all the invalid address regions using PMA
|
||||
//
|
||||
/* 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 apply to M-mode, and a
|
||||
* locked one would survive into the application with no way to reconfigure
|
||||
* it until the next CPU reset). */
|
||||
esp_cpu_configure_invalid_regions();
|
||||
|
||||
//
|
||||
// Configure all the valid address regions using PMP
|
||||
//
|
||||
|
||||
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
|
||||
esp_cpu_configure_region_protection_rev_v3();
|
||||
#else
|
||||
esp_cpu_configure_region_protection_rev_less_than_v3();
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
esp_cpu_configure_valid_regions();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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-P4 PMP entry layout: a bootloader<->application ABI. An entry the
|
||||
* (non-updatable) bootloader locks cannot be reconfigured until CPU reset, so
|
||||
* the index of any entry a shipped bootloader locks is frozen.
|
||||
* Two incompatible layouts selected by chip revision (>= 3.0); binaries do not
|
||||
* mix, so each has its own index namespace. Entries 0-2 are shared.
|
||||
*
|
||||
* Locked by shipped bootloader generations:
|
||||
* rev < 3.0 v5.3/v5.4 : 0-2 (ROM), 13 (periph); v5.5..v6.1 : 0-2, 15
|
||||
* rev >= 3.0 v6.0/v6.1 : 0-3 (ROM cached+uncached), 27 (periph)
|
||||
* >= v6.2 : none
|
||||
*/
|
||||
#define PMP_ENTRY_CPU_SUBSYSTEM 0 /* NAPOT RW, both layouts */
|
||||
#define PMP_ENTRY_CPU_PERIPHERAL 1 /* NAPOT RW, both layouts */
|
||||
#define PMP_ENTRY_ROM 2 /* NAPOT RX, both layouts */
|
||||
|
||||
/* rev < 3.0 has two application layouts, chosen at runtime by probing which
|
||||
* peripheral entry the bootloader locked (see cpu_region_protect.c):
|
||||
* - default : SRAM/flash 3-8, LP-RAM 9-12, peripheral 13; 14-15 free.
|
||||
* - PSRAM-protected : SRAM/flash/ext-RAM 3-10, LP-RAM 11-14, peripheral 15.
|
||||
* The PSRAM layout is taken only on v5.5+ bootloaders (which leave 13 free and
|
||||
* lock the peripheral at 15); a v5.3/v5.4 bootloader locks the peripheral at 13,
|
||||
* forcing the default layout. Entries 13 and 15 are both peripheral homes locked
|
||||
* by shipped bootloaders and must never be repurposed for a non-peripheral region. */
|
||||
#define PMP_ENTRY_PERIPHERAL_REV_LESS_THAN_V3 13 /* NAPOT RW, default layout */
|
||||
#define PMP_ENTRY_PERIPHERAL_REV_LESS_THAN_V3_SPIRAM_MEMPROT_EN 15 /* NAPOT RW, PSRAM layout */
|
||||
|
||||
/* rev >= 3.0: 4..26 (SRAM/ext-RAM/flash cached+uncached aliases) and 28..31
|
||||
* (LP) are application-owned; their indices shift with the memprot config, so
|
||||
* they are programmed by plain index in cpu_region_protect.c, not named here. */
|
||||
#define PMP_ENTRY_ROM_UNCACHED_REV_V3 3 /* NAPOT RX */
|
||||
#define PMP_ENTRY_PERIPHERAL_REV_V3 27 /* NAPOT RW */
|
||||
|
||||
ESP_STATIC_ASSERT(PMP_ENTRY_CPU_SUBSYSTEM == 0 && PMP_ENTRY_CPU_PERIPHERAL == 1
|
||||
&& PMP_ENTRY_ROM == 2,
|
||||
"Shared entries are a frozen ABI and must never move");
|
||||
ESP_STATIC_ASSERT(PMP_ENTRY_PERIPHERAL_REV_LESS_THAN_V3 == 13
|
||||
&& PMP_ENTRY_PERIPHERAL_REV_LESS_THAN_V3_SPIRAM_MEMPROT_EN == 15,
|
||||
"rev < 3.0 peripheral entries are locked by shipped bootloaders and must never move");
|
||||
ESP_STATIC_ASSERT(PMP_ENTRY_ROM_UNCACHED_REV_V3 == 3 && PMP_ENTRY_PERIPHERAL_REV_V3 == 27,
|
||||
"rev >= 3.0 entries locked by shipped bootloaders are a frozen ABI and must never move");
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user