feat(cpu_region_protect): Extend PMP memprot for ESP32-P4 V3

This commit is contained in:
harshal.patil
2026-05-08 12:43:26 +05:30
parent 2ff7df235a
commit 8121f66ec3
9 changed files with 590 additions and 105 deletions
@@ -15,6 +15,9 @@
#include "esp_private/esp_psram_extram.h" #include "esp_private/esp_psram_extram.h"
#endif /* CONFIG_SPIRAM */ #endif /* CONFIG_SPIRAM */
#include "soc/chip_revision.h"
#include "hal/config.h"
#ifdef BOOTLOADER_BUILD #ifdef BOOTLOADER_BUILD
// Without L bit set // Without L bit set
#define CONDITIONAL_NONE 0x0 #define CONDITIONAL_NONE 0x0
@@ -82,70 +85,160 @@ static void esp_cpu_configure_invalid_regions(void)
PMA_RESET_AND_ENTRY_SET_TOR(15, UINT32_MAX, PMA_TOR | PMA_NONE); PMA_RESET_AND_ENTRY_SET_TOR(15, UINT32_MAX, PMA_TOR | PMA_NONE);
} }
void esp_cpu_configure_region_protection(void) #if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
{ // Helper macro to set both cached and non-cached PMP entries with the same permissions
/* Notes on implementation: #define PMP_ENTRY_SET_CACHED_AND_UNCACHED(cached_entry, non_cached_entry, addr, perm) \
* do { \
* 1) Note: ESP32-P4 CPU support overlapping PMP regions, configuration is based on static priority PMP_RESET_AND_ENTRY_SET(cached_entry, addr, perm); \
* feature (lowest numbered entry has highest priority). PMP_RESET_AND_ENTRY_SET(non_cached_entry, CACHE_LL_L2MEM_NON_CACHE_ADDR(addr), perm); \
* } while(0)
* 2) ESP32-P4 supports 16 PMA regions so we use this feature to block the invalid address ranges.
* However the entries are not sufficient to block all reserved memory ranges and the excluded sections are:
* a. Region between LP ROM and LP SRAM
* b. Region between LP peripherals and External flash (direct access)
* c. Region between External flash (direct access) and External RAM (direct access)
* d. Region between External RAM (direct access) and HP ROM (direct access)
* e. Region between HP ROM (direct access) and HP L2MEM (direct access)
*
* 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.
*
* 5) No explicit permission specified in PMP (default all permissions) for following regions due to
* limited entries:
* a. External RAM
* b. LP ROM, LP Peripherals, LP SRAM
* c. External flash, External RAM, HP ROM, HP L2MEM (direct access)
*/
/* There are 4 configuration scenarios for SRAM static void esp_cpu_configure_region_protection_rev_v3(void)
* {
* 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_PMP_IDRAM_SPLIT 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_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 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; const unsigned NONE = PMP_L;
__attribute__((unused)) const unsigned R = PMP_L | PMP_R; __attribute__((unused)) const unsigned R = PMP_L | PMP_R;
const unsigned RW = PMP_L | PMP_R | PMP_W; const unsigned RW = PMP_L | PMP_R | PMP_W;
const unsigned RX = PMP_L | PMP_R | PMP_X; const unsigned RX = PMP_L | PMP_R | PMP_X;
const unsigned RWX = PMP_L | PMP_R | PMP_W | 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
// Configure all the invalid address regions using PMA const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
// PMP_RESET_AND_ENTRY_SET(0, pmpaddr0, PMP_NAPOT | RW);
esp_cpu_configure_invalid_regions(); _Static_assert(SOC_CPU_SUBSYSTEM_LOW < SOC_CPU_SUBSYSTEM_HIGH, "Invalid CPU subsystem region");
// // 2. HP-CPU TCM
// Configure all the valid address regions using PMP // The default memory permissions are RWX and TCM should be RWX, so we can skip configuring it
//
// 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);
_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);
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);
_Static_assert(SOC_IROM_MASK_LOW < SOC_IROM_MASK_HIGH, "Invalid I/D-ROM region");
// 5. IRAM and DRAM
if (esp_cpu_dbgr_is_attached()) {
// Anti-FI check that cpu is really in ocd mode
ESP_FAULT_ASSERT(esp_cpu_dbgr_is_attached());
PMP_ENTRY_SET_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");
} else {
#if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD
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);
_Static_assert(SOC_IRAM_LOW < SOC_IRAM_HIGH, "Invalid RAM region");
#endif
}
#if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !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));
// 6. I_EXTRAM / D_EXTRAM (SPIRAM)
#if CONFIG_SPIRAM && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION
const size_t available_psram_heap = esp_psram_get_heap_size_to_protect();
PMP_ENTRY_SET_CACHED_AND_UNCACHED(10, 15, SOC_EXTRAM_LOW, NONE);
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA
PMP_ENTRY_SET_CACHED_AND_UNCACHED(11, 16, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
PMP_ENTRY_SET_CACHED_AND_UNCACHED(12, 17, page_aligned_irom_resv_end, PMP_TOR | RW);
PMP_ENTRY_SET_CACHED_AND_UNCACHED(13, 18, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
PMP_ENTRY_SET_CACHED_AND_UNCACHED(14, 19, ALIGN_UP((uint32_t)(&_rodata_reserved_end) + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
#elif CONFIG_SPIRAM_FETCH_INSTRUCTIONS
PMP_ENTRY_SET_CACHED_AND_UNCACHED(11, 16, (uint32_t)(&_instruction_reserved_end), PMP_TOR | RX);
PMP_ENTRY_SET_CACHED_AND_UNCACHED(12, 17, page_aligned_irom_resv_end, PMP_TOR | RW);
PMP_ENTRY_SET_CACHED_AND_UNCACHED(13, 18, ALIGN_UP(page_aligned_irom_resv_end + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
#elif CONFIG_SPIRAM_RODATA
PMP_ENTRY_SET_CACHED_AND_UNCACHED(11, 16, (uint32_t)(&_rodata_reserved_end), PMP_TOR | R);
PMP_ENTRY_SET_CACHED_AND_UNCACHED(12, 17, ALIGN_UP((uint32_t)(&_rodata_reserved_end) + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
#else
PMP_ENTRY_SET_CACHED_AND_UNCACHED(11, 16, ALIGN_UP(SOC_EXTRAM_LOW + available_psram_heap, SOC_CPU_PMP_REGION_GRANULARITY), PMP_TOR | RW);
#endif
#endif /* CONFIG_SPIRAM && CONFIG_SPIRAM_PRE_CONFIGURE_MEMORY_PROTECTION */
// ESP32-P4 V3's 24th PMP entry cannot be used as a TOR entry // DIG-752
// 7. I_Cache / D_Cache (flash)
PMP_ENTRY_SET_CACHED_AND_UNCACHED(20, 24, SOC_IROM_LOW, NONE);
PMP_ENTRY_SET_CACHED_AND_UNCACHED(21, 25, page_aligned_irom_resv_end, PMP_TOR | RX);
PMP_ENTRY_SET_CACHED_AND_UNCACHED(22, 26, page_aligned_drom_resv_end, PMP_TOR | R);
#else
#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);
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);
_Static_assert(SOC_EXTRAM_LOW < SOC_EXTRAM_HIGH, "Invalid I/D_EXTRAM region");
#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);
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);
_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);
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
// 9. LP memory
#if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD
extern int _rtc_text_start;
extern int _rtc_text_end;
// ESP32-P4 V3's 28th PMP entry cannot be used as a TOR entry // DIG-752
PMP_RESET_AND_ENTRY_SET(28, 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_PMP_LP_CORE_RESERVE_MEM_EXECUTABLE
PMP_RESET_AND_ENTRY_SET(29, (int)&_rtc_text_start, PMP_TOR | RWX);
#else
PMP_RESET_AND_ENTRY_SET(29, (int)&_rtc_text_start, PMP_TOR | RW);
#endif
PMP_RESET_AND_ENTRY_SET(30, (int)&_rtc_text_end, PMP_TOR | RX);
PMP_RESET_AND_ENTRY_SET(31, SOC_RTC_IRAM_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);
_Static_assert(SOC_RTC_IRAM_LOW < SOC_RTC_IRAM_HIGH, "Invalid RTC IRAM region");
#endif
}
#else
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 // 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); const uint32_t pmpaddr0 = PMPADDR_NAPOT(SOC_CPU_SUBSYSTEM_LOW, SOC_CPU_SUBSYSTEM_HIGH);
@@ -262,3 +355,71 @@ void esp_cpu_configure_region_protection(void)
PMP_ENTRY_SET(15, pmpaddr15, PMP_NAPOT | RW); PMP_ENTRY_SET(15, pmpaddr15, PMP_NAPOT | RW);
_Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region"); _Static_assert(SOC_PERIPHERAL_LOW < SOC_PERIPHERAL_HIGH, "Invalid peripheral region");
} }
#endif
void esp_cpu_configure_region_protection(void)
{
/* Notes on implementation:
*
* 1) Note: ESP32-P4 CPU support overlapping PMP regions, configuration is based on static priority
* feature (lowest numbered entry has highest priority).
*
* 2) ESP32-P4 supports 16 PMA regions so we use this feature to block the invalid address ranges.
* However the entries are not sufficient to block all reserved memory ranges and the excluded sections are:
* a. Region between LP ROM and LP SRAM
* b. Region between LP peripherals and External flash (direct access)
* c. Region between External flash (direct access) and External RAM (direct access)
* d. Region between External RAM (direct access) and HP ROM (direct access)
* e. Region between HP ROM (direct access) and HP L2MEM (direct access)
*
* 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.
*
* 5) For ESP32-P4's versions less than v3, no explicit permissions are specified in PMP (default all permissions) for following regions:
* limited entries:
* a. External RAM
* b. LP ROM, LP Peripherals, LP SRAM
* 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_PMP_IDRAM_SPLIT 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_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 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
//
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();
#endif
}
@@ -16,4 +16,4 @@ CONFIG_PARTITION_TABLE_OFFSET=0xF000
# Increasing TEE I/DRAM size # Increasing TEE I/DRAM size
CONFIG_SECURE_TEE_IRAM_SIZE=0x8800 CONFIG_SECURE_TEE_IRAM_SIZE=0x8800
CONFIG_SECURE_TEE_DRAM_SIZE=0x4c00 CONFIG_SECURE_TEE_DRAM_SIZE=0x5800
+16 -4
View File
@@ -123,19 +123,31 @@ extern "C" {
*/ */
#define PMP_ENTRY_SET(ENTRY, ADDR, CFG) do { \ #define PMP_ENTRY_SET(ENTRY, ADDR, CFG) do { \
RV_WRITE_CSR((CSR_PMPADDR0) + (ENTRY), (ADDR) >> (PMP_SHIFT)); \ RV_WRITE_CSR((CSR_PMPADDR0) + (ENTRY), (ADDR) >> (PMP_SHIFT)); \
RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8); \ PMP_ENTRY_CFG_SET(ENTRY, CFG); \
} while(0) } while(0)
/*Only set PMPCFG entries*/ /*Only set PMPCFG entries*/
#define PMP_ENTRY_CFG_SET(ENTRY, CFG) do {\ #define PMP_ENTRY_CFG_SET(ENTRY, CFG) \
RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8); \ RV_SET_CSR((CSR_PMPCFG0) + (ENTRY)/4, ((CFG)&0xFF) << (ENTRY%4)*8)
} while(0)
/*Reset all permissions of a particular PMPCFG entry*/ /*Reset all permissions of a particular PMPCFG entry*/
#define PMP_ENTRY_CFG_RESET(ENTRY) do {\ #define PMP_ENTRY_CFG_RESET(ENTRY) do {\
RV_WRITE_CSR((CSR_PMPADDR0) + (ENTRY), 0); \
RV_CLEAR_CSR((CSR_PMPCFG0) + (ENTRY)/4, (0xFF) << (ENTRY%4)*8); \ RV_CLEAR_CSR((CSR_PMPCFG0) + (ENTRY)/4, (0xFF) << (ENTRY%4)*8); \
} while(0) } while(0)
/*Read configuration of a particular PMPCFG entry*/
#define PMP_ENTRY_CFG_READ(ENTRY) \
((RV_READ_CSR((CSR_PMPCFG0) + (ENTRY)/4) >> ((ENTRY%4)*8)) & 0xFF)
#define PMP_ENTRY_ADDR_READ(ENTRY) \
(RV_READ_CSR((CSR_PMPADDR0) + (ENTRY)) << (PMP_SHIFT))
#define PMP_RESET_AND_ENTRY_SET(ENTRY, ADDR, CFG) do {\
PMP_ENTRY_CFG_RESET(ENTRY); \
PMP_ENTRY_SET(ENTRY, ADDR, CFG); \
} while(0)
/*Reset all permissions of a particular PMACFG entry*/ /*Reset all permissions of a particular PMACFG entry*/
#define PMA_ENTRY_CFG_RESET(ENTRY) do {\ #define PMA_ENTRY_CFG_RESET(ENTRY) do {\
RV_WRITE_CSR((CSR_PMACFG0) + (ENTRY) , 0); \ RV_WRITE_CSR((CSR_PMACFG0) + (ENTRY) , 0); \
@@ -2,4 +2,4 @@ CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG=y
CONFIG_BOOTLOADER_LOG_LEVEL=4 CONFIG_BOOTLOADER_LOG_LEVEL=4
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
# Bootloader overlapped with partition table after we enabled LOGD for bootloader. Move the partition table a bit to fix the issue on CI. # Bootloader overlapped with partition table after we enabled LOGD for bootloader. Move the partition table a bit to fix the issue on CI.
CONFIG_PARTITION_TABLE_OFFSET=0x9000 CONFIG_PARTITION_TABLE_OFFSET=0xA000
@@ -1,10 +1,12 @@
/* /*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#pragma once #pragma once
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -26,12 +28,25 @@ void test_iram_reg2_write_violation(void);
void test_iram_reg3_write_violation(void); void test_iram_reg3_write_violation(void);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
void test_non_cache_iram_reg1_write_violation(void);
void test_non_cache_iram_reg2_write_violation(void);
void test_non_cache_iram_reg3_write_violation(void);
void test_non_cache_iram_reg4_write_violation(void);
#endif
void test_iram_reg4_write_violation(void); void test_iram_reg4_write_violation(void);
void test_dram_reg1_execute_violation(void); void test_dram_reg1_execute_violation(void);
void test_dram_reg2_execute_violation(void); void test_dram_reg2_execute_violation(void);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
void test_non_cache_dram_reg1_execute_violation(void);
void test_non_cache_dram_reg2_execute_violation(void);
#endif
void test_rtc_fast_reg1_execute_violation(void); void test_rtc_fast_reg1_execute_violation(void);
void test_rtc_fast_reg2_execute_violation(void); void test_rtc_fast_reg2_execute_violation(void);
@@ -52,6 +67,15 @@ void test_drom_reg_write_violation(void);
void test_drom_reg_execute_violation(void); void test_drom_reg_execute_violation(void);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
void test_non_cache_irom_reg_write_violation(void);
void test_non_cache_drom_reg_write_violation(void);
void test_non_cache_drom_reg_execute_violation(void);
void test_non_cache_spiram_xip_irom_alignment_reg_execute_violation(void);
void test_non_cache_spiram_xip_drom_alignment_reg_execute_violation(void);
#endif
void test_invalid_memory_region_write_violation(void); void test_invalid_memory_region_write_violation(void);
void test_invalid_memory_region_execute_violation(void); void test_invalid_memory_region_execute_violation(void);
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -146,6 +146,13 @@ void app_main(void)
HANDLE_TEST(test_name, test_iram_reg2_write_violation); HANDLE_TEST(test_name, test_iram_reg2_write_violation);
HANDLE_TEST(test_name, test_iram_reg3_write_violation); HANDLE_TEST(test_name, test_iram_reg3_write_violation);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
HANDLE_TEST(test_name, test_non_cache_iram_reg1_write_violation);
HANDLE_TEST(test_name, test_non_cache_iram_reg2_write_violation);
HANDLE_TEST(test_name, test_non_cache_iram_reg3_write_violation);
HANDLE_TEST(test_name, test_non_cache_iram_reg4_write_violation);
#endif
/* TODO: IDF-6820: ESP32-S2 -> Fix incorrect panic reason: Unhandled debug exception */ /* TODO: IDF-6820: ESP32-S2 -> Fix incorrect panic reason: Unhandled debug exception */
HANDLE_TEST(test_name, test_iram_reg4_write_violation); HANDLE_TEST(test_name, test_iram_reg4_write_violation);
@@ -154,6 +161,11 @@ void app_main(void)
HANDLE_TEST(test_name, test_dram_reg2_execute_violation); HANDLE_TEST(test_name, test_dram_reg2_execute_violation);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
HANDLE_TEST(test_name, test_non_cache_dram_reg1_execute_violation);
HANDLE_TEST(test_name, test_non_cache_dram_reg2_execute_violation);
#endif
#if CONFIG_SOC_RTC_FAST_MEM_SUPPORTED #if CONFIG_SOC_RTC_FAST_MEM_SUPPORTED
HANDLE_TEST(test_name, test_rtc_fast_reg1_execute_violation); HANDLE_TEST(test_name, test_rtc_fast_reg1_execute_violation);
HANDLE_TEST(test_name, test_rtc_fast_reg2_execute_violation); HANDLE_TEST(test_name, test_rtc_fast_reg2_execute_violation);
@@ -178,13 +190,26 @@ void app_main(void)
HANDLE_TEST(test_name, test_irom_reg_write_violation); HANDLE_TEST(test_name, test_irom_reg_write_violation);
HANDLE_TEST(test_name, test_drom_reg_write_violation); HANDLE_TEST(test_name, test_drom_reg_write_violation);
HANDLE_TEST(test_name, test_drom_reg_execute_violation); HANDLE_TEST(test_name, test_drom_reg_execute_violation);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
HANDLE_TEST(test_name, test_non_cache_irom_reg_write_violation);
HANDLE_TEST(test_name, test_non_cache_drom_reg_write_violation);
HANDLE_TEST(test_name, test_non_cache_drom_reg_execute_violation);
#endif
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED
HANDLE_TEST(test_name, test_spiram_xip_irom_alignment_reg_execute_violation); HANDLE_TEST(test_name, test_spiram_xip_irom_alignment_reg_execute_violation);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
HANDLE_TEST(test_name, test_non_cache_spiram_xip_irom_alignment_reg_execute_violation);
#endif
#endif #endif
#endif #endif
#if CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2
HANDLE_TEST(test_name, test_spiram_xip_drom_alignment_reg_execute_violation); HANDLE_TEST(test_name, test_spiram_xip_drom_alignment_reg_execute_violation);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
HANDLE_TEST(test_name, test_non_cache_spiram_xip_drom_alignment_reg_execute_violation);
#endif
#endif #endif
#ifdef CONFIG_SOC_CPU_HAS_PMA #ifdef CONFIG_SOC_CPU_HAS_PMA
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -18,6 +18,10 @@
#include "test_memprot.h" #include "test_memprot.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#include "hal/cache_ll.h"
#endif
#define RND_VAL (0xA5A5A5A5) #define RND_VAL (0xA5A5A5A5)
#define SPIN_ITER (16) #define SPIN_ITER (16)
@@ -112,6 +116,40 @@ void test_iram_reg4_write_violation(void)
*test_addr = RND_VAL; *test_addr = RND_VAL;
} }
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
/* IRAM: I/DCACHE boundary region */
void test_non_cache_iram_reg1_write_violation(void)
{
uint32_t *test_addr = (uint32_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR((uint32_t)(&_iram_start) - 0x04));
printf("IRAM: Non-cacheable Write operation | Address: %p\n", test_addr);
*test_addr = RND_VAL;
}
/* IRAM: Interrupt vector table region */
void test_non_cache_iram_reg2_write_violation(void)
{
uint32_t *test_addr = (uint32_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR((uint32_t)(&_iram_text_start) - 0x04));
printf("IRAM: Non-cacheable Write operation | Address: %p\n", test_addr);
*test_addr = RND_VAL;
}
/* IRAM: Text (and data) region */
void test_non_cache_iram_reg3_write_violation(void)
{
uint32_t *test_addr = (uint32_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR((uint32_t)(&_iram_text_end) - 0x04));
printf("IRAM: Non-cacheable Write operation | Address: %p\n", test_addr);
*test_addr = RND_VAL;
}
/* IRAM: Through the data bus */
void test_non_cache_iram_reg4_write_violation(void)
{
uint32_t *test_addr = (uint32_t *)MAP_IRAM_TO_DRAM((uint32_t)&_iram_text_end - 0x04);
printf("IRAM: Write operation | Address: %p\n", test_addr);
*test_addr = RND_VAL;
}
#endif /* SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE */
/* ---------------------------------------------------- DRAM Violation Checks ---------------------------------------------------- */ /* ---------------------------------------------------- DRAM Violation Checks ---------------------------------------------------- */
static void foo_d(void) static void foo_d(void)
@@ -144,6 +182,30 @@ void test_dram_reg2_execute_violation(void)
run_function(test_addr); run_function(test_addr);
} }
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
/* DRAM: Data region (DRAM_ATTR tagged) */
void test_non_cache_dram_reg1_execute_violation(void)
{
memcpy(&s_dram_buf, &foo_d, sizeof(s_dram_buf));
void *test_addr = (void *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(&s_dram_buf));
printf("DRAM: Non-cacheable Execute operation | Address: %p\n", &s_dram_buf);
run_function(test_addr);
}
/* DRAM: Heap region */
void test_non_cache_dram_reg2_execute_violation(void)
{
uint8_t *instr = calloc(1024, sizeof(uint8_t));
assert(instr != NULL);
printf("DRAM: Non-cacheable Execute operation | Address: %p\n", instr);
memcpy(instr, &foo_d, 1024);
void *test_addr = (void *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(instr));
run_function(test_addr);
}
#endif /* SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE */
/* ---------------------------------------------------- RTC Violation Checks ---------------------------------------------------- */ /* ---------------------------------------------------- RTC Violation Checks ---------------------------------------------------- */
#if CONFIG_SOC_RTC_FAST_MEM_SUPPORTED #if CONFIG_SOC_RTC_FAST_MEM_SUPPORTED
@@ -251,6 +313,30 @@ void test_drom_reg_execute_violation(void)
run_function(test_addr); run_function(test_addr);
} }
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
void test_non_cache_irom_reg_write_violation(void)
{
extern int _instruction_reserved_end;
uint32_t *test_addr = (uint32_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR((uint32_t)(&_instruction_reserved_end - 0x100)));
printf("Flash (IROM): Non-cacheable Write operation | Address: %p\n", test_addr);
*test_addr = RND_VAL;
}
void test_non_cache_drom_reg_write_violation(void)
{
uint32_t *test_addr = (uint32_t *)CACHE_LL_L2MEM_NON_CACHE_ADDR(((uint32_t)(foo_buf)));
printf("Flash (DROM): Non-cacheable Write operation | Address: %p\n", test_addr);
*test_addr = RND_VAL;
}
void test_non_cache_drom_reg_execute_violation(void)
{
void *test_addr = (void *)CACHE_LL_L2MEM_NON_CACHE_ADDR((void *)foo_buf);
printf("Flash (DROM): Non-cacheable Execute operation | Address: %p\n", test_addr);
run_function(test_addr);
}
#endif
// Check if the memory alignment gaps added to the heap are correctly configured // Check if the memory alignment gaps added to the heap are correctly configured
#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED
void test_spiram_xip_irom_alignment_reg_execute_violation(void) void test_spiram_xip_irom_alignment_reg_execute_violation(void)
@@ -264,6 +350,20 @@ void test_spiram_xip_irom_alignment_reg_execute_violation(void)
printf("SPIRAM (IROM): IROM alignment gap not added into heap\n"); printf("SPIRAM (IROM): IROM alignment gap not added into heap\n");
} }
} }
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
void test_non_cache_spiram_xip_irom_alignment_reg_execute_violation(void)
{
extern int _instruction_reserved_end;
if (ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_instruction_reserved_end)) - (uint32_t)(&_instruction_reserved_end) >= 4) {
void *test_addr = (void *)CACHE_LL_L2MEM_NON_CACHE_ADDR(&_instruction_reserved_end + 1);
printf("SPIRAM (IROM): Non-cacheable Execute operation | Address: %p\n", test_addr);
run_function(test_addr);
} else {
printf("SPIRAM (IROM): Non-cacheable IROM alignment gap not added into heap\n");
}
}
#endif
#endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED */ #endif /* CONFIG_SPIRAM_FETCH_INSTRUCTIONS && SOC_MMU_DI_VADDR_SHARED */
#endif #endif
@@ -279,6 +379,20 @@ void test_spiram_xip_drom_alignment_reg_execute_violation(void)
printf("SPIRAM (DROM): DROM alignment gap not added into heap\n"); printf("SPIRAM (DROM): DROM alignment gap not added into heap\n");
} }
} }
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
void test_non_cache_spiram_xip_drom_alignment_reg_execute_violation(void)
{
extern int _rodata_reserved_end;
if (ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end)) - (uint32_t)(&_rodata_reserved_end) >= 4) {
void *test_addr = (void *)CACHE_LL_L2MEM_NON_CACHE_ADDR(&_rodata_reserved_end + 0x4);
printf("SPIRAM (DROM): Non-cacheable Execute operation | Address: %p\n", test_addr);
run_function(test_addr);
} else {
printf("SPIRAM (DROM): Non-cacheable DROM alignment gap not added into heap\n");
}
}
#endif
#endif /* CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2 */ #endif /* CONFIG_SPIRAM_RODATA && !CONFIG_IDF_TARGET_ESP32S2 */
#ifdef CONFIG_SOC_CPU_HAS_PMA #ifdef CONFIG_SOC_CPU_HAS_PMA
+187 -40
View File
@@ -695,6 +695,8 @@ CONFIGS_MEMPROT_IDRAM = list(
) )
) )
CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE = list(itertools.chain(itertools.product(['memprot_esp32p4'], ['esp32p4'])))
CONFIGS_MEMPROT_DCACHE = list(itertools.chain(itertools.product(['memprot_esp32s2'], ['esp32s2']))) CONFIGS_MEMPROT_DCACHE = list(itertools.chain(itertools.product(['memprot_esp32s2'], ['esp32s2'])))
CONFIGS_MEMPROT_RTC_FAST_MEM = list( CONFIGS_MEMPROT_RTC_FAST_MEM = list(
@@ -725,6 +727,8 @@ CONFIGS_MEMPROT_FLASH_IDROM = list(
) )
) )
CONFIGS_MEMPROT_FLASH_IDROM_L2_NON_CACHE = list(zip(['memprot_esp32p4'], ['esp32p4']))
CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP = list( CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP = list(
itertools.chain( itertools.chain(
zip( zip(
@@ -734,6 +738,14 @@ CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP = list(
) )
) )
CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP_L2_NON_CACHE = list(
zip(
['memprot_spiram_xip_esp32p4'],
['esp32p4'],
)
)
CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP = list( CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP = list(
itertools.chain( itertools.chain(
zip( zip(
@@ -748,6 +760,13 @@ CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP = list(
) )
) )
CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP_L2_NON_CACHE = list(
zip(
['memprot_spiram_xip_esp32p4'],
['esp32p4'],
)
)
CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA = list( CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA = list(
itertools.chain( itertools.chain(
zip( zip(
@@ -779,9 +798,7 @@ def test_dcache_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.expect_cpu_reset() dut.expect_cpu_reset()
@pytest.mark.generic def iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
def test_iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
if dut.target == 'esp32s2': if dut.target == 'esp32s2':
@@ -801,7 +818,55 @@ def test_iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> No
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
def test_iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
iram_reg1_write_violation(dut, test_func_name)
@pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
def test_non_cache_iram_reg1_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
iram_reg1_write_violation(dut, test_func_name)
def iram_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name)
if dut.target == 'esp32s2':
dut.expect_gme('Memory protection fault')
dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)')
dut.expect_reg_dump(0)
dut.expect_backtrace()
elif dut.target == 'esp32c3':
dut.expect_gme('Memory protection fault')
dut.expect(r' memory type: (\S+)')
dut.expect(r' faulting address: [0-9xa-f]+')
dut.expect(r' operation type: (\S+)')
dut.expect_reg_dump(0)
dut.expect_stack_dump()
else:
dut.expect_gme('Store access fault')
dut.expect_reg_dump(0)
dut.expect_stack_dump()
dut.expect_cpu_reset()
@pytest.mark.generic
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
def test_iram_reg2_write_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_iram_reg2_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
iram_reg_write_violation(dut, test_func_name)
@pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
def test_non_cache_iram_reg2_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
iram_reg_write_violation(dut, test_func_name)
def iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
if dut.target == 'esp32s2': if dut.target == 'esp32s2':
@@ -827,6 +892,17 @@ def test_iram_reg2_write_violation(dut: PanicTestDut, test_func_name: str) -> No
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
def test_iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
iram_reg_write_violation(dut, test_func_name)
@pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
def test_non_cache_iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
iram_reg_write_violation(dut, test_func_name)
def iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
if dut.target == 'esp32s2': if dut.target == 'esp32s2':
@@ -854,35 +930,17 @@ def test_iram_reg3_write_violation(dut: PanicTestDut, test_func_name: str) -> No
@pytest.mark.xfail('config.getvalue("target") == "esp32s2"', reason='Incorrect panic reason may be observed', run=False) @pytest.mark.xfail('config.getvalue("target") == "esp32s2"', reason='Incorrect panic reason may be observed', run=False)
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
def test_iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) iram_reg_write_violation(dut, test_func_name)
if dut.target == 'esp32s2':
dut.expect_gme('Memory protection fault')
dut.expect(r'Write operation at address [0-9xa-f]+ not permitted \((\S+)\)')
dut.expect_reg_dump(0)
dut.expect_backtrace()
elif dut.target == 'esp32c3':
dut.expect_gme('Memory protection fault')
dut.expect(r' memory type: (\S+)')
dut.expect(r' faulting address: [0-9xa-f]+')
dut.expect(r' operation type: (\S+)')
dut.expect_reg_dump(0)
dut.expect_stack_dump()
else:
dut.expect_gme('Store access fault')
dut.expect_reg_dump(0)
dut.expect_stack_dump()
dut.expect_cpu_reset()
# TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs
@pytest.mark.generic @pytest.mark.generic
@pytest.mark.xfail( @idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
'config.getvalue("target") == "esp32s2"', reason='Multiple panic reasons for the same test may surface', run=False def test_non_cache_iram_reg4_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
) if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target']) iram_reg_write_violation(dut, test_func_name)
def test_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
def dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
if dut.target == 'esp32s2': if dut.target == 'esp32s2':
@@ -904,7 +962,18 @@ def test_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) ->
'config.getvalue("target") == "esp32s2"', reason='Multiple panic reasons for the same test may surface', run=False 'config.getvalue("target") == "esp32s2"', reason='Multiple panic reasons for the same test may surface', run=False
) )
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
def test_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
dram_reg1_execute_violation(dut, test_func_name)
@pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
def test_non_cache_dram_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
dram_reg1_execute_violation(dut, test_func_name)
def dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
if dut.target == 'esp32s2': if dut.target == 'esp32s2':
@@ -919,6 +988,24 @@ def test_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) ->
dut.expect_cpu_reset() dut.expect_cpu_reset()
# TODO: IDF-6820: ESP32-S2 -> Fix multiple panic reasons in different runs
@pytest.mark.generic
@pytest.mark.xfail(
'config.getvalue("target") == "esp32s2"', reason='Multiple panic reasons for the same test may surface', run=False
)
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM, indirect=['config', 'target'])
def test_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
dram_reg2_execute_violation(dut, test_func_name)
@pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_IDRAM_L2_MEM_NON_CACHE, indirect=['config', 'target'])
def test_non_cache_dram_reg2_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
dram_reg2_execute_violation(dut, test_func_name)
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_RTC_FAST_MEM, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_RTC_FAST_MEM, indirect=['config', 'target'])
def test_rtc_fast_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_rtc_fast_reg1_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
@@ -1000,9 +1087,27 @@ def test_rtc_slow_reg2_execute_violation(dut: PanicTestDut, test_func_name: str)
dut.expect_cpu_reset() dut.expect_cpu_reset()
def irom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name)
dut.expect_gme('Store access fault')
dut.expect_reg_dump(0)
dut.expect_cpu_reset()
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM, indirect=['config', 'target'])
def test_irom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_irom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
irom_reg_write_violation(dut, test_func_name)
@pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM_L2_NON_CACHE, indirect=['config', 'target'])
def test_non_cache_irom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
irom_reg_write_violation(dut, test_func_name)
def drom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
dut.expect_gme('Store access fault') dut.expect_gme('Store access fault')
dut.expect_reg_dump(0) dut.expect_reg_dump(0)
@@ -1012,15 +1117,17 @@ def test_irom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> Non
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM, indirect=['config', 'target'])
def test_drom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_drom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) drom_reg_write_violation(dut, test_func_name)
dut.expect_gme('Store access fault')
dut.expect_reg_dump(0)
dut.expect_cpu_reset()
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM_L2_NON_CACHE, indirect=['config', 'target'])
def test_drom_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_non_cache_drom_reg_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
drom_reg_write_violation(dut, test_func_name)
def drom_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
dut.expect_gme('Instruction access fault') dut.expect_gme('Instruction access fault')
dut.expect_reg_dump(0) dut.expect_reg_dump(0)
@@ -1028,8 +1135,19 @@ def test_drom_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> N
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM, indirect=['config', 'target'])
def test_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_drom_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
drom_reg_execute_violation(dut, test_func_name)
@pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_FLASH_IDROM_L2_NON_CACHE, indirect=['config', 'target'])
def test_non_cache_drom_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
drom_reg_execute_violation(dut, test_func_name)
def spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
try: try:
dut.expect_gme('Instruction access fault') dut.expect_gme('Instruction access fault')
@@ -1040,8 +1158,21 @@ def test_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP, indirect=['config', 'target'])
def test_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
spiram_xip_irom_alignment_reg_execute_violation(dut, test_func_name)
@pytest.mark.generic
@idf_parametrize(
'config, target', CONFIGS_MEMPROT_SPIRAM_XIP_IROM_ALIGNMENT_HEAP_L2_NON_CACHE, indirect=['config', 'target']
)
def test_non_cache_spiram_xip_irom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
spiram_xip_irom_alignment_reg_execute_violation(dut, test_func_name)
def spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
try: try:
if dut.target == 'esp32s3': if dut.target == 'esp32s3':
@@ -1055,6 +1186,22 @@ def test_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test
@pytest.mark.generic @pytest.mark.generic
@idf_parametrize('config, target', CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP, indirect=['config', 'target'])
def test_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
spiram_xip_drom_alignment_reg_execute_violation(dut, test_func_name)
@pytest.mark.generic
@idf_parametrize(
'config, target', CONFIGS_MEMPROT_SPIRAM_XIP_DROM_ALIGNMENT_HEAP_L2_NON_CACHE, indirect=['config', 'target']
)
def test_non_cache_spiram_xip_drom_alignment_reg_execute_violation(dut: PanicTestDut, test_func_name: str) -> None:
if dut.target == 'esp32p4' and not dut.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
spiram_xip_drom_alignment_reg_execute_violation(dut, test_func_name)
@pytest.mark.generic
@pytest.mark.temp_skip_ci(targets=['esp32h21'], reason='lack of runners')
@idf_parametrize('config, target', CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA, indirect=['config', 'target']) @idf_parametrize('config, target', CONFIGS_MEMPROT_INVALID_REGION_PROTECTION_USING_PMA, indirect=['config', 'target'])
def test_invalid_memory_region_write_violation(dut: PanicTestDut, test_func_name: str) -> None: def test_invalid_memory_region_write_violation(dut: PanicTestDut, test_func_name: str) -> None:
dut.run_test_func(test_func_name) dut.run_test_func(test_func_name)
@@ -72,6 +72,8 @@ class PanicTestDut(IdfDut):
return self.target in ['esp32', 'esp32s3', 'esp32p4'] return self.target in ['esp32', 'esp32s3', 'esp32p4']
def run_test_func(self, test_func_name: str) -> None: def run_test_func(self, test_func_name: str) -> None:
if self.target == 'esp32p4' and not self.app.sdkconfig.get('ESP32P4_SELECTS_REV_LESS_V3'):
self.write('\n')
self.expect_exact('Enter test name:') self.expect_exact('Enter test name:')
self.write(test_func_name) self.write(test_func_name)
self.expect_exact('Got test name: ' + test_func_name) self.expect_exact('Got test name: ' + test_func_name)