diff --git a/components/esp_hw_support/port/esp32c6/cpu_region_protect.c b/components/esp_hw_support/port/esp32c6/cpu_region_protect.c index 9dcadc4173..054d7451ce 100644 --- a/components/esp_hw_support/port/esp32c6/cpu_region_protect.c +++ b/components/esp_hw_support/port/esp32c6/cpu_region_protect.c @@ -13,17 +13,45 @@ #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 +#define ALIGN_UP_TO_MMU_PAGE_SIZE(addr) (((addr) + (SOC_MMU_PAGE_SIZE) - 1) & ~((SOC_MMU_PAGE_SIZE) - 1)) +#define ALIGN_DOWN_TO_MMU_PAGE_SIZE(addr) ((addr) & ~((SOC_MMU_PAGE_SIZE) - 1)) + +/** + * @brief Generate the PMP address field value for PMPCFG.A == NAPOT + * + * NOTE: Here, (end-start) must be a power of 2 size and start must + * be aligned to this size. This API returns UINT32_MAX on failing + * these conditions, which when plugged into the PMP entry registers + * does nothing. This skips the corresponding region's protection. + * + * @param start Region starting address + * @param end Region ending address + * + * @return uint32_t PMP address field value + */ +static inline uint32_t pmpaddr_napot(uint32_t start, uint32_t end) +{ + uint32_t size = end - start; + if ((size & (size - 1)) || (start % size)) { + return UINT32_MAX; + } + + return start | ((size - 1) >> 1); +} + static void esp_cpu_configure_invalid_regions(void) { const unsigned PMA_NONE = PMA_L | PMA_EN; @@ -155,15 +183,30 @@ void esp_cpu_configure_region_protection(void) #endif } +#if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD + extern int _instruction_reserved_end; + extern int _rodata_reserved_start; + 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_start = ALIGN_DOWN_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_start)); + const uint32_t drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end)); + // 4. I_Cache (flash) - const uint32_t pmpaddr8 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH); + PMP_ENTRY_CFG_RESET(8); + const uint32_t pmpaddr8 = pmpaddr_napot(SOC_IROM_LOW, irom_resv_end); PMP_ENTRY_SET(8, pmpaddr8, PMP_NAPOT | RX); - _Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I_Cache region"); // 5. D_Cache (flash) - const uint32_t pmpaddr9 = PMPADDR_NAPOT(SOC_DROM_LOW, SOC_DROM_HIGH); + PMP_ENTRY_CFG_RESET(9); + const uint32_t pmpaddr9 = pmpaddr_napot(drom_resv_start, drom_resv_end); PMP_ENTRY_SET(9, pmpaddr9, PMP_NAPOT | R); - _Static_assert(SOC_DROM_LOW < SOC_DROM_HIGH, "Invalid D_Cache region"); +#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 // 6. LP memory #if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD diff --git a/components/esp_hw_support/port/esp32h2/cpu_region_protect.c b/components/esp_hw_support/port/esp32h2/cpu_region_protect.c index 3eb7d03aad..a1073b688a 100644 --- a/components/esp_hw_support/port/esp32h2/cpu_region_protect.c +++ b/components/esp_hw_support/port/esp32h2/cpu_region_protect.c @@ -13,17 +13,45 @@ #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 +#define ALIGN_UP_TO_MMU_PAGE_SIZE(addr) (((addr) + (SOC_MMU_PAGE_SIZE) - 1) & ~((SOC_MMU_PAGE_SIZE) - 1)) +#define ALIGN_DOWN_TO_MMU_PAGE_SIZE(addr) ((addr) & ~((SOC_MMU_PAGE_SIZE) - 1)) + +/** + * @brief Generate the PMP address field value for PMPCFG.A == NAPOT + * + * NOTE: Here, (end-start) must be a power of 2 size and start must + * be aligned to this size. This API returns UINT32_MAX on failing + * these conditions, which when plugged into the PMP entry registers + * does nothing. This skips the corresponding region's protection. + * + * @param start Region starting address + * @param end Region ending address + * + * @return uint32_t PMP address field value + */ +static inline uint32_t pmpaddr_napot(uint32_t start, uint32_t end) +{ + uint32_t size = end - start; + if ((size & (size - 1)) || (start % size)) { + return UINT32_MAX; + } + + return start | ((size - 1) >> 1); +} + static void esp_cpu_configure_invalid_regions(void) { const unsigned PMA_NONE = PMA_L | PMA_EN; @@ -155,15 +183,30 @@ void esp_cpu_configure_region_protection(void) #endif } +#if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD + extern int _instruction_reserved_end; + extern int _rodata_reserved_start; + 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_start = ALIGN_DOWN_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_start)); + const uint32_t drom_resv_end = ALIGN_UP_TO_MMU_PAGE_SIZE((uint32_t)(&_rodata_reserved_end)); + // 4. I_Cache (flash) - const uint32_t pmpaddr8 = PMPADDR_NAPOT(SOC_IROM_LOW, SOC_IROM_HIGH); + PMP_ENTRY_CFG_RESET(8); + const uint32_t pmpaddr8 = pmpaddr_napot(SOC_IROM_LOW, irom_resv_end); PMP_ENTRY_SET(8, pmpaddr8, PMP_NAPOT | RX); - _Static_assert(SOC_IROM_LOW < SOC_IROM_HIGH, "Invalid I_Cache region"); // 5. D_Cache (flash) - const uint32_t pmpaddr9 = PMPADDR_NAPOT(SOC_DROM_LOW, SOC_DROM_HIGH); + PMP_ENTRY_CFG_RESET(9); + const uint32_t pmpaddr9 = pmpaddr_napot(drom_resv_start, drom_resv_end); PMP_ENTRY_SET(9, pmpaddr9, PMP_NAPOT | R); - _Static_assert(SOC_DROM_LOW < SOC_DROM_HIGH, "Invalid D_Cache region"); +#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 // 6. LP memory #if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD