Merge branch 'esp32c2/IDRAM_PMP_split' into 'master'

esp32c2: Enable IRAM/DRAM split using PMP

Closes IDF-3837

See merge request espressif/esp-idf!18156
This commit is contained in:
Mahavir Jain 2022-05-26 00:47:49 +08:00
commit c6e2ae76a9
4 changed files with 82 additions and 17 deletions

View File

@ -5,6 +5,29 @@
*/
#include <assert.h>
#include "esp_cpu.h"
#include "sdkconfig.h"
#if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD
extern int _iram_end;
extern int _data_start;
#define IRAM_END (int)&_iram_end
#define DRAM_START (int)&_data_start
#else
#define IRAM_END SOC_DIRAM_IRAM_HIGH
#define DRAM_START SOC_DIRAM_DRAM_LOW
#endif
#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
#else
// With L bit set
#define CONDITIONAL_NONE NONE
#define CONDITIONAL_RX RX
#define CONDITIONAL_RW RW
#endif
void esp_cpu_configure_region_protection(void)
{
@ -19,47 +42,71 @@ void esp_cpu_configure_region_protection(void)
* 3) 3-15 PMPADDR entries be hardcoded to fixed value, 0-2 PMPADDR be programmed to split ID SRAM
* as IRAM/DRAM. All PMPCFG entryies be available.
*
* 4) Ideally, PMPADDR 0-2 entries should be configured twice, once during bootloader startup and another during app startup.
* However, the CPU currently always executes in machine mode and to enforce these permissions in machine mode, we need
* to set the Lock (L) bit but if set once, it cannot be reconfigured. So, we only configure 0-2 PMPADDR during app startup.
*/
const unsigned NONE = PMP_L ;
const unsigned NONE = PMP_L ;
const unsigned R = PMP_L | PMP_R;
const unsigned X = PMP_L | PMP_X;
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;
/* There are 3 configuration scenarios for PMPADDR 0-2
*
* 1. Bootloader build:
* - We cannot set the lock bit as we need to reconfigure it again for the application.
* We configure PMPADDR 0-1 to cover entire valid IRAM range and PMPADDR 2-3 to cover entire valid DRAM range.
*
* 2. Application build with CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT enabled
* - We split the SRAM into IRAM and DRAM such that IRAM region cannot be accessed via DBUS
* and DRAM region cannot be accessed via IBUS. We use _iram_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_PMP_IDRAM_SPLIT 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 PMPADDR 0-1 to cover entire valid IRAM range and PMPADDR 2-3 to cover entire DRAM region.
* We also lock these entries so the R/W/X permissions are enforced even for machine mode
*
* PMPADDR 3-15 are hard-coded and are appicable to both, bootloader and application. So we configure and lock
* these during BOOTLOADER build itself. During application build, reconfiguration of these PMPADDR entries
* are silently ignored by the CPU
*/
// 1. IRAM
PMP_ENTRY_SET(0,SOC_DIRAM_IRAM_LOW, NONE);
PMP_ENTRY_SET(1,SOC_DIRAM_IRAM_HIGH, PMP_TOR|RWX); //TODO IRAM/DRAM spilt address
PMP_ENTRY_SET(0, SOC_DIRAM_IRAM_LOW, CONDITIONAL_NONE);
PMP_ENTRY_SET(1, IRAM_END, PMP_TOR | CONDITIONAL_RX);
// 2. DRAM
PMP_ENTRY_SET(2,SOC_DIRAM_DRAM_LOW, NONE); //TODO IRAM/DRAM spilt address
PMP_ENTRY_CFG_SET(3,PMP_TOR|RW);
PMP_ENTRY_SET(2, DRAM_START, CONDITIONAL_NONE);
PMP_ENTRY_CFG_SET(3, PMP_TOR | CONDITIONAL_RW);
// 3. Debug region
PMP_ENTRY_CFG_SET(4,PMP_NAPOT|RWX);
PMP_ENTRY_CFG_SET(4, PMP_NAPOT | RWX);
// 4. DROM (flash dcache)
PMP_ENTRY_CFG_SET(5,PMP_NAPOT|R);
PMP_ENTRY_CFG_SET(5, PMP_NAPOT | R);
// 5. DROM_MASK
PMP_ENTRY_CFG_SET(6,NONE);
PMP_ENTRY_CFG_SET(7,PMP_TOR|R);
PMP_ENTRY_CFG_SET(6, NONE);
PMP_ENTRY_CFG_SET(7, PMP_TOR | R);
// 6. IROM_MASK
PMP_ENTRY_CFG_SET(8,NONE);
PMP_ENTRY_CFG_SET(9,PMP_TOR|RX);
PMP_ENTRY_CFG_SET(8, NONE);
PMP_ENTRY_CFG_SET(9, PMP_TOR | RX);
// 7. IROM (flash icache)
PMP_ENTRY_CFG_SET(10,PMP_NAPOT|RX);
PMP_ENTRY_CFG_SET(10, PMP_NAPOT | RX);
// 8. Peripheral addresses
PMP_ENTRY_CFG_SET(11,PMP_NAPOT|RW);
PMP_ENTRY_CFG_SET(11, PMP_NAPOT | RW);
// 9. SRAM (used as ICache)
PMP_ENTRY_CFG_SET(12,PMP_NAPOT|X);
PMP_ENTRY_CFG_SET(12, PMP_NAPOT | X);
// 10. no access to any address below(0x0-0xFFFF_FFFF)
PMP_ENTRY_CFG_SET(13,PMP_NA4|NONE);// last 4 bytes(0xFFFFFFFC)
PMP_ENTRY_CFG_SET(14,NONE);
PMP_ENTRY_CFG_SET(15,PMP_TOR|NONE);
PMP_ENTRY_CFG_SET(13, PMP_NA4 | NONE);// last 4 bytes(0xFFFFFFFC)
PMP_ENTRY_CFG_SET(14, NONE);
PMP_ENTRY_CFG_SET(15, PMP_TOR | NONE);
}

View File

@ -117,6 +117,18 @@ menu "ESP System Settings"
menu "Memory protection"
config ESP_SYSTEM_PMP_IDRAM_SPLIT
bool "Enable IRAM/DRAM split protection"
depends on SOC_CPU_IDRAM_SPLIT_USING_PMP
default "y"
help
If enabled, the CPU watches all the memory access and raises an exception in case
of any memory violation. This feature automatically splits
the SRAM memory, using PMP, into data and instruction segments and sets Read/Execute permissions
for the instruction part (below given splitting address) and Read/Write permissions
for the data part (above the splitting address). The memory protection is effective
on all access through the IRAM0 and DRAM0 buses.
config ESP_SYSTEM_MEMPROT_DEPCHECK
bool
default y if IDF_TARGET_ESP32S2

View File

@ -151,6 +151,10 @@ config SOC_CPU_WATCHPOINT_SIZE
hex
default 0x80000000
config SOC_CPU_IDRAM_SPLIT_USING_PMP
bool
default y
config SOC_GDMA_GROUPS
int
default 1

View File

@ -80,6 +80,8 @@
#define SOC_CPU_WATCHPOINT_SIZE 0x80000000 // bytes
#define SOC_CPU_IDRAM_SPLIT_USING_PMP 1
/*-------------------------- GDMA CAPS -------------------------------------*/
#define SOC_GDMA_GROUPS (1U) // Number of GDMA groups
#define SOC_GDMA_PAIRS_PER_GROUP (1U) // Number of GDMA pairs in each group