From 497b730e8f7b3b76b136831bea318f9f1bb8b649 Mon Sep 17 00:00:00 2001 From: Martin Vychodil Date: Thu, 8 Oct 2020 11:19:23 +0800 Subject: [PATCH] * memprot support for RTC_SLOW * API upgrade JIRA IDF-1636 --- components/esp32s2/Kconfig | 1 - components/esp32s2/include/esp32s2/memprot.h | 189 ++++- components/esp32s2/ld/esp32s2.project.ld.in | 10 +- components/esp32s2/memprot.c | 800 ++++++++++++++---- components/esp_system/panic.c | 3 +- components/esp_system/port/cpu_start.c | 4 +- components/esp_system/port/panic_handler.c | 6 +- .../hal/esp32s2/include/hal/memprot_ll.h | 790 +++++++++++------ .../src/esp32s2/include/hal/memprot_peri_ll.h | 453 ++++++++++ tools/ci/config/target-test.yml | 6 + tools/test_apps/system/memprot/CMakeLists.txt | 9 + tools/test_apps/system/memprot/app_test.py | 39 + .../system/memprot/main/CMakeLists.txt | 2 + .../system/memprot/main/test_memprot_main.c | 484 +++++++++++ .../system/memprot/main/test_panic.c | 44 + tools/test_apps/system/memprot/sdkconfig.ci | 5 + 16 files changed, 2353 insertions(+), 492 deletions(-) create mode 100644 components/soc/src/esp32s2/include/hal/memprot_peri_ll.h create mode 100644 tools/test_apps/system/memprot/CMakeLists.txt create mode 100644 tools/test_apps/system/memprot/app_test.py create mode 100644 tools/test_apps/system/memprot/main/CMakeLists.txt create mode 100644 tools/test_apps/system/memprot/main/test_memprot_main.c create mode 100644 tools/test_apps/system/memprot/main/test_panic.c create mode 100644 tools/test_apps/system/memprot/sdkconfig.ci diff --git a/components/esp32s2/Kconfig b/components/esp32s2/Kconfig index 0441c77f1b..a0c9664140 100644 --- a/components/esp32s2/Kconfig +++ b/components/esp32s2/Kconfig @@ -511,7 +511,6 @@ menu "ESP32S2-specific" config ESP32S2_ALLOW_RTC_FAST_MEM_AS_HEAP bool "Enable RTC fast memory for dynamic allocations" - depends on !ESP32S2_MEMPROT_FEATURE default y help This config option allows to add RTC fast memory region to system heap with capability diff --git a/components/esp32s2/include/esp32s2/memprot.h b/components/esp32s2/include/esp32s2/memprot.h index 7246826530..57a9cc747a 100644 --- a/components/esp32s2/include/esp32s2/memprot.h +++ b/components/esp32s2/include/esp32s2/memprot.h @@ -18,15 +18,22 @@ */ #pragma once +#include "esp_attr.h" #ifdef __cplusplus extern "C" { #endif typedef enum { - MEMPROT_IRAM0 = 0x00000000, - MEMPROT_DRAM0 = 0x00000001, - MEMPROT_UNKNOWN + MEMPROT_NONE = 0x00000000, + MEMPROT_IRAM0_SRAM = 0x00000001, //0x40020000-0x4006FFFF, RWX + MEMPROT_DRAM0_SRAM = 0x00000002, //0x3FFB0000-0x3FFFFFFF, RW + MEMPROT_IRAM0_RTCFAST = 0x00000004, //0x40070000-0x40071FFF, RWX + MEMPROT_DRAM0_RTCFAST = 0x00000008, //0x3FF9E000-0x3FF9FFFF, RW + MEMPROT_PERI1_RTCSLOW = 0x00000010, //0x3F421000-0x3F423000, RW + MEMPROT_PERI2_RTCSLOW_0 = 0x00000020, //0x50001000-0x50003000, RWX + MEMPROT_PERI2_RTCSLOW_1 = 0x00000040, //0x60002000-0x60004000, RWX + MEMPROT_ALL = 0xFFFFFFFF } mem_type_prot_t; @@ -60,22 +67,6 @@ void esp_memprot_intr_init(mem_type_prot_t mem_type); */ void esp_memprot_intr_ena(mem_type_prot_t mem_type, bool enable); -/** - * @brief Detects whether any of the memory protection interrupts is active - * - * @return true/false - */ -bool esp_memprot_is_assoc_intr_any(void); - -/** - * @brief Detects whether specific memory protection interrupt is active - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return true/false - */ -bool esp_memprot_is_assoc_intr(mem_type_prot_t mem_type); - /** * @brief Sets a request for clearing interrupt-on flag for specified memory region (register write) * @@ -87,11 +78,17 @@ bool esp_memprot_is_assoc_intr(mem_type_prot_t mem_type); void esp_memprot_clear_intr(mem_type_prot_t mem_type); /** - * @brief Detects which memory protection interrupt is active, check order: IRAM0, DRAM0 + * @brief Detects which memory protection interrupt is active + * + * @note Check order + * MEMPROT_IRAM0_SRAM + * MEMPROT_IRAM0_RTCFAST + * MEMPROT_DRAM0_SRAM + * MEMPROT_DRAM0_RTCFAST * * @return Memory protection area type (see mem_type_prot_t enum) */ -mem_type_prot_t IRAM_ATTR esp_memprot_get_intr_memtype(void); +mem_type_prot_t IRAM_ATTR esp_memprot_get_active_intr_memtype(void); /** * @brief Gets interrupt status register contents for specified memory region @@ -151,13 +148,13 @@ void esp_memprot_set_lock(mem_type_prot_t mem_type); bool esp_memprot_get_lock(mem_type_prot_t mem_type); /** - * @brief Gets interrupt permission control register contents for required memory region + * @brief Gets permission control configuration register contents for required memory region * * @param mem_type Memory protection area type (see mem_type_prot_t enum) * * @return Permission control register contents */ -uint32_t esp_memprot_get_ena_reg(mem_type_prot_t mem_type); +uint32_t esp_memprot_get_conf_reg(mem_type_prot_t mem_type); /** * @brief Gets interrupt permission settings for unified management block @@ -321,11 +318,12 @@ void esp_memprot_set_prot_iram(mem_type_prot_t mem_type, uint32_t *split_addr, b * * @param invoke_panic_handler map mem.prot interrupt to ETS_MEMACCESS_ERR_INUM and thus invokes panic handler when fired ('true' not suitable for testing) * @param lock_feature sets LOCK bit, see esp_memprot_set_lock() ('true' not suitable for testing) + * @param mem_type_mask holds a set of required memory protection types (bitmask built of mem_type_prot_t). NULL means default (MEMPROT_ALL in this version) */ -void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature); +void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask); /** - * @brief Get permission settings bits for IRAM split mgmt based on current split address + * @brief Get permission settings bits for IRAM0 split mgmt. Only IRAM0 memory types allowed * * @param mem_type Memory protection area type (see mem_type_prot_t enum) * @param lw Low segment Write permission flag @@ -338,7 +336,7 @@ void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature); void esp_memprot_get_perm_split_bits_iram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx); /** - * @brief Get permission settings bits for DRAM split mgmt based on current split address + * @brief Get permission settings bits for DRAM0 split mgmt. Only DRAM0 memory types allowed * * @param mem_type Memory protection area type (see mem_type_prot_t enum) * @param lw Low segment Write permission flag @@ -348,6 +346,145 @@ void esp_memprot_get_perm_split_bits_iram(mem_type_prot_t mem_type, bool *lw, bo */ void esp_memprot_get_perm_split_bits_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr); +/** + * @brief Sets permissions for high and low memory segment in PERIBUS1 region + * + * Sets Read and Write permission for both low and high memory segments given by splitting address. + * Applicable only to PERIBUS1 memory types + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param split_addr Address to split the memory region to lower and higher segment + * @param lw Low segment Write permission flag + * @param lr Low segment Read permission flag + * @param hw High segment Write permission flag + * @param hr High segment Read permission flag + */ +void esp_memprot_set_prot_peri1(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr); + +/** + * @brief Get permission settings bits for PERIBUS1 split mgmt. Only PERIBUS1 memory types allowed + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param lw Low segment Write permission flag + * @param lr Low segment Read permission flag + * @param hw High segment Write permission flag + * @param hr High segment Read permission flag + */ +void esp_memprot_get_perm_split_bits_peri1(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr); + +/** + * @brief Get permission settings bits for PERIBUS2 split mgmt. Only PERIBUS2 memory types allowed + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param lw Low segment Write permission flag + * @param lr Low segment Read permission flag + * @param lx Low segment Execute permission flag + * @param hw High segment Write permission flag + * @param hr High segment Read permission flag + * @param hx High segment Execute permission flag + */ +void esp_memprot_get_perm_split_bits_peri2(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx); + +/** + * @brief Sets permissions for high and low memory segment in PERIBUS2 region + * + * Sets Read Write permission for both low and high memory segments given by splitting address. + * Applicable only to PERIBUS2 memory types + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param split_addr Address to split the memory region to lower and higher segment + * @param lw Low segment Write permission flag + * @param lr Low segment Read permission flag + * @param lx Low segment Execute permission flag + * @param hw High segment Write permission flag + * @param hr High segment Read permission flag + * @param hx High segment Execute permission flag + */ +void esp_memprot_set_prot_peri2(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx); + +/** + * @brief Get permissions for specified memory type. Irrelevant bits are ignored + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param lw Low segment Write permission flag + * @param lr Low segment Read permission flag + * @param lx Low segment Execute permission flag + * @param hw High segment Write permission flag + * @param hr High segment Read permission flag + * @param hx High segment Execute permission flag + */ +void esp_memprot_get_permissions(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx); + +/** + * @brief Get Read permission settings for low and high regions of given memory type + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param lr Low segment Read permission flag + * @param hr High segment Read permission flag + */ +void esp_memprot_get_perm_read(mem_type_prot_t mem_type, bool *lr, bool *hr); + +/** + * @brief Get Write permission settings for low and high regions of given memory type + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param lr Low segment Write permission flag + * @param hr High segment Write permission flag + */ +void esp_memprot_get_perm_write(mem_type_prot_t mem_type, bool *lw, bool *hw); + +/** + * @brief Get Execute permission settings for low and high regions of given memory type + * Applicable only to IBUS-compatible memory types + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param lr Low segment Exec permission flag + * @param hr High segment Exec permission flag + */ +void esp_memprot_get_perm_exec(mem_type_prot_t mem_type, bool *lx, bool *hx); + +/** + * @brief Returns the lowest address in required memory region + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + */ +uint32_t esp_memprot_get_low_limit(mem_type_prot_t mem_type); + +/** + * @brief Returns the highest address in required memory region + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + */ +uint32_t esp_memprot_get_high_limit(mem_type_prot_t mem_type); + +/** + * @brief Sets READ permission bit for required memory region + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param lr Low segment Read permission flag + * @param hr High segment Read permission flag + */ +void esp_memprot_set_read_perm(mem_type_prot_t mem_type, bool lr, bool hr); + +/** + * @brief Sets WRITE permission bit for required memory region + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param lr Low segment Write permission flag + * @param hr High segment Write permission flag + */ +void esp_memprot_set_write_perm(mem_type_prot_t mem_type, bool lw, bool hw); + +/** + * @brief Sets EXECUTE permission bit for required memory region + * + * @param mem_type Memory protection area type (see mem_type_prot_t enum) + * @param lr Low segment Exec permission flag + * @param hr High segment Exec permission flag + */ +void esp_memprot_set_exec_perm(mem_type_prot_t mem_type, bool lx, bool hx); + + #ifdef __cplusplus } #endif diff --git a/components/esp32s2/ld/esp32s2.project.ld.in b/components/esp32s2/ld/esp32s2.project.ld.in index fc619c5904..ba806b298f 100644 --- a/components/esp32s2/ld/esp32s2.project.ld.in +++ b/components/esp32s2/ld/esp32s2.project.ld.in @@ -8,11 +8,19 @@ SECTIONS */ .rtc.text : { + _rtc_text_start = ABSOLUTE(.); . = ALIGN(4); + _rtc_code_start = .; + mapping[rtc_text] *rtc_wake_stub*.*(.literal .text .literal.* .text.*) + _rtc_code_end = .; + + /* possibly align + add 16B for CPU dummy speculative instr. fetch */ + . = ((_rtc_code_end - _rtc_code_start) == 0) ? ALIGN(0) : ALIGN(4) + 16; + _rtc_text_end = ABSOLUTE(.); } > rtc_iram_seg @@ -176,7 +184,7 @@ SECTIONS _coredump_iram_start = 0; _coredump_iram_end = 0; - /* align + add 16B for the possibly overlapping instructions */ + /* align + add 16B for CPU dummy speculative instr. fetch */ . = ALIGN(4) + 16; _iram_text_end = ABSOLUTE(.); _iram_end = ABSOLUTE(.); diff --git a/components/esp32s2/memprot.c b/components/esp32s2/memprot.c index d89a526508..b25f92da26 100644 --- a/components/esp32s2/memprot.c +++ b/components/esp32s2/memprot.c @@ -18,44 +18,79 @@ #include #include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_system.h" -#include "esp_spi_flash.h" #include "soc/sensitive_reg.h" #include "soc/dport_access.h" #include "soc/periph_defs.h" #include "esp_intr_alloc.h" + +#include "esp_log.h" +static const char *TAG = "memprot"; + #include "esp32s2/memprot.h" #include "hal/memprot_ll.h" +#include "hal/memprot_peri_ll.h" #include "esp_fault.h" -#include "esp_log.h" + #include "soc/cpu.h" extern int _iram_text_end; extern int _data_start; -static const char *TAG = "memprot"; +extern int _rtc_text_end; +extern int _rtc_dummy_end; -uint32_t *esp_memprot_iram0_get_min_split_addr(void) +uint32_t *esp_memprot_iram0_sram_get_min_split_addr(void) { return (uint32_t *)&_iram_text_end; } -uint32_t *esp_memprot_dram0_get_min_split_addr(void) +uint32_t *esp_memprot_iram0_rtcfast_get_min_split_addr(void) +{ + return (uint32_t *)&_rtc_text_end; +} + +uint32_t *esp_memprot_dram0_sram_get_min_split_addr(void) { return (uint32_t *)&_data_start; } +uint32_t *esp_memprot_dram0_rtcfast_get_min_split_addr(void) +{ + return (uint32_t *)&_rtc_dummy_end; +} + +uint32_t *esp_memprot_peri1_rtcslow_get_min_split_addr(void) +{ + return (uint32_t *)(PERI1_RTCSLOW_ADDRESS_BASE); +} + +uint32_t *esp_memprot_peri2_rtcslow_0_get_min_split_addr(void) +{ + return (uint32_t *)(PERI2_RTCSLOW_0_ADDRESS_BASE); +} + +uint32_t *esp_memprot_peri2_rtcslow_1_get_min_split_addr(void) +{ + return (uint32_t *)(PERI2_RTCSLOW_1_ADDRESS_BASE); +} + uint32_t *esp_memprot_get_split_addr(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - return esp_memprot_iram0_get_min_split_addr(); - case MEMPROT_DRAM0: - return esp_memprot_dram0_get_min_split_addr(); + case MEMPROT_IRAM0_SRAM: + return esp_memprot_iram0_sram_get_min_split_addr(); + case MEMPROT_DRAM0_SRAM: + return esp_memprot_dram0_sram_get_min_split_addr(); + case MEMPROT_IRAM0_RTCFAST: + return esp_memprot_iram0_rtcfast_get_min_split_addr(); + case MEMPROT_DRAM0_RTCFAST: + return esp_memprot_dram0_rtcfast_get_min_split_addr(); + case MEMPROT_PERI1_RTCSLOW: + return esp_memprot_peri1_rtcslow_get_min_split_addr(); + case MEMPROT_PERI2_RTCSLOW_0: + return esp_memprot_peri2_rtcslow_0_get_min_split_addr(); + case MEMPROT_PERI2_RTCSLOW_1: + return esp_memprot_peri2_rtcslow_1_get_min_split_addr(); default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -65,10 +100,20 @@ uint32_t *esp_memprot_get_split_addr(mem_type_prot_t mem_type) const char *esp_memprot_type_to_str(mem_type_prot_t mem_type) { switch (mem_type) { - case MEMPROT_IRAM0: - return "IRAM0"; - case MEMPROT_DRAM0: - return "DRAM0"; + case MEMPROT_IRAM0_SRAM: + return "IRAM0_SRAM"; + case MEMPROT_DRAM0_SRAM: + return "DRAM0_SRAM"; + case MEMPROT_IRAM0_RTCFAST: + return "IRAM0_RTCFAST"; + case MEMPROT_DRAM0_RTCFAST: + return "DRAM0_RTCFAST"; + case MEMPROT_PERI1_RTCSLOW: + return "PERI1_RTCSLOW"; + case MEMPROT_PERI2_RTCSLOW_0: + return "PERI2_RTCSLOW_0"; + case MEMPROT_PERI2_RTCSLOW_1: + return "PERI2_RTCSLOW_1"; default: return "UNKOWN"; } @@ -76,17 +121,24 @@ const char *esp_memprot_type_to_str(mem_type_prot_t mem_type) void esp_memprot_intr_init(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM); switch (mem_type) { - case MEMPROT_IRAM0: + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: intr_matrix_set(PRO_CPU_NUM, esp_memprot_iram0_get_intr_source_num(), ETS_MEMACCESS_ERR_INUM); break; - case MEMPROT_DRAM0: + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: intr_matrix_set(PRO_CPU_NUM, esp_memprot_dram0_get_intr_source_num(), ETS_MEMACCESS_ERR_INUM); break; + case MEMPROT_PERI1_RTCSLOW: + intr_matrix_set(PRO_CPU_NUM, esp_memprot_peri1_get_intr_source_num(), ETS_MEMACCESS_ERR_INUM); + break; + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + intr_matrix_set(PRO_CPU_NUM, esp_memprot_peri2_get_intr_source_num(), ETS_MEMACCESS_ERR_INUM); + break; default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -97,61 +149,67 @@ void esp_memprot_intr_init(mem_type_prot_t mem_type) void esp_memprot_intr_ena(mem_type_prot_t mem_type, bool enable) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: esp_memprot_iram0_intr_ena(enable); break; - case MEMPROT_DRAM0: + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: esp_memprot_dram0_intr_ena(enable); break; + case MEMPROT_PERI1_RTCSLOW: + esp_memprot_peri1_intr_ena(enable); + break; + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + esp_memprot_peri2_intr_ena(enable); + break; default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); } } -bool esp_memprot_is_assoc_intr_any() +mem_type_prot_t esp_memprot_get_active_intr_memtype() { - return esp_memprot_iram0_is_assoc_intr() || esp_memprot_dram0_is_assoc_intr(); -} - -mem_type_prot_t esp_memprot_get_intr_memtype() -{ - if ( esp_memprot_is_assoc_intr(MEMPROT_IRAM0) ) { - return MEMPROT_IRAM0; - } else if ( esp_memprot_is_assoc_intr(MEMPROT_DRAM0) ) { - return MEMPROT_DRAM0; + if (esp_memprot_iram0_sram_is_intr_mine()) { + return MEMPROT_IRAM0_SRAM; + } else if (esp_memprot_iram0_rtcfast_is_intr_mine()) { + return MEMPROT_IRAM0_RTCFAST; + } else if (esp_memprot_dram0_sram_is_intr_mine()) { + return MEMPROT_DRAM0_SRAM; + } else if (esp_memprot_dram0_rtcfast_is_intr_mine()) { + return MEMPROT_DRAM0_RTCFAST; + } else if (esp_memprot_peri1_rtcslow_is_intr_mine()) { + return MEMPROT_PERI1_RTCSLOW; + } else if (esp_memprot_peri2_rtcslow_0_is_intr_mine()) { + return MEMPROT_PERI2_RTCSLOW_0; + } else if (esp_memprot_peri2_rtcslow_1_is_intr_mine()) { + return MEMPROT_PERI2_RTCSLOW_1; } - return MEMPROT_UNKNOWN; -} - -bool esp_memprot_is_assoc_intr(mem_type_prot_t mem_type) -{ - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - - switch (mem_type) { - case MEMPROT_IRAM0: - return esp_memprot_iram0_is_assoc_intr(); - case MEMPROT_DRAM0: - return esp_memprot_dram0_is_assoc_intr(); - default: - ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); - abort(); - } + return MEMPROT_NONE; } void esp_memprot_clear_intr(mem_type_prot_t mem_type) { switch (mem_type) { - case MEMPROT_IRAM0: + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: esp_memprot_iram0_clear_intr(); break; - case MEMPROT_DRAM0: + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: esp_memprot_dram0_clear_intr(); break; + case MEMPROT_PERI1_RTCSLOW: + esp_memprot_peri1_clear_intr(); + break; + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + esp_memprot_peri2_clear_intr(); + break; default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -160,15 +218,22 @@ void esp_memprot_clear_intr(mem_type_prot_t mem_type) void esp_memprot_set_lock(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: esp_memprot_iram0_set_lock(); break; - case MEMPROT_DRAM0: + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: esp_memprot_dram0_set_lock(); break; + case MEMPROT_PERI1_RTCSLOW: + esp_memprot_peri1_set_lock(); + break; + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + esp_memprot_peri2_set_lock(); + break; default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -177,13 +242,18 @@ void esp_memprot_set_lock(mem_type_prot_t mem_type) bool esp_memprot_get_lock(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - return esp_memprot_iram0_get_lock_reg() > 0; - case MEMPROT_DRAM0: - return esp_memprot_dram0_get_lock_reg() > 0; + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: + return esp_memprot_iram0_get_lock_bit() > 0; + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: + return esp_memprot_dram0_get_lock_bit() > 0; + case MEMPROT_PERI1_RTCSLOW: + return esp_memprot_peri1_get_lock_bit() > 0; + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + return esp_memprot_peri2_get_lock_bit() > 0; default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -192,33 +262,48 @@ bool esp_memprot_get_lock(mem_type_prot_t mem_type) bool esp_memprot_is_locked_any() { - return esp_memprot_iram0_get_lock_reg() > 0 || esp_memprot_iram0_get_lock_reg() > 0; + return + esp_memprot_iram0_get_lock_bit() > 0 || + esp_memprot_dram0_get_lock_bit() > 0 || + esp_memprot_peri1_get_lock_bit() > 0 || + esp_memprot_peri2_get_lock_bit() > 0; } uint32_t esp_memprot_get_lock_bit(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: return esp_memprot_iram0_get_lock_bit(); - case MEMPROT_DRAM0: + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: return esp_memprot_dram0_get_lock_bit(); + case MEMPROT_PERI1_RTCSLOW: + return esp_memprot_peri1_get_lock_bit(); + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + return esp_memprot_peri2_get_lock_bit(); default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); } } -uint32_t esp_memprot_get_ena_reg(mem_type_prot_t mem_type) +uint32_t esp_memprot_get_conf_reg(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - return esp_memprot_iram0_get_ena_reg(); - case MEMPROT_DRAM0: - return esp_memprot_dram0_get_ena_reg(); + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: + return esp_memprot_iram0_get_conf_reg(); + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: + return esp_memprot_dram0_get_conf_reg(); + case MEMPROT_PERI1_RTCSLOW: + return esp_memprot_peri1_rtcslow_get_conf_reg(); + case MEMPROT_PERI2_RTCSLOW_0: + return esp_memprot_peri2_rtcslow_0_get_conf_reg(); + case MEMPROT_PERI2_RTCSLOW_1: + return esp_memprot_peri2_rtcslow_1_get_conf_reg(); default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -227,13 +312,18 @@ uint32_t esp_memprot_get_ena_reg(mem_type_prot_t mem_type) uint32_t esp_memprot_get_fault_reg(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: return esp_memprot_iram0_get_fault_reg(); - case MEMPROT_DRAM0: + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: return esp_memprot_dram0_get_fault_reg(); + case MEMPROT_PERI1_RTCSLOW: + return esp_memprot_peri1_get_fault_reg(); + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + return esp_memprot_peri2_get_fault_reg(); default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -242,35 +332,65 @@ uint32_t esp_memprot_get_fault_reg(mem_type_prot_t mem_type) void esp_memprot_get_fault_status(mem_type_prot_t mem_type, uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - esp_memprot_iram0_get_fault_status(faulting_address, op_type, op_subtype); + case MEMPROT_IRAM0_SRAM: + *faulting_address = esp_memprot_iram0_sram_get_fault_address(); break; - case MEMPROT_DRAM0: - esp_memprot_dram0_get_fault_status(faulting_address, op_type, op_subtype); + case MEMPROT_IRAM0_RTCFAST: + *faulting_address = esp_memprot_iram0_rtcfast_get_fault_address(); + break; + case MEMPROT_DRAM0_SRAM: + *faulting_address = esp_memprot_dram0_sram_get_fault_address(); + break; + case MEMPROT_DRAM0_RTCFAST: + *faulting_address = esp_memprot_dram0_rtcfast_get_fault_address(); + break; + case MEMPROT_PERI1_RTCSLOW: + *faulting_address = esp_memprot_peri1_rtcslow_get_fault_address(); + break; + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + *faulting_address = esp_memprot_peri2_rtcslow_get_fault_address(); break; default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); } + + if (mem_type == MEMPROT_IRAM0_SRAM || mem_type == MEMPROT_IRAM0_RTCFAST) { + esp_memprot_iram0_get_fault_op_type(op_type, op_subtype); + } else if (mem_type == MEMPROT_DRAM0_SRAM || mem_type == MEMPROT_DRAM0_RTCFAST) { + esp_memprot_dram0_get_fault_op_type(op_type, op_subtype); + } else if (mem_type == MEMPROT_PERI1_RTCSLOW) { + esp_memprot_peri1_get_fault_op_type(op_type, op_subtype); + } else if (mem_type == MEMPROT_PERI2_RTCSLOW_0 || mem_type == MEMPROT_PERI2_RTCSLOW_1) { + esp_memprot_peri2_get_fault_op_type(op_type, op_subtype); + } } bool esp_memprot_is_intr_ena_any() { - return esp_memprot_iram0_get_intr_ena_bit() > 0 || esp_memprot_dram0_get_intr_ena_bit() > 0; + return + esp_memprot_iram0_get_intr_ena_bit() > 0 || + esp_memprot_dram0_get_intr_ena_bit() > 0 || + esp_memprot_peri1_get_intr_ena_bit() > 0 || + esp_memprot_peri2_get_intr_ena_bit() > 0; } uint32_t esp_memprot_get_intr_ena_bit(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: return esp_memprot_iram0_get_intr_ena_bit(); - case MEMPROT_DRAM0: + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: return esp_memprot_dram0_get_intr_ena_bit(); + case MEMPROT_PERI1_RTCSLOW: + return esp_memprot_peri1_get_intr_ena_bit(); + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + return esp_memprot_peri2_get_intr_ena_bit(); default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -279,13 +399,18 @@ uint32_t esp_memprot_get_intr_ena_bit(mem_type_prot_t mem_type) uint32_t esp_memprot_get_intr_on_bit(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: return esp_memprot_iram0_get_intr_on_bit(); - case MEMPROT_DRAM0: + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: return esp_memprot_dram0_get_intr_on_bit(); + case MEMPROT_PERI1_RTCSLOW: + return esp_memprot_peri1_get_intr_on_bit(); + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + return esp_memprot_peri2_get_intr_on_bit(); default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -294,13 +419,18 @@ uint32_t esp_memprot_get_intr_on_bit(mem_type_prot_t mem_type) uint32_t esp_memprot_get_intr_clr_bit(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: + case MEMPROT_IRAM0_SRAM: + case MEMPROT_IRAM0_RTCFAST: return esp_memprot_iram0_get_intr_clr_bit(); - case MEMPROT_DRAM0: + case MEMPROT_DRAM0_SRAM: + case MEMPROT_DRAM0_RTCFAST: return esp_memprot_dram0_get_intr_clr_bit(); + case MEMPROT_PERI1_RTCSLOW: + return esp_memprot_peri1_get_intr_clr_bit(); + case MEMPROT_PERI2_RTCSLOW_0: + case MEMPROT_PERI2_RTCSLOW_1: + return esp_memprot_peri2_get_intr_clr_bit(); default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -309,85 +439,83 @@ uint32_t esp_memprot_get_intr_clr_bit(mem_type_prot_t mem_type) uint32_t esp_memprot_get_uni_block_read_bit(mem_type_prot_t mem_type, uint32_t block) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - return esp_memprot_iram0_get_uni_block_read_bit(block); - case MEMPROT_DRAM0: - return esp_memprot_dram0_get_uni_block_read_bit(block); + case MEMPROT_IRAM0_SRAM: + return esp_memprot_iram0_sram_get_uni_block_read_bit(block); + case MEMPROT_DRAM0_SRAM: + return esp_memprot_dram0_sram_get_uni_block_read_bit(block); default: - ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + ESP_LOGE(TAG, "Invalid mem_type %d (unified block management not supported)", mem_type); abort(); } } uint32_t esp_memprot_get_uni_block_write_bit(mem_type_prot_t mem_type, uint32_t block) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - return esp_memprot_iram0_get_uni_block_write_bit(block); - case MEMPROT_DRAM0: - return esp_memprot_dram0_get_uni_block_write_bit(block); + case MEMPROT_IRAM0_SRAM: + return esp_memprot_iram0_sram_get_uni_block_write_bit(block); + case MEMPROT_DRAM0_SRAM: + return esp_memprot_dram0_sram_get_uni_block_write_bit(block); default: - ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + ESP_LOGE(TAG, "Invalid mem_type %d (unified block management not supported)", mem_type); abort(); } } uint32_t esp_memprot_get_uni_block_exec_bit(mem_type_prot_t mem_type, uint32_t block) { - assert(mem_type == MEMPROT_IRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - return esp_memprot_iram0_get_uni_block_exec_bit(block); + case MEMPROT_IRAM0_SRAM: + return esp_memprot_iram0_sram_get_uni_block_exec_bit(block); default: - ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + ESP_LOGE(TAG, "Invalid mem_type %d (unified block management not supported)", mem_type); abort(); } } void esp_memprot_set_uni_block_perm_dram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm) { - assert(mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_DRAM0: - esp_memprot_dram0_set_uni_block_perm(block, write_perm, read_perm); + case MEMPROT_DRAM0_SRAM: + esp_memprot_dram0_sram_set_uni_block_perm(block, write_perm, read_perm); break; default: - ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + ESP_LOGE(TAG, "Invalid mem_type %d (unified block management not supported)", mem_type); abort(); } } uint32_t esp_memprot_get_perm_uni_reg(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - return esp_memprot_iram0_get_perm_uni_reg(); - case MEMPROT_DRAM0: - return esp_memprot_dram0_get_perm_reg(); + case MEMPROT_IRAM0_SRAM: + return esp_memprot_iram0_sram_get_perm_uni_reg(); + case MEMPROT_DRAM0_SRAM: + return esp_memprot_dram0_sram_get_perm_reg(); default: - ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + ESP_LOGE(TAG, "Invalid mem_type %d (unified block management not supported)", mem_type); abort(); } } uint32_t esp_memprot_get_perm_split_reg(mem_type_prot_t mem_type) { - assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - return esp_memprot_iram0_get_perm_split_reg(); - case MEMPROT_DRAM0: - return esp_memprot_dram0_get_perm_reg(); + case MEMPROT_IRAM0_SRAM: + return esp_memprot_iram0_sram_get_perm_split_reg(); + case MEMPROT_IRAM0_RTCFAST: + return esp_memprot_iram0_rtcfast_get_perm_split_reg(); + case MEMPROT_DRAM0_SRAM: + return esp_memprot_dram0_sram_get_perm_reg(); + case MEMPROT_DRAM0_RTCFAST: + return esp_memprot_dram0_rtcfast_get_perm_split_reg(); + case MEMPROT_PERI1_RTCSLOW: + return esp_memprot_peri1_rtcslow_get_conf_reg(); + case MEMPROT_PERI2_RTCSLOW_0: + return esp_memprot_peri2_rtcslow_0_get_conf_reg(); + case MEMPROT_PERI2_RTCSLOW_1: + return esp_memprot_peri2_rtcslow_1_get_conf_reg(); default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); abort(); @@ -396,11 +524,12 @@ uint32_t esp_memprot_get_perm_split_reg(mem_type_prot_t mem_type) void esp_memprot_set_prot_dram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr) { - assert(mem_type == MEMPROT_DRAM0); - switch (mem_type) { - case MEMPROT_DRAM0: - esp_memprot_dram0_set_prot(split_addr != NULL ? split_addr : esp_memprot_dram0_get_min_split_addr(), lw, lr, hw, hr); + case MEMPROT_DRAM0_SRAM: + esp_memprot_dram0_sram_set_prot(split_addr != NULL ? split_addr : esp_memprot_dram0_sram_get_min_split_addr(), lw, lr, hw, hr); + break; + case MEMPROT_DRAM0_RTCFAST: + esp_memprot_dram0_rtcfast_set_prot(split_addr != NULL ? split_addr : esp_memprot_dram0_rtcfast_get_min_split_addr(), lw, lr, hw, hr); break; default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); @@ -410,25 +539,24 @@ void esp_memprot_set_prot_dram(mem_type_prot_t mem_type, uint32_t *split_addr, b void esp_memprot_set_uni_block_perm_iram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm, bool exec_perm) { - assert(mem_type == MEMPROT_IRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - esp_memprot_iram0_set_uni_block_perm(block, write_perm, read_perm, exec_perm); + case MEMPROT_IRAM0_SRAM: + esp_memprot_iram0_sram_set_uni_block_perm(block, write_perm, read_perm, exec_perm); break; default: - ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + ESP_LOGE(TAG, "Invalid mem_type %d (unified block management not supported)", mem_type); abort(); } } void esp_memprot_set_prot_iram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx) { - assert(mem_type == MEMPROT_IRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - esp_memprot_iram0_set_prot(split_addr != NULL ? split_addr : esp_memprot_iram0_get_min_split_addr(), lw, lr, lx, hw, hr, hx); + case MEMPROT_IRAM0_SRAM: + esp_memprot_iram0_sram_set_prot(split_addr != NULL ? split_addr : esp_memprot_iram0_sram_get_min_split_addr(), lw, lr, lx, hw, hr, hx); + break; + case MEMPROT_IRAM0_RTCFAST: + esp_memprot_iram0_rtcfast_set_prot(split_addr != NULL ? split_addr : esp_memprot_iram0_rtcfast_get_min_split_addr(), lw, lr, lx, hw, hr, hx); break; default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); @@ -438,24 +566,12 @@ void esp_memprot_set_prot_iram(mem_type_prot_t mem_type, uint32_t *split_addr, b void esp_memprot_get_perm_split_bits_iram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx) { - assert(mem_type == MEMPROT_IRAM0); - switch (mem_type) { - case MEMPROT_IRAM0: - esp_memprot_iram0_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx); + case MEMPROT_IRAM0_SRAM: + esp_memprot_iram0_sram_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx); break; - default: - assert(0); - } -} - -void esp_memprot_get_perm_split_bits_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr) -{ - assert(mem_type == MEMPROT_DRAM0); - - switch (mem_type) { - case MEMPROT_DRAM0: - esp_memprot_dram0_get_split_sgnf_bits(lw, lr, hw, hr); + case MEMPROT_IRAM0_RTCFAST: + esp_memprot_iram0_rtcfast_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx); break; default: ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); @@ -463,30 +579,358 @@ void esp_memprot_get_perm_split_bits_dram(mem_type_prot_t mem_type, bool *lw, bo } } -void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature) +void esp_memprot_get_perm_split_bits_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr) { - esp_memprot_intr_ena(MEMPROT_DRAM0, false); - esp_memprot_intr_ena(MEMPROT_IRAM0, false); + switch (mem_type) { + case MEMPROT_DRAM0_SRAM: + esp_memprot_dram0_sram_get_split_sgnf_bits(lw, lr, hw, hr); + break; + case MEMPROT_DRAM0_RTCFAST: + esp_memprot_dram0_rtcfast_get_split_sgnf_bits(lw, lr, hw, hr); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} +void esp_memprot_get_perm_split_bits_peri1(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr) +{ + switch (mem_type) { + case MEMPROT_PERI1_RTCSLOW: + esp_memprot_peri1_rtcslow_get_split_sgnf_bits(lw, lr, hw, hr); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} + +void esp_memprot_set_prot_peri1(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr) +{ + switch (mem_type) { + case MEMPROT_PERI1_RTCSLOW: + esp_memprot_peri1_rtcslow_set_prot(split_addr != NULL ? split_addr : esp_memprot_peri1_rtcslow_get_min_split_addr(), lw, lr, hw, hr); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} + +void esp_memprot_get_perm_split_bits_peri2(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx) +{ + switch (mem_type) { + case MEMPROT_PERI2_RTCSLOW_0: + esp_memprot_peri2_rtcslow_0_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx); + break; + case MEMPROT_PERI2_RTCSLOW_1: + esp_memprot_peri2_rtcslow_1_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} + +void esp_memprot_set_prot_peri2(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx) +{ + switch (mem_type) { + case MEMPROT_PERI2_RTCSLOW_0: + esp_memprot_peri2_rtcslow_0_set_prot(split_addr != NULL ? split_addr : esp_memprot_peri2_rtcslow_0_get_min_split_addr(), lw, lr, lx, hw, hr, hx); + break; + case MEMPROT_PERI2_RTCSLOW_1: + esp_memprot_peri2_rtcslow_1_set_prot(split_addr != NULL ? split_addr : esp_memprot_peri2_rtcslow_1_get_min_split_addr(), lw, lr, lx, hw, hr, hx); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} + +void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask) +{ + //any IRAM0/DRAM0 enable/disable call applies to all memory modules connected + uint32_t required_mem_prot = mem_type_mask == NULL ? (uint32_t)MEMPROT_ALL : *mem_type_mask; + bool use_iram0 = required_mem_prot & MEMPROT_IRAM0_SRAM || required_mem_prot & MEMPROT_IRAM0_RTCFAST; + bool use_dram0 = required_mem_prot & MEMPROT_DRAM0_SRAM || required_mem_prot & MEMPROT_DRAM0_RTCFAST; + bool use_peri1 = required_mem_prot & MEMPROT_PERI1_RTCSLOW; + bool use_peri2 = required_mem_prot & MEMPROT_PERI2_RTCSLOW_0 || required_mem_prot & MEMPROT_PERI2_RTCSLOW_1; + + //disable protection + if (use_iram0) { + esp_memprot_intr_ena(MEMPROT_IRAM0_SRAM, false); + } + if (use_dram0) { + esp_memprot_intr_ena(MEMPROT_DRAM0_SRAM, false); + } + if (use_peri1) { + esp_memprot_intr_ena(MEMPROT_PERI1_RTCSLOW, false); + } + if (use_peri2) { + esp_memprot_intr_ena(MEMPROT_PERI2_RTCSLOW_0, false); + } + + //connect to intr. matrix if not being debugged if (!esp_cpu_in_ocd_debug_mode()) { ESP_FAULT_ASSERT(!esp_cpu_in_ocd_debug_mode()); - if ( invoke_panic_handler ) { - esp_memprot_intr_init(MEMPROT_DRAM0); - esp_memprot_intr_init(MEMPROT_IRAM0); + //initialize for specific buses (any memory type does the job) + if (invoke_panic_handler) { + if (use_iram0) { + esp_memprot_intr_init(MEMPROT_IRAM0_SRAM); + } + if (use_dram0) { + esp_memprot_intr_init(MEMPROT_DRAM0_SRAM); + } + if (use_peri1) { + esp_memprot_intr_init(MEMPROT_PERI1_RTCSLOW); + } + if (use_peri2) { + esp_memprot_intr_init(MEMPROT_PERI2_RTCSLOW_0); + } } - esp_memprot_set_prot_dram(MEMPROT_DRAM0, NULL, false, true, true, true); - esp_memprot_set_prot_iram(MEMPROT_IRAM0, NULL, false, true, true, true, true, false); + //set permissions + if (required_mem_prot & MEMPROT_IRAM0_SRAM) { + esp_memprot_set_prot_iram(MEMPROT_IRAM0_SRAM, NULL, false, true, true, true, true, true); + } + if (required_mem_prot & MEMPROT_IRAM0_RTCFAST) { + esp_memprot_set_prot_iram(MEMPROT_IRAM0_RTCFAST, NULL, false, true, true, true, true, true); + } + if (required_mem_prot & MEMPROT_DRAM0_SRAM) { + esp_memprot_set_prot_dram(MEMPROT_DRAM0_SRAM, NULL, false, true, true, true); + } + if (required_mem_prot & MEMPROT_DRAM0_RTCFAST) { + esp_memprot_set_prot_dram(MEMPROT_DRAM0_RTCFAST, NULL, false, true, true, true); + } + if (required_mem_prot & MEMPROT_PERI1_RTCSLOW) { + esp_memprot_set_prot_peri1(MEMPROT_PERI1_RTCSLOW, NULL, true, true, true, true); + } + if (required_mem_prot & MEMPROT_PERI2_RTCSLOW_0) { + esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_0, NULL, true, true, false, true, true, false); + } + if (required_mem_prot & MEMPROT_PERI2_RTCSLOW_1) { + esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_1, NULL, true, true, false, true, true, false); + } - esp_memprot_intr_ena(MEMPROT_DRAM0, true); - esp_memprot_intr_ena(MEMPROT_IRAM0, true); + //reenable protection (bus based) + if (use_iram0) { + esp_memprot_intr_ena(MEMPROT_IRAM0_SRAM, true); + } + if (use_dram0) { + esp_memprot_intr_ena(MEMPROT_DRAM0_SRAM, true); + } + if (use_peri1) { + esp_memprot_intr_ena(MEMPROT_PERI1_RTCSLOW, true); + } + if (use_peri2) { + esp_memprot_intr_ena(MEMPROT_PERI2_RTCSLOW_0, true); + } - if ( lock_feature ) { - esp_memprot_set_lock(MEMPROT_DRAM0); - esp_memprot_set_lock(MEMPROT_IRAM0); + //lock if required (bus based) + if (lock_feature) { + if (use_iram0) { + esp_memprot_set_lock(MEMPROT_IRAM0_SRAM); + } + if (use_dram0) { + esp_memprot_set_lock(MEMPROT_DRAM0_SRAM); + } + if (use_peri1) { + esp_memprot_set_lock(MEMPROT_PERI1_RTCSLOW); + } + if (use_peri2) { + esp_memprot_set_lock(MEMPROT_PERI2_RTCSLOW_0); + } } } } +void esp_memprot_get_permissions(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx) +{ + switch (mem_type) { + case MEMPROT_IRAM0_SRAM: + esp_memprot_iram0_sram_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx); + break; + case MEMPROT_DRAM0_SRAM: + esp_memprot_dram0_sram_get_split_sgnf_bits(lw, lr, hw, hr); + break; + case MEMPROT_IRAM0_RTCFAST: + esp_memprot_iram0_rtcfast_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx); + break; + case MEMPROT_DRAM0_RTCFAST: + esp_memprot_dram0_rtcfast_get_split_sgnf_bits(lw, lr, hw, hr); + break; + case MEMPROT_PERI1_RTCSLOW: + esp_memprot_peri1_rtcslow_get_split_sgnf_bits(lw, lr, hw, hr); + break; + case MEMPROT_PERI2_RTCSLOW_0: + esp_memprot_peri2_rtcslow_0_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx); + break; + case MEMPROT_PERI2_RTCSLOW_1: + esp_memprot_peri2_rtcslow_1_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} + +void esp_memprot_get_perm_read(mem_type_prot_t mem_type, bool *lr, bool *hr) +{ + bool _lw, _lr, _lx, _hw, _hr, _hx; + esp_memprot_get_permissions(mem_type, &_lw, &_lr, &_lx, &_hw, &_hr, &_hx); + *lr = _lr; + *hr = _hr; +} + +void esp_memprot_get_perm_write(mem_type_prot_t mem_type, bool *lw, bool *hw) +{ + bool _lw, _lr, _lx, _hw, _hr, _hx; + esp_memprot_get_permissions(mem_type, &_lw, &_lr, &_lx, &_hw, &_hr, &_hx); + *lw = _lw; + *hw = _hw; +} + +void esp_memprot_get_perm_exec(mem_type_prot_t mem_type, bool *lx, bool *hx) +{ + if ( mem_type == MEMPROT_DRAM0_SRAM || + mem_type == MEMPROT_DRAM0_RTCFAST || + mem_type == MEMPROT_PERI1_RTCSLOW ) { + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } + + bool _lw, _lr, _lx, _hw, _hr, _hx; + esp_memprot_get_permissions(mem_type, &_lw, &_lr, &_lx, &_hw, &_hr, &_hx); + *lx = _lx; + *hx = _hx; +} + +uint32_t esp_memprot_get_low_limit(mem_type_prot_t mem_type) +{ + switch (mem_type) { + case MEMPROT_IRAM0_SRAM: + return IRAM0_SRAM_ADDRESS_LOW; + case MEMPROT_DRAM0_SRAM: + return DRAM0_SRAM_ADDRESS_LOW; + case MEMPROT_IRAM0_RTCFAST: + return IRAM0_RTCFAST_ADDRESS_LOW; + case MEMPROT_DRAM0_RTCFAST: + return DRAM0_RTCFAST_ADDRESS_LOW; + case MEMPROT_PERI1_RTCSLOW: + return PERI1_RTCSLOW_ADDRESS_LOW; + case MEMPROT_PERI2_RTCSLOW_0: + return PERI2_RTCSLOW_0_ADDRESS_LOW; + case MEMPROT_PERI2_RTCSLOW_1: + return PERI2_RTCSLOW_1_ADDRESS_LOW; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} + +uint32_t esp_memprot_get_high_limit(mem_type_prot_t mem_type) +{ + switch (mem_type) { + case MEMPROT_IRAM0_SRAM: + return IRAM0_SRAM_ADDRESS_HIGH; + case MEMPROT_DRAM0_SRAM: + return DRAM0_SRAM_ADDRESS_HIGH; + case MEMPROT_IRAM0_RTCFAST: + return IRAM0_RTCFAST_ADDRESS_HIGH; + case MEMPROT_DRAM0_RTCFAST: + return DRAM0_RTCFAST_ADDRESS_HIGH; + case MEMPROT_PERI1_RTCSLOW: + return PERI1_RTCSLOW_ADDRESS_HIGH; + case MEMPROT_PERI2_RTCSLOW_0: + return PERI2_RTCSLOW_0_ADDRESS_HIGH; + case MEMPROT_PERI2_RTCSLOW_1: + return PERI2_RTCSLOW_1_ADDRESS_HIGH; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} + +void esp_memprot_set_read_perm(mem_type_prot_t mem_type, bool lr, bool hr) +{ + switch (mem_type) { + case MEMPROT_IRAM0_SRAM: + esp_memprot_iram0_sram_set_read_perm(lr, hr); + break; + case MEMPROT_DRAM0_SRAM: + esp_memprot_dram0_sram_set_read_perm(lr, hr); + break; + case MEMPROT_IRAM0_RTCFAST: + esp_memprot_iram0_rtcfast_set_read_perm(lr, hr); + break; + case MEMPROT_DRAM0_RTCFAST: + esp_memprot_dram0_rtcfast_set_read_perm(lr, hr); + break; + case MEMPROT_PERI1_RTCSLOW: + esp_memprot_peri1_rtcslow_set_read_perm(lr, hr); + break; + case MEMPROT_PERI2_RTCSLOW_0: + esp_memprot_peri2_rtcslow_0_set_read_perm(lr, hr); + break; + case MEMPROT_PERI2_RTCSLOW_1: + esp_memprot_peri2_rtcslow_1_set_read_perm(lr, hr); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} + +void esp_memprot_set_write_perm(mem_type_prot_t mem_type, bool lw, bool hw) +{ + switch (mem_type) { + case MEMPROT_IRAM0_SRAM: + esp_memprot_iram0_sram_set_write_perm(lw, hw); + break; + case MEMPROT_DRAM0_SRAM: + esp_memprot_dram0_sram_set_write_perm(lw, hw); + break; + case MEMPROT_IRAM0_RTCFAST: + esp_memprot_iram0_rtcfast_set_write_perm(lw, hw); + break; + case MEMPROT_DRAM0_RTCFAST: + esp_memprot_dram0_rtcfast_set_write_perm(lw, hw); + break; + case MEMPROT_PERI1_RTCSLOW: + esp_memprot_peri1_rtcslow_set_write_perm(lw, hw); + break; + case MEMPROT_PERI2_RTCSLOW_0: + esp_memprot_peri2_rtcslow_0_set_write_perm(lw, hw); + break; + case MEMPROT_PERI2_RTCSLOW_1: + esp_memprot_peri2_rtcslow_1_set_write_perm(lw, hw); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} + +void esp_memprot_set_exec_perm(mem_type_prot_t mem_type, bool lx, bool hx) +{ + switch (mem_type) { + case MEMPROT_IRAM0_SRAM: + esp_memprot_iram0_sram_set_exec_perm(lx, hx); + break; + case MEMPROT_IRAM0_RTCFAST: + esp_memprot_iram0_rtcfast_set_exec_perm(lx, hx); + break; + case MEMPROT_PERI2_RTCSLOW_0: + esp_memprot_peri2_rtcslow_0_set_exec_perm(lx, hx); + break; + case MEMPROT_PERI2_RTCSLOW_1: + esp_memprot_peri2_rtcslow_1_set_exec_perm(lx, hx); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type %d", mem_type); + abort(); + } +} diff --git a/components/esp_system/panic.c b/components/esp_system/panic.c index 61b8a124fe..73dee777a1 100644 --- a/components/esp_system/panic.c +++ b/components/esp_system/panic.c @@ -186,7 +186,7 @@ void esp_panic_handler(panic_info_t *info) info->exception = PANIC_EXCEPTION_ABORT; } - /* + /* * For any supported chip, the panic handler prints the contents of panic_info_t in the following format: * * @@ -343,6 +343,7 @@ void esp_panic_handler(panic_info_t *info) #endif /* CONFIG_ESP_SYSTEM_PANIC_GDBSTUB */ } + void __attribute__((noreturn)) panic_abort(const char *details) { g_panic_abort = true; diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index d2de4bcf55..75cd0706d3 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -433,9 +433,9 @@ void IRAM_ATTR call_start_cpu0(void) #if CONFIG_IDF_TARGET_ESP32S2 #if CONFIG_ESP32S2_MEMPROT_FEATURE #if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK - esp_memprot_set_prot(true, true); + esp_memprot_set_prot(true, true, NULL); #else - esp_memprot_set_prot(true, false); + esp_memprot_set_prot(true, false, NULL); #endif #endif #endif diff --git a/components/esp_system/port/panic_handler.c b/components/esp_system/port/panic_handler.c index 61382f4651..314ab2d206 100644 --- a/components/esp_system/port/panic_handler.c +++ b/components/esp_system/port/panic_handler.c @@ -371,12 +371,12 @@ static inline void print_memprot_err_details(const void *f) { uint32_t *fault_addr; uint32_t op_type, op_subtype; - mem_type_prot_t mem_type = esp_memprot_get_intr_memtype(); + mem_type_prot_t mem_type = esp_memprot_get_active_intr_memtype(); esp_memprot_get_fault_status( mem_type, &fault_addr, &op_type, &op_subtype ); char *operation_type = "Write"; if ( op_type == 0 ) { - operation_type = (mem_type == MEMPROT_IRAM0 && op_subtype == 0) ? "Instruction fetch" : "Read"; + operation_type = (mem_type == MEMPROT_IRAM0_SRAM && op_subtype == 0) ? "Instruction fetch" : "Read"; } panic_print_str( operation_type ); @@ -506,7 +506,7 @@ static void frame_to_panic_info(XtExcFrame *frame, panic_info_t *info, bool pseu #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 if (frame->exccause == PANIC_RSN_CACHEERR) { - if ( esp_memprot_is_assoc_intr_any() ) { + if ( esp_memprot_get_active_intr_memtype() != MEMPROT_NONE ) { info->details = print_memprot_err_details; info->reason = "Memory protection fault"; } else { diff --git a/components/hal/esp32s2/include/hal/memprot_ll.h b/components/hal/esp32s2/include/hal/memprot_ll.h index d7769972c9..bf99e149af 100644 --- a/components/hal/esp32s2/include/hal/memprot_ll.h +++ b/components/hal/esp32s2/include/hal/memprot_ll.h @@ -19,38 +19,18 @@ extern "C" { #endif /** - * === IRAM0 ==== + * ======================================================================================== + * === IRAM0 common + * ======================================================================================== */ - -#define IRAM0_TOTAL_UNI_BLOCKS 4 -#define IRAM0_UNI_BLOCK_0 0 -#define IRAM0_UNI_BLOCK_1 1 -#define IRAM0_UNI_BLOCK_2 2 -#define IRAM0_UNI_BLOCK_3 3 - -#define IRAM0_SPL_BLOCK_BASE 0x40000000 - -//unified management (SRAM blocks 0-3) -#define IRAM0_UNI_BLOCK_0_LOW 0x40020000 -#define IRAM0_UNI_BLOCK_0_HIGH 0x40021FFF -#define IRAM0_UNI_BLOCK_1_LOW 0x40022000 -#define IRAM0_UNI_BLOCK_1_HIGH 0x40023FFF -#define IRAM0_UNI_BLOCK_2_LOW 0x40024000 -#define IRAM0_UNI_BLOCK_2_HIGH 0x40025FFF -#define IRAM0_UNI_BLOCK_3_LOW 0x40026000 -#define IRAM0_UNI_BLOCK_3_HIGH 0x40027FFF - -//split management (SRAM blocks 4-21) -#define IRAM0_SPL_BLOCK_LOW 0x40028000 //block 4 low -#define IRAM0_SPL_BLOCK_HIGH 0x4006FFFF //block 21 high -#define IRAM0_SPLTADDR_MIN 0x40030000 //block 6 low - minimum splitting address - //IRAM0 interrupt status bitmasks -#define IRAM0_INTR_ST_FAULTADDR_M 0x003FFFFC //(bits 21:6 in the reg, as well as in real address) -#define IRAM0_INTR_ST_FAULTADDR_HI 0x40000000 //(high nonsignificant bits 31:22 of the faulting address - constant) -#define IRAM0_INTR_ST_OP_TYPE_BIT BIT(1) //instruction: 0, data: 1 -#define IRAM0_INTR_ST_OP_RW_BIT BIT(0) //read: 0, write: 1 +#define IRAM0_INTR_ST_OP_TYPE_BIT BIT(1) //instruction: 0, data: 1 +#define IRAM0_INTR_ST_OP_RW_BIT BIT(0) //read: 0, write: 1 +static inline void esp_memprot_iram0_clear_intr(void) +{ + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_CLR); +} static inline uint32_t esp_memprot_iram0_get_intr_source_num(void) { @@ -59,14 +39,14 @@ static inline uint32_t esp_memprot_iram0_get_intr_source_num(void) static inline void esp_memprot_iram0_intr_ena(bool enable) { - if ( enable ) { - DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN ); + if (enable) { + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN); } else { - DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN ); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN); } } -static inline uint32_t esp_memprot_iram0_get_ena_reg(void) +static inline uint32_t esp_memprot_iram0_get_conf_reg(void) { return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_4_REG); } @@ -76,13 +56,9 @@ static inline uint32_t esp_memprot_iram0_get_fault_reg(void) return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_5_REG); } -static inline void esp_memprot_iram0_get_fault_status(uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype) +static inline void esp_memprot_iram0_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype) { uint32_t status_bits = esp_memprot_iram0_get_fault_reg(); - - uint32_t fault_addr = (status_bits & IRAM0_INTR_ST_FAULTADDR_M); - *faulting_address = (uint32_t *)(fault_addr | IRAM0_INTR_ST_FAULTADDR_HI); - *op_type = (uint32_t)status_bits & IRAM0_INTR_ST_OP_RW_BIT; *op_subtype = (uint32_t)status_bits & IRAM0_INTR_ST_OP_TYPE_BIT; } @@ -92,11 +68,6 @@ static inline bool esp_memprot_iram0_is_assoc_intr(void) return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_INTR) > 0; } -static inline void esp_memprot_iram0_clear_intr(void) -{ - DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_CLR); -} - static inline uint32_t esp_memprot_iram0_get_intr_ena_bit(void) { return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN); @@ -128,29 +99,72 @@ static inline uint32_t esp_memprot_iram0_get_lock_bit(void) return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_0_REG, DPORT_PMS_PRO_IRAM0_LOCK); } -//block 0-3 -static inline void esp_memprot_iram0_set_uni_block_perm(uint32_t block, bool write_perm, bool read_perm, bool exec_perm) +/** + * ======================================================================================== + * === IRAM0 SRAM + * ======================================================================================== + */ +#define IRAM0_SRAM_ADDRESS_LOW 0x40020000 +#define IRAM0_SRAM_ADDRESS_HIGH 0x4006FFFF + +#define IRAM0_SRAM_TOTAL_UNI_BLOCKS 4 +#define IRAM0_SRAM_UNI_BLOCK_0 0 +#define IRAM0_SRAM_UNI_BLOCK_1 1 +#define IRAM0_SRAM_UNI_BLOCK_2 2 +#define IRAM0_SRAM_UNI_BLOCK_3 3 + +//unified management (SRAM blocks 0-3) +#define IRAM0_SRAM_UNI_BLOCK_0_LOW 0x40020000 +#define IRAM0_SRAM_UNI_BLOCK_1_LOW 0x40022000 +#define IRAM0_SRAM_UNI_BLOCK_2_LOW 0x40024000 +#define IRAM0_SRAM_UNI_BLOCK_3_LOW 0x40026000 + +//split management (SRAM blocks 4-21) +#define IRAM0_SRAM_SPL_BLOCK_LOW 0x40028000 //block 4 low +#define IRAM0_SRAM_SPL_BLOCK_HIGH 0x4006FFFF //block 21 high + +#define IRAM0_INTR_ST_FAULTADDR_M 0x003FFFFC //bits 21:6 in the reg, as well as in real address +#define IRAM0_SRAM_INTR_ST_FAULTADDR_HI 0x40000000 //high nonsignificant bits 31:22 of the faulting address - constant + + +static inline uint32_t *esp_memprot_iram0_sram_get_fault_address(void) { - assert(block < IRAM0_TOTAL_UNI_BLOCKS); + uint32_t status_bits = esp_memprot_iram0_get_fault_reg(); + return (uint32_t *)((status_bits & IRAM0_INTR_ST_FAULTADDR_M) | IRAM0_SRAM_INTR_ST_FAULTADDR_HI); +} + +static inline bool esp_memprot_iram0_sram_is_intr_mine(void) +{ + if (esp_memprot_iram0_is_assoc_intr()) { + uint32_t *faulting_address = esp_memprot_iram0_sram_get_fault_address(); + return (uint32_t)faulting_address >= IRAM0_SRAM_ADDRESS_LOW && (uint32_t)faulting_address <= IRAM0_SRAM_ADDRESS_HIGH; + } + return false; +} + +//block 0-3 +static inline void esp_memprot_iram0_sram_set_uni_block_perm(uint32_t block, bool write_perm, bool read_perm, bool exec_perm) +{ + assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS); uint32_t write_bit, read_bit, exec_bit; - switch ( block ) { - case IRAM0_UNI_BLOCK_0: + switch (block) { + case IRAM0_SRAM_UNI_BLOCK_0: write_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_W; read_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_R; exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_F; break; - case IRAM0_UNI_BLOCK_1: + case IRAM0_SRAM_UNI_BLOCK_1: write_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_W; read_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_R; exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_F; break; - case IRAM0_UNI_BLOCK_2: + case IRAM0_SRAM_UNI_BLOCK_2: write_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_W; read_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_R; exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_F; break; - case IRAM0_UNI_BLOCK_3: + case IRAM0_SRAM_UNI_BLOCK_3: write_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_W; read_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_R; exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_F; @@ -159,100 +173,100 @@ static inline void esp_memprot_iram0_set_uni_block_perm(uint32_t block, bool wri abort(); } - if ( write_perm ) { - DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, write_bit ); + if (write_perm) { + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, write_bit); } else { - DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, write_bit ); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, write_bit); } - if ( read_perm ) { - DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, read_bit ); + if (read_perm) { + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, read_bit); } else { - DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, read_bit ); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, read_bit); } - if ( exec_perm ) { - DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, exec_bit ); + if (exec_perm) { + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, exec_bit); } else { - DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, exec_bit ); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_1_REG, exec_bit); } } -static inline uint32_t esp_memprot_iram0_get_uni_block_read_bit(uint32_t block) +static inline uint32_t esp_memprot_iram0_sram_get_uni_block_read_bit(uint32_t block) { - assert(block < IRAM0_TOTAL_UNI_BLOCKS); + assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS); - switch ( block ) { - case IRAM0_UNI_BLOCK_0: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_R ); - case IRAM0_UNI_BLOCK_1: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_R ); - case IRAM0_UNI_BLOCK_2: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_R ); - case IRAM0_UNI_BLOCK_3: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_R ); + switch (block) { + case IRAM0_SRAM_UNI_BLOCK_0: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_R); + case IRAM0_SRAM_UNI_BLOCK_1: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_R); + case IRAM0_SRAM_UNI_BLOCK_2: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_R); + case IRAM0_SRAM_UNI_BLOCK_3: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_R); default: abort(); } } -static inline uint32_t esp_memprot_iram0_get_uni_block_write_bit(uint32_t block) +static inline uint32_t esp_memprot_iram0_sram_get_uni_block_write_bit(uint32_t block) { - assert(block < IRAM0_TOTAL_UNI_BLOCKS); + assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS); - switch ( block ) { - case IRAM0_UNI_BLOCK_0: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_W ); - case IRAM0_UNI_BLOCK_1: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_W ); - case IRAM0_UNI_BLOCK_2: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_W ); - case IRAM0_UNI_BLOCK_3: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_W ); + switch (block) { + case IRAM0_SRAM_UNI_BLOCK_0: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_W); + case IRAM0_SRAM_UNI_BLOCK_1: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_W); + case IRAM0_SRAM_UNI_BLOCK_2: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_W); + case IRAM0_SRAM_UNI_BLOCK_3: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_W); default: abort(); } } -static inline uint32_t esp_memprot_iram0_get_uni_block_exec_bit(uint32_t block) +static inline uint32_t esp_memprot_iram0_sram_get_uni_block_exec_bit(uint32_t block) { - assert(block < IRAM0_TOTAL_UNI_BLOCKS); + assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS); - switch ( block ) { - case IRAM0_UNI_BLOCK_0: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_F ); - case IRAM0_UNI_BLOCK_1: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_F ); - case IRAM0_UNI_BLOCK_2: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_F ); - case IRAM0_UNI_BLOCK_3: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_F ); + switch (block) { + case IRAM0_SRAM_UNI_BLOCK_0: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_F); + case IRAM0_SRAM_UNI_BLOCK_1: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_F); + case IRAM0_SRAM_UNI_BLOCK_2: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_F); + case IRAM0_SRAM_UNI_BLOCK_3: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_F); default: abort(); } } -static inline void esp_memprot_iram0_get_uni_block_sgnf_bits(uint32_t block, uint32_t *write_bit, uint32_t *read_bit, uint32_t *exec_bit) +static inline void esp_memprot_iram0_sram_get_uni_block_sgnf_bits(uint32_t block, uint32_t *write_bit, uint32_t *read_bit, uint32_t *exec_bit) { - assert(block < IRAM0_TOTAL_UNI_BLOCKS); + assert(block < IRAM0_SRAM_TOTAL_UNI_BLOCKS); - switch ( block ) { - case IRAM0_UNI_BLOCK_0: + switch (block) { + case IRAM0_SRAM_UNI_BLOCK_0: *write_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_W; *read_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_R; *exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_F; break; - case IRAM0_UNI_BLOCK_1: + case IRAM0_SRAM_UNI_BLOCK_1: *write_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_W; *read_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_R; *exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_F; break; - case IRAM0_UNI_BLOCK_2: + case IRAM0_SRAM_UNI_BLOCK_2: *write_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_W; *read_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_R; *exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_F; break; - case IRAM0_UNI_BLOCK_3: + case IRAM0_SRAM_UNI_BLOCK_3: *write_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_W; *read_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_R; *exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_F; @@ -262,33 +276,33 @@ static inline void esp_memprot_iram0_get_uni_block_sgnf_bits(uint32_t block, uin } } -static inline uint32_t esp_memprot_iram0_get_perm_uni_reg(void) +static inline uint32_t esp_memprot_iram0_sram_get_perm_uni_reg(void) { return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_1_REG); } -static inline uint32_t esp_memprot_iram0_get_perm_split_reg(void) +static inline uint32_t esp_memprot_iram0_sram_get_perm_split_reg(void) { return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_2_REG); } -static inline void esp_memprot_iram0_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx) +static inline void esp_memprot_iram0_sram_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx) { uint32_t addr = (uint32_t)split_addr; - assert( addr <= IRAM0_SPL_BLOCK_HIGH ); + assert(addr <= IRAM0_SRAM_SPL_BLOCK_HIGH); //find possible split.address in low region blocks int uni_blocks_low = -1; - if ( addr >= IRAM0_UNI_BLOCK_0_LOW ) { + if (addr >= IRAM0_SRAM_UNI_BLOCK_0_LOW) { uni_blocks_low++; } - if ( addr >= IRAM0_UNI_BLOCK_1_LOW ) { + if (addr >= IRAM0_SRAM_UNI_BLOCK_1_LOW) { uni_blocks_low++; } - if ( addr >= IRAM0_UNI_BLOCK_2_LOW ) { + if (addr >= IRAM0_SRAM_UNI_BLOCK_2_LOW) { uni_blocks_low++; } - if ( addr >= IRAM0_UNI_BLOCK_3_LOW ) { + if (addr >= IRAM0_SRAM_UNI_BLOCK_3_LOW) { uni_blocks_low++; } @@ -296,9 +310,9 @@ static inline void esp_memprot_iram0_set_prot(uint32_t *split_addr, bool lw, boo uint32_t write_bit, read_bit, exec_bit; uint32_t uni_block_perm = 0; - for ( size_t x = 0; x < IRAM0_TOTAL_UNI_BLOCKS; x++ ) { - esp_memprot_iram0_get_uni_block_sgnf_bits(x, &write_bit, &read_bit, &exec_bit); - if ( x <= uni_blocks_low ) { + for (size_t x = 0; x < IRAM0_SRAM_TOTAL_UNI_BLOCKS; x++) { + esp_memprot_iram0_sram_get_uni_block_sgnf_bits(x, &write_bit, &read_bit, &exec_bit); + if (x <= uni_blocks_low) { if (lw) { uni_block_perm |= write_bit; } @@ -324,85 +338,175 @@ static inline void esp_memprot_iram0_set_prot(uint32_t *split_addr, bool lw, boo //if splt.ddr not set yet, do required normalization to make the addr writeble into splt.mgmt cfg register uint32_t reg_split_addr = 0; - if ( addr >= IRAM0_SPL_BLOCK_LOW ) { + if (addr >= IRAM0_SRAM_SPL_BLOCK_LOW) { - //split Address must be WORD aligned + //[16:0] reg_split_addr = addr >> 2; assert(addr == (reg_split_addr << 2)); - - //use only 17 signf.bits as the cropped parts are constant for whole section (bits [16:0]) - reg_split_addr = (reg_split_addr << DPORT_PMS_PRO_IRAM0_SRAM_4_SPLTADDR_S) & DPORT_PMS_PRO_IRAM0_SRAM_4_SPLTADDR_M; + reg_split_addr &= DPORT_PMS_PRO_IRAM0_SRAM_4_SPLTADDR_M; } //prepare high & low permission mask (bits: [22:20] high range, [19:17] low range) uint32_t permission_mask = 0; - if ( lw ) { + if (lw) { permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_L_W; } - if ( lr ) { + if (lr) { permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_L_R; } - if ( lx ) { + if (lx) { permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_L_F; } - if ( hw ) { + if (hw) { permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_H_W; } - if ( hr ) { + if (hr) { permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_H_R; } - if ( hx ) { + if (hx) { permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_H_F; } - //write both cfg. registers - DPORT_WRITE_PERI_REG( DPORT_PMS_PRO_IRAM0_1_REG, uni_block_perm ); - DPORT_WRITE_PERI_REG( DPORT_PMS_PRO_IRAM0_2_REG, reg_split_addr | permission_mask ); + //write IRAM SRAM uni & splt cfg. registers + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_IRAM0_1_REG, uni_block_perm); + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_IRAM0_2_REG, (uint32_t)(reg_split_addr | permission_mask)); } -static inline void esp_memprot_iram0_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx) +static inline void esp_memprot_iram0_sram_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx) { - *lw = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_W ); - *lr = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_R ); - *lx = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_F ); - *hw = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_W ); - *hr = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_R ); - *hx = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_F ); + *lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_W); + *lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_R); + *lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_F); + *hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_W); + *hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_R); + *hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_F); } +static inline void esp_memprot_iram0_sram_set_read_perm(bool lr, bool hr) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_R, lr ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_R, hr ? 1 : 0); +} + +static inline void esp_memprot_iram0_sram_set_write_perm(bool lw, bool hw) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_W, lw ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_W, hw ? 1 : 0); +} + +static inline void esp_memprot_iram0_sram_set_exec_perm(bool lx, bool hx) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_F, lx ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_F, hx ? 1 : 0); +} + + /** - * === DRAM0 ==== + * ======================================================================================== + * === IRAM0 RTC FAST + * ======================================================================================== */ +#define IRAM0_RTCFAST_ADDRESS_LOW 0x40070000 +#define IRAM0_RTCFAST_ADDRESS_HIGH 0x40071FFF +#define IRAM0_RTCFAST_INTR_ST_FAULTADDR_HI 0x40070000 //RTCFAST faulting address high bits (31:22, constant) -#define DRAM0_TOTAL_UNI_BLOCKS 4 -#define DRAM0_UNI_BLOCK_0 0 -#define DRAM0_UNI_BLOCK_1 1 -#define DRAM0_UNI_BLOCK_2 2 -#define DRAM0_UNI_BLOCK_3 3 -#define DRAM0_SPL_BLOCK_BASE 0x3FFB0000 +static inline uint32_t *esp_memprot_iram0_rtcfast_get_fault_address(void) +{ + uint32_t status_bits = esp_memprot_iram0_get_fault_reg(); + return (uint32_t *)((status_bits & IRAM0_INTR_ST_FAULTADDR_M) | IRAM0_RTCFAST_INTR_ST_FAULTADDR_HI); +} -//unified management (SRAM blocks 0-3) -#define DRAM0_UNI_BLOCK_0_LOW 0x3FFB0000 -#define DRAM0_UNI_BLOCK_0_HIGH 0x3FFB1FFF -#define DRAM0_UNI_BLOCK_1_LOW 0x3FFB2000 -#define DRAM0_UNI_BLOCK_1_HIGH 0x3FFB3FFF -#define DRAM0_UNI_BLOCK_2_LOW 0x3FFB4000 -#define DRAM0_UNI_BLOCK_2_HIGH 0x3FFB5FFF -#define DRAM0_UNI_BLOCK_3_LOW 0x3FFB6000 -#define DRAM0_UNI_BLOCK_3_HIGH 0x3FFB7FFF +static inline bool esp_memprot_iram0_rtcfast_is_intr_mine(void) +{ + if (esp_memprot_iram0_is_assoc_intr()) { + uint32_t *faulting_address = esp_memprot_iram0_rtcfast_get_fault_address(); + return (uint32_t)faulting_address >= IRAM0_RTCFAST_ADDRESS_LOW && (uint32_t)faulting_address <= IRAM0_RTCFAST_ADDRESS_HIGH; + } + return false; +} -//split management (SRAM blocks 4-21) -#define DRAM0_SPL_BLOCK_LOW 0x3FFB8000 //block 4 low -#define DRAM0_SPL_BLOCK_HIGH 0x3FFFFFFF //block 21 high -#define DRAM0_SPLTADDR_MIN 0x3FFC0000 //block 6 low - minimum splitting address +static inline uint32_t esp_memprot_iram0_rtcfast_get_perm_split_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_3_REG); +} +static inline void esp_memprot_iram0_rtcfast_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx) +{ + uint32_t addr = (uint32_t)split_addr; + + //if splt.ddr not set yet, do required normalization to make the addr writeble into splt.mgmt cfg register + uint32_t reg_split_addr = 0; + + //[10:0] + reg_split_addr = addr >> 2; + assert(addr == (reg_split_addr << 2)); + reg_split_addr &= DPORT_PMS_PRO_IRAM0_RTCFAST_SPLTADDR_M; + + //prepare high & low permission mask (bits: [16:14] high range, [13:11] low range) + uint32_t permission_mask = 0; + if (lw) { + permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_L_W; + } + if (lr) { + permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_L_R; + } + if (lx) { + permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_L_F; + } + if (hw) { + permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_H_W; + } + if (hr) { + permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_H_R; + } + if (hx) { + permission_mask |= DPORT_PMS_PRO_IRAM0_RTCFAST_H_F; + } + + //write IRAM0 RTCFAST cfg register + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_IRAM0_3_REG, reg_split_addr | permission_mask); +} + +static inline void esp_memprot_iram0_rtcfast_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx) +{ + *lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_W); + *lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_R); + *lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_F); + *hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_W); + *hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_R); + *hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_F); +} + +static inline void esp_memprot_iram0_rtcfast_set_read_perm(bool lr, bool hr) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_R, lr ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_R, hr ? 1 : 0); +} + +static inline void esp_memprot_iram0_rtcfast_set_write_perm(bool lw, bool hw) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_W, lw ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_W, hw ? 1 : 0); +} + +static inline void esp_memprot_iram0_rtcfast_set_exec_perm(bool lx, bool hx) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_L_F, lx ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_IRAM0_3_REG, DPORT_PMS_PRO_IRAM0_RTCFAST_H_F, hx ? 1 : 0); +} + + +/** + * ======================================================================================== + * === DRAM0 common + * ======================================================================================== + */ //DRAM0 interrupt status bitmasks -#define DRAM0_INTR_ST_FAULTADDR_M 0x03FFFFC0 //(bits 25:6 in the reg) -#define DRAM0_INTR_ST_FAULTADDR_S 0x4 //(bits 21:2 of real address) -#define DRAM0_INTR_ST_FAULTADDR_HI 0x3FF00000 //(high nonsignificant bits 31:22 of the faulting address - constant) -#define DRAM0_INTR_ST_OP_RW_BIT BIT(4) //read: 0, write: 1 -#define DRAM0_INTR_ST_OP_ATOMIC_BIT BIT(5) //non-atomic: 0, atomic: 1 +#define DRAM0_INTR_ST_FAULTADDR_M 0x03FFFFC0 //(bits 25:6 in the reg) +#define DRAM0_INTR_ST_FAULTADDR_S 0x4 //(bits 21:2 of real address) +#define DRAM0_INTR_ST_OP_RW_BIT BIT(4) //read: 0, write: 1 +#define DRAM0_INTR_ST_OP_ATOMIC_BIT BIT(5) //non-atomic: 0, atomic: 1 static inline uint32_t esp_memprot_dram0_get_intr_source_num(void) @@ -412,10 +516,10 @@ static inline uint32_t esp_memprot_dram0_get_intr_source_num(void) static inline void esp_memprot_dram0_intr_ena(bool enable) { - if ( enable ) { - DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN ); + if (enable) { + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN); } else { - DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN ); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN); } } @@ -444,91 +548,10 @@ static inline uint32_t esp_memprot_dram0_get_intr_clr_bit(void) return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_CLR); } -static inline uint32_t esp_memprot_dram0_get_lock_bit(void) +//lock resets automatically on CPU restart +static inline void esp_memprot_dram0_set_lock(void) { - return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_0_REG, DPORT_PMS_PRO_DRAM0_LOCK); -} - -static inline void esp_memprot_dram0_get_uni_block_sgnf_bits(uint32_t block, uint32_t *write_bit, uint32_t *read_bit) -{ - assert(block < DRAM0_TOTAL_UNI_BLOCKS); - - switch ( block ) { - case DRAM0_UNI_BLOCK_0: - *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_0_W; - *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_0_R; - break; - case DRAM0_UNI_BLOCK_1: - *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_1_W; - *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_1_R; - break; - case DRAM0_UNI_BLOCK_2: - *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_2_W; - *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_2_R; - break; - case DRAM0_UNI_BLOCK_3: - *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_3_W; - *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_3_R; - break; - default: - abort(); - } -} - -static inline void esp_memprot_dram0_set_uni_block_perm(uint32_t block, bool write_perm, bool read_perm) -{ - assert(block < DRAM0_TOTAL_UNI_BLOCKS); - - uint32_t write_bit, read_bit; - esp_memprot_dram0_get_uni_block_sgnf_bits(block, &write_bit, &read_bit); - - if ( write_perm ) { - DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_1_REG, write_bit ); - } else { - DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_1_REG, write_bit ); - } - - if ( read_perm ) { - DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_1_REG, read_bit ); - } else { - DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_1_REG, read_bit ); - } -} - -static inline uint32_t esp_memprot_dram0_get_uni_block_read_bit(uint32_t block) -{ - assert(block < DRAM0_TOTAL_UNI_BLOCKS); - - switch ( block ) { - case DRAM0_UNI_BLOCK_0: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_0_R ); - case DRAM0_UNI_BLOCK_1: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_1_R ); - case DRAM0_UNI_BLOCK_2: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_2_R ); - case DRAM0_UNI_BLOCK_3: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_3_R ); - default: - abort(); - } -} - -static inline uint32_t esp_memprot_dram0_get_uni_block_write_bit(uint32_t block) -{ - assert(block < DRAM0_TOTAL_UNI_BLOCKS); - - switch ( block ) { - case DRAM0_UNI_BLOCK_0: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_0_W ); - case DRAM0_UNI_BLOCK_1: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_1_W ); - case DRAM0_UNI_BLOCK_2: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_2_W ); - case DRAM0_UNI_BLOCK_3: - return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_3_W ); - default: - abort(); - } + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DRAM0_0_REG, DPORT_PMS_PRO_DRAM0_LOCK); } static inline uint32_t esp_memprot_dram0_get_lock_reg(void) @@ -536,18 +559,12 @@ static inline uint32_t esp_memprot_dram0_get_lock_reg(void) return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_0_REG); } -//lock resets automatically on CPU restart -static inline void esp_memprot_dram0_set_lock(void) +static inline uint32_t esp_memprot_dram0_get_lock_bit(void) { - DPORT_WRITE_PERI_REG( DPORT_PMS_PRO_DRAM0_0_REG, DPORT_PMS_PRO_DRAM0_LOCK); + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_0_REG, DPORT_PMS_PRO_DRAM0_LOCK); } -static inline uint32_t esp_memprot_dram0_get_perm_reg(void) -{ - return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_1_REG); -} - -static inline uint32_t esp_memprot_dram0_get_ena_reg(void) +static inline uint32_t esp_memprot_dram0_get_conf_reg(void) { return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_3_REG); } @@ -557,44 +574,169 @@ static inline uint32_t esp_memprot_dram0_get_fault_reg(void) return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_4_REG); } -static inline void esp_memprot_dram0_get_fault_status(uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype) +static inline void esp_memprot_dram0_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype) { uint32_t status_bits = esp_memprot_dram0_get_fault_reg(); - - uint32_t fault_addr = (status_bits & DRAM0_INTR_ST_FAULTADDR_M) >> DRAM0_INTR_ST_FAULTADDR_S; - *faulting_address = (uint32_t *)(fault_addr | DRAM0_INTR_ST_FAULTADDR_HI); - - *op_type = (uint32_t)status_bits & DRAM0_INTR_ST_OP_RW_BIT; - *op_subtype = (uint32_t)status_bits & DRAM0_INTR_ST_OP_ATOMIC_BIT; + *op_type = status_bits & DRAM0_INTR_ST_OP_RW_BIT; + *op_subtype = status_bits & DRAM0_INTR_ST_OP_ATOMIC_BIT; } -static inline void esp_memprot_dram0_set_prot(uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr) + +/** + * ======================================================================================== + * === DRAM0 SRAM + * ======================================================================================== + */ +#define DRAM0_SRAM_ADDRESS_LOW 0x3FFB0000 +#define DRAM0_SRAM_ADDRESS_HIGH 0x3FFFFFFF + +#define DRAM0_SRAM_TOTAL_UNI_BLOCKS 4 +#define DRAM0_SRAM_UNI_BLOCK_0 0 +#define DRAM0_SRAM_UNI_BLOCK_1 1 +#define DRAM0_SRAM_UNI_BLOCK_2 2 +#define DRAM0_SRAM_UNI_BLOCK_3 3 + +//unified management (SRAM blocks 0-3) +#define DRAM0_SRAM_UNI_BLOCK_0_LOW 0x3FFB0000 +#define DRAM0_SRAM_UNI_BLOCK_1_LOW 0x3FFB2000 +#define DRAM0_SRAM_UNI_BLOCK_2_LOW 0x3FFB4000 +#define DRAM0_SRAM_UNI_BLOCK_3_LOW 0x3FFB6000 + +//split management (SRAM blocks 4-21) +#define DRAM0_SRAM_SPL_BLOCK_HIGH 0x3FFFFFFF //block 21 high +#define DRAM0_SRAM_INTR_ST_FAULTADDR_HI 0x3FF00000 //SRAM high bits 31:22 of the faulting address - constant + + +static inline uint32_t *esp_memprot_dram0_sram_get_fault_address(void) +{ + uint32_t status_bits = esp_memprot_dram0_get_fault_reg(); + return (uint32_t *)(((status_bits & DRAM0_INTR_ST_FAULTADDR_M) >> DRAM0_INTR_ST_FAULTADDR_S) | DRAM0_SRAM_INTR_ST_FAULTADDR_HI); +} + +static inline bool esp_memprot_dram0_sram_is_intr_mine(void) +{ + if (esp_memprot_dram0_is_assoc_intr()) { + uint32_t *faulting_address = esp_memprot_dram0_sram_get_fault_address(); + return (uint32_t)faulting_address >= DRAM0_SRAM_ADDRESS_LOW && (uint32_t)faulting_address <= DRAM0_SRAM_ADDRESS_HIGH; + } + return false; +} + +static inline void esp_memprot_dram0_sram_get_uni_block_sgnf_bits(uint32_t block, uint32_t *write_bit, uint32_t *read_bit) +{ + assert(block < DRAM0_SRAM_TOTAL_UNI_BLOCKS); + + switch (block) { + case DRAM0_SRAM_UNI_BLOCK_0: + *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_0_W; + *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_0_R; + break; + case DRAM0_SRAM_UNI_BLOCK_1: + *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_1_W; + *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_1_R; + break; + case DRAM0_SRAM_UNI_BLOCK_2: + *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_2_W; + *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_2_R; + break; + case DRAM0_SRAM_UNI_BLOCK_3: + *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_3_W; + *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_3_R; + break; + default: + abort(); + } +} + +static inline void esp_memprot_dram0_sram_set_uni_block_perm(uint32_t block, bool write_perm, bool read_perm) +{ + assert(block < DRAM0_SRAM_TOTAL_UNI_BLOCKS); + + uint32_t write_bit, read_bit; + esp_memprot_dram0_sram_get_uni_block_sgnf_bits(block, &write_bit, &read_bit); + + if (write_perm) { + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_1_REG, write_bit); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_1_REG, write_bit); + } + + if (read_perm) { + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_1_REG, read_bit); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_1_REG, read_bit); + } +} + +static inline uint32_t esp_memprot_dram0_sram_get_uni_block_read_bit(uint32_t block) +{ + assert(block < DRAM0_SRAM_TOTAL_UNI_BLOCKS); + + switch (block) { + case DRAM0_SRAM_UNI_BLOCK_0: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_0_R); + case DRAM0_SRAM_UNI_BLOCK_1: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_1_R); + case DRAM0_SRAM_UNI_BLOCK_2: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_2_R); + case DRAM0_SRAM_UNI_BLOCK_3: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_3_R); + default: + abort(); + } +} + +static inline uint32_t esp_memprot_dram0_sram_get_uni_block_write_bit(uint32_t block) +{ + assert(block < DRAM0_SRAM_TOTAL_UNI_BLOCKS); + + switch (block) { + case DRAM0_SRAM_UNI_BLOCK_0: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_0_W); + case DRAM0_SRAM_UNI_BLOCK_1: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_1_W); + case DRAM0_SRAM_UNI_BLOCK_2: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_2_W); + case DRAM0_SRAM_UNI_BLOCK_3: + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_3_W); + default: + abort(); + } +} + +//DRAM0 has both unified blocks and split address configured in 1 register +static inline uint32_t esp_memprot_dram0_sram_get_perm_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_1_REG); +} + +static inline void esp_memprot_dram0_sram_set_prot(uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr) { uint32_t addr = (uint32_t)split_addr; - //low boundary check provided by LD script. see comment in esp_memprot_iram0_set_prot() - assert( addr <= DRAM0_SPL_BLOCK_HIGH ); + //low boundary check provided by LD script. see comment in esp_memprot_iram0_sram_set_prot() + assert( addr <= DRAM0_SRAM_SPL_BLOCK_HIGH ); //set low region int uni_blocks_low = -1; - if ( addr >= DRAM0_UNI_BLOCK_0_LOW ) { + if (addr >= DRAM0_SRAM_UNI_BLOCK_0_LOW) { uni_blocks_low++; } - if ( addr >= DRAM0_UNI_BLOCK_1_LOW ) { + if (addr >= DRAM0_SRAM_UNI_BLOCK_1_LOW) { uni_blocks_low++; } - if ( addr >= DRAM0_UNI_BLOCK_2_LOW ) { + if (addr >= DRAM0_SRAM_UNI_BLOCK_2_LOW) { uni_blocks_low++; } - if ( addr >= DRAM0_UNI_BLOCK_3_LOW ) { + if (addr >= DRAM0_SRAM_UNI_BLOCK_3_LOW) { uni_blocks_low++; } //set unified mgmt region uint32_t write_bit, read_bit, uni_block_perm = 0; - for ( size_t x = 0; x < DRAM0_TOTAL_UNI_BLOCKS; x++ ) { - esp_memprot_dram0_get_uni_block_sgnf_bits(x, &write_bit, &read_bit); - if ( x <= uni_blocks_low ) { + for (size_t x = 0; x < DRAM0_SRAM_TOTAL_UNI_BLOCKS; x++) { + esp_memprot_dram0_sram_get_uni_block_sgnf_bits(x, &write_bit, &read_bit); + if (x <= uni_blocks_low) { if (lw) { uni_block_perm |= write_bit; } @@ -611,12 +753,10 @@ static inline void esp_memprot_dram0_set_prot(uint32_t *split_addr, bool lw, boo } } - //check split address is WORD aligned + //[24:8] uint32_t reg_split_addr = addr >> 2; assert(addr == (reg_split_addr << 2)); - - //shift aligned split address to proper bit offset - reg_split_addr = (reg_split_addr << DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_S) & DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_M; + reg_split_addr = (reg_split_addr & DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_V) << DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_S; //prepare high & low permission mask uint32_t permission_mask = 0; @@ -633,18 +773,108 @@ static inline void esp_memprot_dram0_set_prot(uint32_t *split_addr, bool lw, boo permission_mask |= DPORT_PMS_PRO_DRAM0_SRAM_4_H_R; } - //write configuration to DPORT_PMS_PRO_DRAM0_1_REG + //write DRAM0 SRAM cfg register DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DRAM0_1_REG, reg_split_addr | permission_mask | uni_block_perm); } -static inline void esp_memprot_dram0_get_split_sgnf_bits(bool *lw, bool *lr, bool *hw, bool *hr) +static inline void esp_memprot_dram0_sram_get_split_sgnf_bits(bool *lw, bool *lr, bool *hw, bool *hr) { - *lw = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_W ); - *lr = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_R ); - *hw = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_W ); - *hr = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_R ); + *lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_W); + *lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_R); + *hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_W); + *hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_R); } +static inline void esp_memprot_dram0_sram_set_read_perm(bool lr, bool hr) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_R, lr ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_R, hr ? 1 : 0); +} + +static inline void esp_memprot_dram0_sram_set_write_perm(bool lw, bool hw) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_W, lw ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_W, hw ? 1 : 0); +} + + +/** + * ======================================================================================== + * === DRAM0 RTC FAST + * ======================================================================================== + */ +#define DRAM0_RTCFAST_ADDRESS_LOW 0x3FF9E000 +#define DRAM0_RTCFAST_ADDRESS_HIGH 0x3FF9FFFF +#define DRAM0_RTCFAST_INTR_ST_FAULTADDR_HI 0x3FF00000 //RTCFAST high bits 31:22 of the faulting address - constant + + +static inline uint32_t *esp_memprot_dram0_rtcfast_get_fault_address(void) +{ + uint32_t status_bits = esp_memprot_dram0_get_fault_reg(); + return (uint32_t *)(((status_bits & DRAM0_INTR_ST_FAULTADDR_M) >> DRAM0_INTR_ST_FAULTADDR_S) | DRAM0_RTCFAST_INTR_ST_FAULTADDR_HI); +} + +static inline bool esp_memprot_dram0_rtcfast_is_intr_mine(void) +{ + if (esp_memprot_dram0_is_assoc_intr()) { + uint32_t *faulting_address = esp_memprot_dram0_rtcfast_get_fault_address(); + return (uint32_t)faulting_address >= DRAM0_RTCFAST_ADDRESS_LOW && (uint32_t)faulting_address <= DRAM0_RTCFAST_ADDRESS_HIGH; + } + return false; +} + +static inline void esp_memprot_dram0_rtcfast_set_prot(uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr) +{ + uint32_t addr = (uint32_t)split_addr; + + //[10:0] + uint32_t reg_split_addr = addr >> 2; + assert(addr == (reg_split_addr << 2)); + reg_split_addr &= DPORT_PMS_PRO_DRAM0_RTCFAST_SPLTADDR_M; + + //prepare high & low permission mask + uint32_t permission_mask = 0; + if (lw) { + permission_mask |= DPORT_PMS_PRO_DRAM0_RTCFAST_L_W; + } + if (lr) { + permission_mask |= DPORT_PMS_PRO_DRAM0_RTCFAST_L_R; + } + if (hw) { + permission_mask |= DPORT_PMS_PRO_DRAM0_RTCFAST_H_W; + } + if (hr) { + permission_mask |= DPORT_PMS_PRO_DRAM0_RTCFAST_H_R; + } + + //write DRAM0 RTC FAST cfg register + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DRAM0_2_REG, reg_split_addr | permission_mask); +} + +static inline void esp_memprot_dram0_rtcfast_get_split_sgnf_bits(bool *lw, bool *lr, bool *hw, bool *hr) +{ + *lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_L_W); + *lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_L_R); + *hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_H_W); + *hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_H_R); +} + +static inline uint32_t esp_memprot_dram0_rtcfast_get_perm_split_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_2_REG); +} + +static inline void esp_memprot_dram0_rtcfast_set_read_perm(bool lr, bool hr) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_L_R, lr ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_H_R, hr ? 1 : 0); +} + +static inline void esp_memprot_dram0_rtcfast_set_write_perm(bool lw, bool hw) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_L_W, lw ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DRAM0_2_REG, DPORT_PMS_PRO_DRAM0_RTCFAST_H_W, hw ? 1 : 0); +} #ifdef __cplusplus } diff --git a/components/soc/src/esp32s2/include/hal/memprot_peri_ll.h b/components/soc/src/esp32s2/include/hal/memprot_peri_ll.h new file mode 100644 index 0000000000..35dc03cefc --- /dev/null +++ b/components/soc/src/esp32s2/include/hal/memprot_peri_ll.h @@ -0,0 +1,453 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define RTCSLOW_MEMORY_SIZE 0x00002000 + +/** + * ======================================================================================== + * === PeriBus1 common + * ======================================================================================== + */ +//PeriBus1 interrupt status bitmasks +#define PERI1_INTR_ST_OP_TYPE_BIT BIT(4) //0: non-atomic, 1: atomic +#define PERI1_INTR_ST_OP_HIGH_BITS BIT(5) //0: high bits = unchanged, 1: high bits = 0x03F40000 +#define PERI1_INTR_ST_FAULTADDR_M 0x03FFFFC0 //(bits 25:6 in the reg) +#define PERI1_INTR_ST_FAULTADDR_S 0x4 //(bits 21:2 of real address) + +static inline void esp_memprot_peri1_clear_intr(void) +{ + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_CLR); +} + +static inline uint32_t esp_memprot_peri1_get_intr_source_num(void) +{ + return ETS_PMS_PRO_DPORT_ILG_INTR_SOURCE; +} + +static inline void esp_memprot_peri1_intr_ena(bool enable) +{ + if (enable) { + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_EN); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_EN); + } +} + +static inline uint32_t esp_memprot_peri1_get_ctrl_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_6_REG); +} + +static inline uint32_t esp_memprot_peri1_get_fault_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_7_REG); +} + +static inline void esp_memprot_peri1_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype) +{ + uint32_t status_bits = esp_memprot_peri1_get_fault_reg(); + //*op_type = (uint32_t)status_bits & PERI1_INTR_ST_OP_RW_BIT; + *op_type = 0; + //! DPORT_PMS_PRO_DPORT_7_REG is missing op_type bit + *op_subtype = (uint32_t)status_bits & PERI1_INTR_ST_OP_TYPE_BIT; +} + +static inline bool esp_memprot_peri1_is_assoc_intr(void) +{ + return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_DPORT_7_REG, DPORT_PMS_PRO_DPORT_ILG_INTR) > 0; +} + +static inline uint32_t esp_memprot_peri1_get_intr_ena_bit(void) +{ + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_EN); +} + +static inline uint32_t esp_memprot_peri1_get_intr_on_bit(void) +{ + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_INTR); +} + +static inline uint32_t esp_memprot_peri1_get_intr_clr_bit(void) +{ + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_6_REG, DPORT_PMS_PRO_DPORT_ILG_CLR); +} + +static inline uint32_t esp_memprot_peri1_get_lock_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_0_REG); +} + +//resets automatically on CPU restart +static inline void esp_memprot_peri1_set_lock(void) +{ + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DPORT_0_REG, DPORT_PMS_PRO_DPORT_LOCK); +} + +static inline uint32_t esp_memprot_peri1_get_lock_bit(void) +{ + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_0_REG, DPORT_PMS_PRO_DPORT_LOCK); +} + + +/** + * ======================================================================================== + * === PeriBus1 RTC SLOW + * ======================================================================================== + */ +#define PERI1_RTCSLOW_ADDRESS_BASE 0x3F421000 +#define PERI1_RTCSLOW_ADDRESS_LOW PERI1_RTCSLOW_ADDRESS_BASE +#define PERI1_RTCSLOW_ADDRESS_HIGH PERI1_RTCSLOW_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE +#define PERI1_RTCSLOW_INTR_ST_FAULTADDR_HI_0 0x3F400000 + + +static inline uint32_t *esp_memprot_peri1_rtcslow_get_fault_address(void) +{ + uint32_t status_bits = esp_memprot_peri1_get_fault_reg(); + uint32_t fault_address = (status_bits & PERI1_INTR_ST_FAULTADDR_M) >> PERI1_INTR_ST_FAULTADDR_S; + uint32_t high_bits = (status_bits & PERI1_INTR_ST_OP_HIGH_BITS) ? PERI1_RTCSLOW_INTR_ST_FAULTADDR_HI_0 : 0; + return (uint32_t *)(fault_address | high_bits); +} + +static inline bool esp_memprot_peri1_rtcslow_is_intr_mine(void) +{ + if (esp_memprot_dram0_is_assoc_intr()) { + uint32_t *faulting_address = esp_memprot_peri1_rtcslow_get_fault_address(); + return (uint32_t)faulting_address >= PERI1_RTCSLOW_ADDRESS_LOW && (uint32_t)faulting_address <= PERI1_RTCSLOW_ADDRESS_HIGH; + } + return false; +} + +static inline void esp_memprot_peri1_rtcslow_set_prot(uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr) +{ + uint32_t addr = (uint32_t)split_addr; + + //check split address is WORD aligned + uint32_t reg_split_addr = addr >> 2; + assert(addr == (reg_split_addr << 2)); + reg_split_addr &= DPORT_PMS_PRO_DPORT_RTCSLOW_SPLTADDR_M; + + //prepare high & low permission mask + uint32_t permission_mask = 0; + if (lw) { + permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_L_W; + } + if (lr) { + permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_L_R; + } + if (hw) { + permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_H_W; + } + if (hr) { + permission_mask |= DPORT_PMS_PRO_DPORT_RTCSLOW_H_R; + } + + //write PERIBUS1 RTC SLOW cfg register + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DPORT_1_REG, reg_split_addr | permission_mask); +} + +static inline void esp_memprot_peri1_rtcslow_get_split_sgnf_bits(bool *lw, bool *lr, bool *hw, bool *hr) +{ + *lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_W); + *lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_R); + *hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_W); + *hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_R); +} + +static inline void esp_memprot_peri1_rtcslow_set_read_perm(bool lr, bool hr) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_R, lr ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_R, hr ? 1 : 0); +} + +static inline void esp_memprot_peri1_rtcslow_set_write_perm(bool lw, bool hw) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_L_W, lw ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_DPORT_1_REG, DPORT_PMS_PRO_DPORT_RTCSLOW_H_W, hw ? 1 : 0); +} + +static inline uint32_t esp_memprot_peri1_rtcslow_get_conf_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_1_REG); +} + + +/** + * ======================================================================================== + * === PeriBus2 common + * ======================================================================================== + */ +//PeriBus2 interrupt status bitmasks +#define PERI2_INTR_ST_OP_TYPE_BIT BIT(1) //instruction: 0, data: 1 +#define PERI2_INTR_ST_OP_RW_BIT BIT(0) //read: 0, write: 1 +#define PERI2_INTR_ST_FAULTADDR_M 0xFFFFFFFC //(bits 31:2 in the reg) + +static inline void esp_memprot_peri2_clear_intr(void) +{ + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_CLR); +} + +static inline uint32_t esp_memprot_peri2_get_intr_source_num(void) +{ + return ETS_PMS_PRO_AHB_ILG_INTR_SOURCE; +} + +static inline void esp_memprot_peri2_intr_ena(bool enable) +{ + if (enable) { + DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_EN); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_EN); + } +} + +static inline uint32_t esp_memprot_peri2_get_ctrl_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_AHB_3_REG); +} + +static inline uint32_t esp_memprot_peri2_get_fault_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_AHB_4_REG); +} + +static inline void esp_memprot_peri2_get_fault_op_type(uint32_t *op_type, uint32_t *op_subtype) +{ + uint32_t status_bits = esp_memprot_peri2_get_fault_reg(); + *op_type = (uint32_t)status_bits & PERI2_INTR_ST_OP_RW_BIT; + *op_subtype = (uint32_t)status_bits & PERI2_INTR_ST_OP_TYPE_BIT; +} + +static inline bool esp_memprot_peri2_is_assoc_intr(void) +{ + return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_INTR) > 0; +} + +static inline uint32_t esp_memprot_peri2_get_intr_ena_bit(void) +{ + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_EN); +} + +static inline uint32_t esp_memprot_peri2_get_intr_on_bit(void) +{ + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_INTR); +} + +static inline uint32_t esp_memprot_peri2_get_intr_clr_bit(void) +{ + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_3_REG, DPORT_PMS_PRO_AHB_ILG_CLR); +} + +static inline uint32_t esp_memprot_peri2_get_lock_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_AHB_0_REG); +} + +//resets automatically on CPU restart +static inline void esp_memprot_peri2_set_lock(void) +{ + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_AHB_0_REG, DPORT_PMS_PRO_AHB_LOCK); +} + +static inline uint32_t esp_memprot_peri2_get_lock_bit(void) +{ + return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_0_REG, DPORT_PMS_PRO_AHB_LOCK); +} + +static inline uint32_t *esp_memprot_peri2_rtcslow_get_fault_address(void) +{ + uint32_t status_bits = esp_memprot_peri2_get_fault_reg(); + return (uint32_t *)(status_bits & PERI2_INTR_ST_FAULTADDR_M); +} + + +/** + * ======================================================================================== + * === PeriBus2 RTC SLOW 0 (AHB0) + * ======================================================================================== + */ +#define PERI2_RTCSLOW_0_ADDRESS_BASE 0x50000000 +#define PERI2_RTCSLOW_0_ADDRESS_LOW PERI2_RTCSLOW_0_ADDRESS_BASE +#define PERI2_RTCSLOW_0_ADDRESS_HIGH PERI2_RTCSLOW_0_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE + +static inline bool esp_memprot_peri2_rtcslow_0_is_intr_mine(void) +{ + if (esp_memprot_peri2_is_assoc_intr()) { + uint32_t *faulting_address = esp_memprot_peri2_rtcslow_get_fault_address(); + return (uint32_t)faulting_address >= PERI2_RTCSLOW_0_ADDRESS_LOW && (uint32_t)faulting_address <= PERI2_RTCSLOW_0_ADDRESS_HIGH; + } + return false; +} + +static inline void esp_memprot_peri2_rtcslow_0_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx) +{ + uint32_t addr = (uint32_t)split_addr; + + //check split address is WORD aligned + uint32_t reg_split_addr = addr >> 2; + assert(addr == (reg_split_addr << 2)); + reg_split_addr &= DPORT_PMS_PRO_AHB_RTCSLOW_0_SPLTADDR_M; + + //prepare high & low permission mask + uint32_t permission_mask = 0; + if (lw) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_L_W; + } + if (lr) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_L_R; + } + if (lx) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_L_F; + } + if (hw) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_H_W; + } + if (hr) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_H_R; + } + if (hx) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_0_H_F; + } + + //write PERIBUS1 RTC SLOW cfg register + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_AHB_1_REG, reg_split_addr | permission_mask); +} + +static inline void esp_memprot_peri2_rtcslow_0_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx) +{ + *lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_W); + *lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_R); + *lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_F); + *hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_W); + *hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_R); + *hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_F); +} + +static inline void esp_memprot_peri2_rtcslow_0_set_read_perm(bool lr, bool hr) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_R, lr ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_R, hr ? 1 : 0); +} + +static inline void esp_memprot_peri2_rtcslow_0_set_write_perm(bool lw, bool hw) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_W, lw ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_W, hw ? 1 : 0); +} + +static inline void esp_memprot_peri2_rtcslow_0_set_exec_perm(bool lx, bool hx) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_L_F, lx ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_1_REG, DPORT_PMS_PRO_AHB_RTCSLOW_0_H_F, hx ? 1 : 0); +} + +static inline uint32_t esp_memprot_peri2_rtcslow_0_get_conf_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_1_REG); +} + +/** + * ======================================================================================== + * === PeriBus2 RTC SLOW 1 (AHB1) + * ======================================================================================== + */ +#define PERI2_RTCSLOW_1_ADDRESS_BASE 0x60021000 +#define PERI2_RTCSLOW_1_ADDRESS_LOW PERI2_RTCSLOW_1_ADDRESS_BASE +#define PERI2_RTCSLOW_1_ADDRESS_HIGH PERI2_RTCSLOW_1_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE + + +static inline bool esp_memprot_peri2_rtcslow_1_is_intr_mine(void) +{ + if (esp_memprot_peri2_is_assoc_intr()) { + uint32_t *faulting_address = esp_memprot_peri2_rtcslow_get_fault_address(); + return (uint32_t)faulting_address >= PERI2_RTCSLOW_1_ADDRESS_LOW && (uint32_t)faulting_address <= PERI2_RTCSLOW_1_ADDRESS_HIGH; + } + return false; +} + +static inline void esp_memprot_peri2_rtcslow_1_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx) +{ + uint32_t addr = (uint32_t)split_addr; + + //check split address is WORD aligned + uint32_t reg_split_addr = addr >> 2; + assert(addr == (reg_split_addr << 2)); + reg_split_addr &= DPORT_PMS_PRO_AHB_RTCSLOW_1_SPLTADDR_M; + + //prepare high & low permission mask + uint32_t permission_mask = 0; + if (lw) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_L_W; + } + if (lr) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_L_R; + } + if (lx) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_L_F; + } + if (hw) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_H_W; + } + if (hr) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_H_R; + } + if (hx) { + permission_mask |= DPORT_PMS_PRO_AHB_RTCSLOW_1_H_F; + } + + //write PERIBUS1 RTC SLOW cfg register + DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_AHB_2_REG, reg_split_addr | permission_mask); +} + +static inline void esp_memprot_peri2_rtcslow_1_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx) +{ + *lw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_W); + *lr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_R); + *lx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_F); + *hw = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_W); + *hr = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_R); + *hx = DPORT_REG_GET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_F); +} + +static inline void esp_memprot_peri2_rtcslow_1_set_read_perm(bool lr, bool hr) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_R, lr ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_R, hr ? 1 : 0); +} + +static inline void esp_memprot_peri2_rtcslow_1_set_write_perm(bool lw, bool hw) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_W, lw ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_W, hw ? 1 : 0); +} + +static inline void esp_memprot_peri2_rtcslow_1_set_exec_perm(bool lx, bool hx) +{ + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_L_F, lx ? 1 : 0); + DPORT_REG_SET_FIELD(DPORT_PMS_PRO_AHB_2_REG, DPORT_PMS_PRO_AHB_RTCSLOW_1_H_F, hx ? 1 : 0); +} + +static inline uint32_t esp_memprot_peri2_rtcslow_1_get_conf_reg(void) +{ + return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DPORT_2_REG); +} + +#ifdef __cplusplus +} +#endif diff --git a/tools/ci/config/target-test.yml b/tools/ci/config/target-test.yml index 8737fb0be4..40b8c73210 100644 --- a/tools/ci/config/target-test.yml +++ b/tools/ci/config/target-test.yml @@ -415,6 +415,12 @@ test_app_test_003: - ESP32 - Example_PPP +test_app_test_004: + extends: .test_app_template + tags: + - ESP32S2 + - Example_GENERIC + component_ut_test_001: extends: .component_ut_template tags: diff --git a/tools/test_apps/system/memprot/CMakeLists.txt b/tools/test_apps/system/memprot/CMakeLists.txt new file mode 100644 index 0000000000..2d649a57e8 --- /dev/null +++ b/tools/test_apps/system/memprot/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.5) + +if(IDF_TARGET STREQUAL "esp32s2") + include($ENV{IDF_PATH}/tools/cmake/project.cmake) + project(test_memprot) + + target_link_libraries(${project_elf} "-Wl,--wrap=esp_panic_handler") + +endif() diff --git a/tools/test_apps/system/memprot/app_test.py b/tools/test_apps/system/memprot/app_test.py new file mode 100644 index 0000000000..fbc3ec2269 --- /dev/null +++ b/tools/test_apps/system/memprot/app_test.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +import ttfw_idf +from tiny_test_fw import Utility + + +mem_test = [ + ['IRAM0_SRAM', 'WRX'], + ['IRAM0_RTCFAST', 'WRX'], + ['DRAM0_SRAM', 'WR'], + ['DRAM0_RTCFAST', 'WR'], + ['PERI1_RTCSLOW', 'WR'], + ['PERI2_RTCSLOW_0', 'WRX'], + ['PERI2_RTCSLOW_1', 'WRX'] +] + + +@ttfw_idf.idf_custom_test(env_tag="Example_GENERIC", target="esp32s2", group="test-apps") +def test_memprot(env, extra_data): + + dut = env.get_dut("memprot", "tools/test_apps/system/memprot") + dut.start_app() + + for i in mem_test: + if 'R' in i[1]: + dut.expect(i[0] + " read low: OK") + dut.expect(i[0] + " read high: OK") + if 'W' in i[1]: + dut.expect(i[0] + " write low: OK") + dut.expect(i[0] + " write high: OK") + if 'X' in i[1]: + dut.expect(i[0] + " exec low: OK") + dut.expect(i[0] + " exec high: OK") + + Utility.console_log("Memprot test done") + + +if __name__ == '__main__': + test_memprot() diff --git a/tools/test_apps/system/memprot/main/CMakeLists.txt b/tools/test_apps/system/memprot/main/CMakeLists.txt new file mode 100644 index 0000000000..f833245af5 --- /dev/null +++ b/tools/test_apps/system/memprot/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "test_memprot_main.c" "test_panic.c" + INCLUDE_DIRS "") \ No newline at end of file diff --git a/tools/test_apps/system/memprot/main/test_memprot_main.c b/tools/test_apps/system/memprot/main/test_memprot_main.c new file mode 100644 index 0000000000..6571d3ce0c --- /dev/null +++ b/tools/test_apps/system/memprot/main/test_memprot_main.c @@ -0,0 +1,484 @@ +/* MEMPROT IramDram testing code */ +#include +#include "sdkconfig.h" +#include "esp_spi_flash.h" +#include "esp32s2/memprot.h" +#include +#include "esp_log.h" + +/* + * ESP32S2 MEMORY PROTECTION MODULE TEST + * ===================================== + * + * In order to safely test all the mem_prot features, this test uses a proprietary setting + * for all splitting addresses, ie it partially overrides production settings. + * Each operation is tested at [test-splitting-addr - 16B] (low region) and + * [test-splitting-addr + 16B] (high region). Complete testing scheme + * is depicted below, the addresses used come from this application binary: + * + * ******************************************************************************************** + * + * IRAM0 SRAM (320kB) DRAM0 + * =========================== + * (_iram_text_end) | | (_data_start) + * 0x4002B51C(!) <-------- real splt.addr --------> 0x3FFBB520 + * | | + * 0x4002DA30 <---|-------------------------|--> 0x3FFBDA30 + * | test buffer (64 kB) | + * | ... | + * 0x40035A30 <-------- test splt.addr --------> 0x3FFC5A30 + * | ... | + * |-------------------------| + * | | + * =========================== + * + * RTC_FAST (8kB) + * (_rtc_text_end) =========================== (_rtc_dummy_end) + * 0x40070000 <-------- real splt.addr --------> 0x3FF9E000 + * | | + * | test buffer (7 kB) | + * | ... | + * 0x40070E00 <-------- test splt.addr --------> 0x3FF9EE00 + * | ... | + * |-------------------------| + * | | + * =========================== + * + * ******************************************************************************************** + * + * PERIBUS_1 RTC_SLOW (8/768kB) PERIBUS_2_0 PERIBUS_2_1 + * =========================== + * | | + * 0x3F421000 <-------- real splt.addr --------> 0x50000000 0x60021000 + * | | + * | test buffer (7 kB) | + * | ... | + * 0x3F421E00 <-------- test splt.addr --------> 0x50000E00 0x60021E00 + * | ... | + * |-------------------------| + * | | + * =========================== + * + * ******************************************************************************************** + */ + + +/* !!!IMPORTANT!!! + * a0 needs to be saved/restored manually (not clobbered) to avoid return address corruption + * caused by ASM block handling + */ +#define CODE_EXEC(code_buf, param, res) \ + asm volatile ( \ + "mov a3, a0\n\t" \ + "movi a2," #param "\n\t" \ + "callx0 %1\n\t" \ + "mov %0,a2\n\t" \ + "mov a0, a3\n\t" \ + : "=r"(res) \ + : "r"(code_buf) \ + : "a2", "a3" ); + +/* Binary code for the following asm: + * + .type _testfunc,@function + .global _testfunc + .align 4 + + _testfunc: + slli a2, a2, 1 + ret.n + */ +static uint8_t fnc_call0_buff[] = {0xf0, 0x22, 0x11, 0x0d, 0xf0, 0x00, 0x00, 0x00}; + +#define SRAM_DUMMY_BUFFER_SIZE 64*1024 +#define RTCFAST_DUMMY_BUFFER_SIZE 7*1024 +#define RTCSLOW_DUMMY_BUFFER_SIZE 7*1024 + +volatile bool g_override_illegal_instruction = false; + +static uint8_t sram_dummy_buffer[SRAM_DUMMY_BUFFER_SIZE] = {0}; +static uint8_t RTC_FAST_ATTR rtcfast_dummy_buffer[RTCFAST_DUMMY_BUFFER_SIZE] = {0}; +static uint8_t RTC_SLOW_ATTR rtcslow_dummy_buffer[RTCSLOW_DUMMY_BUFFER_SIZE] = {0}; + + +/* ******************************************************************************************** + * testing regions and splitting address scheme + * + */ +static uint32_t *test_memprot_dram0_sram_get_min_split_addr(void) +{ + return (uint32_t *)(sram_dummy_buffer + sizeof(sram_dummy_buffer) / 2); +} + +static uint32_t *test_memprot_dram0_rtcfast_get_min_split_addr(void) +{ + return (uint32_t *)(rtcfast_dummy_buffer + sizeof(rtcfast_dummy_buffer) / 2); +} + +static uint32_t *test_memprot_iram0_sram_get_min_split_addr(void) +{ + return (uint32_t *) + ((uint32_t)test_memprot_dram0_sram_get_min_split_addr() + + + esp_memprot_get_low_limit(MEMPROT_IRAM0_SRAM) + - esp_memprot_get_low_limit(MEMPROT_DRAM0_SRAM)); +} + +static uint32_t *test_memprot_iram0_rtcfast_get_min_split_addr(void) +{ + return (uint32_t *) + ((uint32_t)test_memprot_dram0_rtcfast_get_min_split_addr() + + esp_memprot_get_low_limit(MEMPROT_IRAM0_RTCFAST) + - esp_memprot_get_low_limit(MEMPROT_DRAM0_RTCFAST)); +} + +static uint32_t *test_memprot_peri2_rtcslow_0_get_min_split_addr(void) +{ + return (uint32_t *)(rtcslow_dummy_buffer + sizeof(rtcslow_dummy_buffer) / 2); +} + +static uint32_t *test_memprot_peri1_rtcslow_get_min_split_addr(void) +{ + return (uint32_t *) + ((uint32_t)test_memprot_peri2_rtcslow_0_get_min_split_addr() + - (esp_memprot_get_low_limit(MEMPROT_PERI2_RTCSLOW_0) + - esp_memprot_get_low_limit(MEMPROT_PERI1_RTCSLOW))); +} + +static uint32_t *test_memprot_peri2_rtcslow_1_get_min_split_addr(void) +{ + return (uint32_t *) + ((uint32_t)test_memprot_peri2_rtcslow_0_get_min_split_addr() + + esp_memprot_get_low_limit(MEMPROT_PERI2_RTCSLOW_1) + - esp_memprot_get_low_limit(MEMPROT_PERI2_RTCSLOW_0)); +} + +static uint32_t *test_memprot_get_split_addr(mem_type_prot_t mem_type) +{ + switch (mem_type) { + case MEMPROT_IRAM0_SRAM: + return test_memprot_iram0_sram_get_min_split_addr(); + case MEMPROT_DRAM0_SRAM: + return test_memprot_dram0_sram_get_min_split_addr(); + case MEMPROT_IRAM0_RTCFAST: + return test_memprot_iram0_rtcfast_get_min_split_addr(); + case MEMPROT_DRAM0_RTCFAST: + return test_memprot_dram0_rtcfast_get_min_split_addr(); + case MEMPROT_PERI1_RTCSLOW: + return test_memprot_peri1_rtcslow_get_min_split_addr(); + case MEMPROT_PERI2_RTCSLOW_0: + return test_memprot_peri2_rtcslow_0_get_min_split_addr(); + case MEMPROT_PERI2_RTCSLOW_1: + return test_memprot_peri2_rtcslow_1_get_min_split_addr(); + default: + abort(); + } +} + + +/* + * testing setup of the memory-protection module + */ +static void test_memprot_set_prot(uint32_t *mem_type_mask, bool use_panic_handler) +{ + //any IRAM0/DRAM0 enable/disable call applies to all memory modules connected + uint32_t required_mem_prot = mem_type_mask == NULL ? (uint32_t)MEMPROT_ALL : *mem_type_mask; + bool use_iram0 = required_mem_prot & MEMPROT_IRAM0_SRAM || required_mem_prot & MEMPROT_IRAM0_RTCFAST; + bool use_dram0 = required_mem_prot & MEMPROT_DRAM0_SRAM || required_mem_prot & MEMPROT_DRAM0_RTCFAST; + bool use_peri1 = required_mem_prot & MEMPROT_PERI1_RTCSLOW; + bool use_peri2 = required_mem_prot & MEMPROT_PERI2_RTCSLOW_0 || required_mem_prot & MEMPROT_PERI2_RTCSLOW_1; + + //disable protection + if (use_iram0) { + esp_memprot_intr_ena(MEMPROT_IRAM0_SRAM, false); + } + if (use_dram0) { + esp_memprot_intr_ena(MEMPROT_DRAM0_SRAM, false); + } + if (use_peri1) { + esp_memprot_intr_ena(MEMPROT_PERI1_RTCSLOW, false); + } + if (use_peri2) { + esp_memprot_intr_ena(MEMPROT_PERI2_RTCSLOW_0, false); + } + + if ( use_panic_handler ) { + if (use_iram0) { + esp_memprot_intr_init(MEMPROT_IRAM0_SRAM); + } + if (use_dram0) { + esp_memprot_intr_init(MEMPROT_DRAM0_SRAM); + } + if (use_peri1) { + esp_memprot_intr_init(MEMPROT_PERI1_RTCSLOW); + } + if (use_peri2) { + esp_memprot_intr_init(MEMPROT_PERI2_RTCSLOW_0); + } + } + + //set permissions + if (required_mem_prot & MEMPROT_IRAM0_SRAM) { + esp_memprot_set_prot_iram(MEMPROT_IRAM0_SRAM, test_memprot_iram0_sram_get_min_split_addr(), true, true, true, true, true, false); + } + if (required_mem_prot & MEMPROT_IRAM0_RTCFAST) { + esp_memprot_set_prot_iram(MEMPROT_IRAM0_RTCFAST, test_memprot_iram0_rtcfast_get_min_split_addr(), false, true, true, true, true, false); + } + if (required_mem_prot & MEMPROT_DRAM0_SRAM) { + esp_memprot_set_prot_dram(MEMPROT_DRAM0_SRAM, test_memprot_dram0_sram_get_min_split_addr(), true, true, true, true); + } + if (required_mem_prot & MEMPROT_DRAM0_RTCFAST) { + esp_memprot_set_prot_dram(MEMPROT_DRAM0_RTCFAST, test_memprot_dram0_rtcfast_get_min_split_addr(), false, true, true, true); + } + if (required_mem_prot & MEMPROT_PERI1_RTCSLOW) { + esp_memprot_set_prot_peri1(MEMPROT_PERI1_RTCSLOW, test_memprot_peri1_rtcslow_get_min_split_addr(), true, true, true, true); + } + if (required_mem_prot & MEMPROT_PERI2_RTCSLOW_0) { + esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_0, test_memprot_peri2_rtcslow_0_get_min_split_addr(), true, true, false, true, true, false); + } + if (required_mem_prot & MEMPROT_PERI2_RTCSLOW_1) { + esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_1, test_memprot_peri2_rtcslow_1_get_min_split_addr(), true, true, false, true, true, false); + } + + //reenable protection (bus based) + if (use_iram0) { + esp_memprot_intr_ena(MEMPROT_IRAM0_SRAM, true); + } + if (use_dram0) { + esp_memprot_intr_ena(MEMPROT_DRAM0_SRAM, true); + } + if (use_peri1) { + esp_memprot_intr_ena(MEMPROT_PERI1_RTCSLOW, true); + } + if (use_peri2) { + esp_memprot_intr_ena(MEMPROT_PERI2_RTCSLOW_0, true); + } +} + + +/* ******************************************************************************************** + * auxiliary functions + */ +static void __attribute__((unused)) dump_fnc_buff(uint32_t *buff) +{ + esp_rom_printf( "0x%08X: 0x%08X-0x%08X\n", (uint32_t)buff, buff[0], buff[1] ); +} + +static void __attribute__((unused)) dump_bus_permissions(mem_type_prot_t mem_type) +{ + bool write_perm_low, write_perm_high, read_perm_low, read_perm_high, exec_perm_low, exec_perm_high; + esp_memprot_get_permissions(mem_type, &write_perm_low, &write_perm_high, &read_perm_low, &read_perm_high, &exec_perm_low, &exec_perm_high); + + esp_rom_printf("%s permissions: LW=%u LR=%u LX=%u HW=%u HR=%u HX=%u\n", esp_memprot_type_to_str(mem_type), + write_perm_low, read_perm_low, exec_perm_low, write_perm_high, read_perm_high, exec_perm_high); +} + +static void __attribute__((unused)) dump_status_register(mem_type_prot_t mem_type) +{ + uint32_t *faulting_address, op_type, op_subtype; + esp_memprot_get_fault_status(mem_type, &faulting_address, &op_type, &op_subtype); + esp_rom_printf( + " FAULT [split addr: 0x%08X, fault addr: 0x%08X, fault status: 0x%08X]\n", + (uint32_t)test_memprot_get_split_addr(mem_type), + (uint32_t)faulting_address, + esp_memprot_get_fault_reg(mem_type) + ); +} + + +/* ******************************************************************************************** + * testing functions + */ +static void check_test_result(mem_type_prot_t mem_type, bool expected_status) +{ + uint32_t fault = esp_memprot_get_fault_reg(mem_type); + + bool test_result = expected_status ? fault == 0 : fault != 0; + if ( test_result ) { + esp_rom_printf("OK\n"); + } else { + dump_status_register(mem_type); + } +} + +static void test_memprot_read(mem_type_prot_t mem_type) +{ + //get current READ & WRITE permission settings + bool write_perm_low, write_perm_high, read_perm_low, read_perm_high; + esp_memprot_get_perm_read(mem_type, &write_perm_low, &write_perm_high); + esp_memprot_get_perm_read(mem_type, &read_perm_low, &read_perm_high); + + //get current splitting address + volatile uint32_t *ptr = test_memprot_get_split_addr(mem_type); + + //temporarily allow WRITE for setting the test values + const uint32_t test_val = 100; + esp_memprot_set_write_perm(mem_type, true, true); + *(ptr - 4) = test_val; + *(ptr + 4) = test_val + 1; + esp_memprot_set_write_perm(mem_type, write_perm_low, write_perm_high); + + //perform READ in low region + esp_rom_printf("%s read low: ", esp_memprot_type_to_str(mem_type)); + esp_memprot_clear_intr(mem_type); + volatile uint32_t val = *(ptr - 4); + if ( val != 0 && val != test_val ) { + esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val ); + dump_status_register(mem_type); + } else { + check_test_result(mem_type, val == test_val); + } + + //perform read in high region + esp_rom_printf("%s read high: ", esp_memprot_type_to_str(mem_type)); + esp_memprot_clear_intr(mem_type); + val = *(ptr + 4); + if ( val != 0 && val != (test_val + 1) ) { + esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); + dump_status_register(mem_type); + } else { + check_test_result(mem_type, val == (test_val + 1)); + } +} + +static void test_memprot_write(mem_type_prot_t mem_type) +{ + //get current READ & WRITE permission settings + bool write_perm_low, write_perm_high, read_perm_low, read_perm_high; + esp_memprot_get_perm_read(mem_type, &write_perm_low, &write_perm_high); + esp_memprot_get_perm_read(mem_type, &read_perm_low, &read_perm_high); + + //temporarily allow READ operation + esp_memprot_set_read_perm(mem_type, true, true); + + //get current splitting address + volatile uint32_t *ptr = test_memprot_get_split_addr(mem_type); + + //perform WRITE in low region + const uint32_t test_val = 10; + esp_rom_printf("%s write low: ", esp_memprot_type_to_str(mem_type)); + esp_memprot_clear_intr(mem_type); + + volatile uint32_t val = 0; + *(ptr - 4) = test_val; + val = *(ptr - 4); + + if ( val != test_val && write_perm_low ) { + esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); + dump_status_register(mem_type); + } else { + check_test_result(mem_type, write_perm_low); + } + + //perform WRITE in high region + esp_rom_printf("%s write high: ", esp_memprot_type_to_str(mem_type)); + esp_memprot_clear_intr(mem_type); + val = 0; + *(ptr + 4) = test_val + 1; + val = *(ptr + 4); + + if ( val != (test_val + 1) && write_perm_high ) { + esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); + dump_status_register(mem_type); + } else { + check_test_result(mem_type, write_perm_high); + } +} + +static void test_memprot_exec(mem_type_prot_t mem_type) +{ + //store current write permissions + bool write_perm_low, write_perm_high; + esp_memprot_get_perm_write(mem_type, &write_perm_low, &write_perm_high); + + //get current EXEC permission settings + bool exec_perm_low, exec_perm_high; + esp_memprot_get_perm_exec(mem_type, &exec_perm_low, &exec_perm_high); + + volatile uint32_t *fnc_ptr_low = (uint32_t *)(test_memprot_get_split_addr(mem_type) - 4); + volatile uint32_t *fnc_ptr_high = (uint32_t *)(test_memprot_get_split_addr(mem_type) + 4); + + //enable WRITE permission for both segments + esp_memprot_set_write_perm(mem_type, true, true); + + //inject the code to both low & high segments + memcpy( (void *)fnc_ptr_low, fnc_call0_buff, sizeof(fnc_call0_buff) ); + memcpy( (void *)fnc_ptr_high, fnc_call0_buff, sizeof(fnc_call0_buff) ); + + //restore original WRITE perms + esp_memprot_set_write_perm(mem_type, write_perm_low, write_perm_high); + + uint32_t res = 0; + + //LOW REGION: clear the intr flag & try to execute the code injected + esp_memprot_clear_intr(mem_type); + esp_rom_printf("%s exec low: ", esp_memprot_type_to_str(mem_type)); + + g_override_illegal_instruction = true; + CODE_EXEC(fnc_ptr_low, 5, res); + g_override_illegal_instruction = false; + + //check results + bool fnc_call_ok = res == 10; + if ( fnc_call_ok ) { + check_test_result(mem_type, exec_perm_low); + } else { + if ( !exec_perm_low ) { + check_test_result(mem_type, true); + } else { + esp_rom_printf(" FAULT [injected code not executed]\n"); + } + } + + //HIGH REGION: clear the intr flag & try to execute the code injected + esp_memprot_clear_intr(mem_type); + esp_rom_printf("%s exec high: ", esp_memprot_type_to_str(mem_type)); + + g_override_illegal_instruction = true; + CODE_EXEC(fnc_ptr_high, 6, res); + g_override_illegal_instruction = false; + + fnc_call_ok = res == 12; + if ( fnc_call_ok ) { + check_test_result(mem_type, exec_perm_high); + } else { + if ( !exec_perm_high ) { + check_test_result(mem_type, true); + } else { + esp_rom_printf(" FAULT [injected code not executed]\n"); + } + } +} + + +/* ******************************************************************************************** + * main test runner + */ +void app_main(void) +{ + test_memprot_set_prot(NULL, false); + + test_memprot_read(MEMPROT_IRAM0_SRAM); + test_memprot_write(MEMPROT_IRAM0_SRAM); + test_memprot_exec(MEMPROT_IRAM0_SRAM); + + test_memprot_read(MEMPROT_IRAM0_RTCFAST); + test_memprot_write(MEMPROT_IRAM0_RTCFAST); + test_memprot_exec(MEMPROT_IRAM0_RTCFAST); + + test_memprot_read(MEMPROT_DRAM0_SRAM); + test_memprot_write(MEMPROT_DRAM0_SRAM); + + test_memprot_read(MEMPROT_DRAM0_RTCFAST); + test_memprot_write(MEMPROT_DRAM0_RTCFAST); + + test_memprot_read(MEMPROT_PERI1_RTCSLOW); + test_memprot_write(MEMPROT_PERI1_RTCSLOW); + + test_memprot_read(MEMPROT_PERI2_RTCSLOW_0); + test_memprot_write(MEMPROT_PERI2_RTCSLOW_0); + test_memprot_exec(MEMPROT_PERI2_RTCSLOW_0); + + test_memprot_read(MEMPROT_PERI2_RTCSLOW_1); + test_memprot_write(MEMPROT_PERI2_RTCSLOW_1); + test_memprot_exec(MEMPROT_PERI2_RTCSLOW_1); +} diff --git a/tools/test_apps/system/memprot/main/test_panic.c b/tools/test_apps/system/memprot/main/test_panic.c new file mode 100644 index 0000000000..30fdd5c36d --- /dev/null +++ b/tools/test_apps/system/memprot/main/test_panic.c @@ -0,0 +1,44 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "freertos/xtensa_context.h" +#include "esp_private/panic_internal.h" + +extern void esp_panic_handler(panic_info_t *info); +extern volatile bool g_override_illegal_instruction; + +void __real_esp_panic_handler(panic_info_t *info); + +/* Memprot test specific IllegalInstruction exception handler: + * when testing the protection against a code execution, sample code + * is being injected into various memory regions which produces + * EXCCAUSE_ILLEGAL on execution attempt. Such a result is expected + * but it causes system reboot in the standard panic handler. + * The following variant of panic handling simply returns back to the + * next instruction and continues normal execution. + * + * NOTE: if EXCCAUSE_ILLEGAL comes from a different source than the testing code + * the behavior is undefined + * */ +void __wrap_esp_panic_handler(panic_info_t *info) +{ + XtExcFrame *frm = (XtExcFrame *)info->frame; + if ( frm->exccause == EXCCAUSE_ILLEGAL && g_override_illegal_instruction == true ) { + frm->pc = frm->a0; + return; + } else { + __real_esp_panic_handler(info); + } +} + diff --git a/tools/test_apps/system/memprot/sdkconfig.ci b/tools/test_apps/system/memprot/sdkconfig.ci new file mode 100644 index 0000000000..b77e5a7358 --- /dev/null +++ b/tools/test_apps/system/memprot/sdkconfig.ci @@ -0,0 +1,5 @@ +# Esp32S2 only +CONFIG_IDF_TARGET="esp32s2" + +# Disable automatic memory protection +CONFIG_ESP32S2_MEMPROT_FEATURE=n