diff --git a/components/driver/test/test_spi_master.c b/components/driver/test/test_spi_master.c index ffca8d2522..656bd0e9fb 100644 --- a/components/driver/test/test_spi_master.c +++ b/components/driver/test/test_spi_master.c @@ -565,7 +565,7 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]") ESP_LOGI(TAG, "dram: %p", data_dram); ESP_LOGI(TAG, "drom: %p, malloc: %p", data_drom, data_malloc); -#ifndef CONFIG_ESP32C3_MEMPROT_FEATURE +#ifndef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE uint32_t* data_iram = (uint32_t*)heap_caps_malloc(324, MALLOC_CAP_EXEC); TEST_ASSERT(data_iram != NULL); TEST_ASSERT(esp_ptr_executable(data_iram) || esp_ptr_in_iram(data_iram) || esp_ptr_in_diram_iram(data_iram)); @@ -574,7 +574,7 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]") srand(52); for (int i = 0; i < 320/4; i++) { -#ifndef CONFIG_ESP32C3_MEMPROT_FEATURE +#ifndef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE data_iram[i] = rand(); #endif data_dram[i] = rand(); @@ -601,7 +601,7 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]") int x; memset(trans, 0, sizeof(trans)); -#ifndef CONFIG_ESP32C3_MEMPROT_FEATURE +#ifndef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE trans[0].length = 320*8, trans[0].tx_buffer = data_iram; trans[0].rx_buffer = data_malloc+1; @@ -627,7 +627,7 @@ TEST_CASE("SPI Master DMA test, TX and RX in different regions", "[spi]") *ptr = 0xbc124960; //Queue all transactions. -#ifndef CONFIG_ESP32C3_MEMPROT_FEATURE +#ifndef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE for (x=0; x +#include #include "esp_attr.h" #ifdef __cplusplus @@ -27,329 +27,67 @@ extern "C" { #endif typedef enum { - MEMPROT_IRAM0 = 0x00000000, - MEMPROT_DRAM0 = 0x00000001, - MEMPROT_UNKNOWN + MEMPROT_NONE = 0x00000000, + MEMPROT_IRAM0_SRAM = 0x00000001, + MEMPROT_DRAM0_SRAM = 0x00000002, + MEMPROT_ALL = 0xFFFFFFFF } mem_type_prot_t; +typedef enum { + MEMPROT_IRAM0_DRAM0_SPLITLINE, + MEMPROT_IRAM0_LINE_0_SPLITLINE, + MEMPROT_IRAM0_LINE_1_SPLITLINE, + MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE, + MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE +} split_line_t; -/** - * @brief Returns splitting address for required memory region - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return Splitting address for the memory region required. - * The address is given by region-specific global symbol exported from linker script, - * it is not read out from related configuration register. - */ -uint32_t *IRAM_ATTR esp_memprot_get_split_addr(mem_type_prot_t mem_type); +typedef enum { + MEMPROT_IRAM0_PMS_AREA_0, + MEMPROT_IRAM0_PMS_AREA_1, + MEMPROT_IRAM0_PMS_AREA_2, + MEMPROT_IRAM0_PMS_AREA_3, + MEMPROT_DRAM0_PMS_AREA_0, + MEMPROT_DRAM0_PMS_AREA_1, + MEMPROT_DRAM0_PMS_AREA_2, + MEMPROT_DRAM0_PMS_AREA_3 +} pms_area_t; -/** - * @brief Initializes illegal memory access control (MMU) for required memory section. - * - * All memory access interrupts share ETS_MEMACCESS_ERR_INUM input channel, it is caller's - * responsibility to properly detect actual intr. source as well as possible prioritization in case - * of multiple source reported during one intr.handling routine run - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - */ -void esp_memprot_intr_init(mem_type_prot_t mem_type); -/** - * @brief Enable/disable the memory protection interrupt - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * @param enable enable/disable - */ -void esp_memprot_intr_ena(mem_type_prot_t mem_type, bool enable); +const char *mem_type_to_str(mem_type_prot_t mem_type); +const char *split_line_to_str(split_line_t line_type); +const char *pms_to_str(pms_area_t area_type); -/** - * @brief Detects whether any of the memory protection interrupts is active - * - * @return true/false - */ -bool esp_memprot_is_assoc_intr_any(void); +void *esp_memprot_get_main_split_addr(void); +void esp_memprot_set_split_line_lock(bool lock); +bool esp_memprot_get_split_line_lock(void); +void esp_memprot_set_split_line(split_line_t line_type, const void *line_addr); -/** - * @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); +void esp_memprot_set_pms_lock(mem_type_prot_t mem_type, bool lock); +bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type); +void esp_memprot_iram_set_pms_area(pms_area_t area_type, bool r, bool w, bool x); +void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w); -/** - * @brief Sets a request for clearing interrupt-on flag for specified memory region (register write) - * - * @note When called without actual interrupt-on flag set, subsequent occurrence of related interrupt is ignored. - * Should be used only after the real interrupt appears, typically as the last step in interrupt handler's routine. - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - */ -void esp_memprot_clear_intr(mem_type_prot_t mem_type); +void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type, bool lock); +bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type); +void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable); +bool esp_memprot_get_monitor_en(mem_type_prot_t mem_type); -/** - * @brief Detects which memory protection interrupt is active, check order: IRAM0, DRAM0 - * - * @return Memory protection area type (see mem_type_prot_t enum) - */ -mem_type_prot_t IRAM_ATTR esp_memprot_get_intr_memtype(void); +int IRAM_ATTR esp_memprot_intr_get_cpuid(void); +void IRAM_ATTR esp_memprot_monitor_clear_intr(mem_type_prot_t mem_type); +mem_type_prot_t IRAM_ATTR esp_memprot_get_active_intr_memtype(void); +bool IRAM_ATTR esp_memprot_is_locked_any(void); +bool IRAM_ATTR esp_memprot_is_intr_ena_any(void); -/** - * @brief Gets interrupt status register contents for specified memory region - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return Contents of status register - */ -uint32_t esp_memprot_get_fault_reg(mem_type_prot_t mem_type); +uint32_t IRAM_ATTR esp_memprot_get_violate_intr_on(mem_type_prot_t mem_type); +uint32_t IRAM_ATTR esp_memprot_get_violate_addr(mem_type_prot_t mem_type); +uint32_t IRAM_ATTR esp_memprot_get_violate_world(mem_type_prot_t mem_type); +uint32_t IRAM_ATTR esp_memprot_get_violate_wr(mem_type_prot_t mem_type); +uint32_t IRAM_ATTR esp_memprot_get_violate_loadstore(mem_type_prot_t mem_type); +uint32_t IRAM_ATTR esp_memprot_get_violate_byte_en(mem_type_prot_t mem_type); -/** - * @brief Get details of given interrupt status - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * @param faulting_address Faulting address causing the interrupt [out] - * @param op_type Operation being processed at the faulting address [out] - * IRAM0: 0 - read, 1 - write - * DRAM0: 0 - read, 1 - write - * @param op_subtype Additional info for op_type [out] - * IRAM0: 0 - instruction segment access, 1 - data segment access - * DRAM0: 0 - non-atomic operation, 1 - atomic operation - */ -void IRAM_ATTR esp_memprot_get_fault_status(mem_type_prot_t mem_type, uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype); - -/** - * @brief Gets string representation of required memory region identifier - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return mem_type as string - */ -const char *IRAM_ATTR esp_memprot_type_to_str(mem_type_prot_t mem_type); - -/** - * @brief Detects whether any of the interrupt locks is active (requires digital system reset to unlock) - * - * @return true/false - */ -bool esp_memprot_is_locked_any(void); - -/** - * @brief Sets lock for specified memory region. - * - * Locks can be unlocked only by digital system reset - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - */ -void esp_memprot_set_lock(mem_type_prot_t mem_type); - -/** - * @brief Gets lock status for required memory region - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return true/false (locked/unlocked) - */ -bool esp_memprot_get_lock(mem_type_prot_t mem_type); - -/** - * @brief Gets interrupt permission control 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); - -/** - * @brief Gets interrupt permission settings for unified management block - * - * Gets interrupt permission settings register contents for required memory region, returns settings for unified management blocks - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return Permission settings register contents - */ -uint32_t esp_memprot_get_perm_uni_reg(mem_type_prot_t mem_type); - -/** - * @brief Gets interrupt permission settings for split management block - * - * Gets interrupt permission settings register contents for required memory region, returns settings for split management blocks - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return Permission settings register contents - */ -uint32_t esp_memprot_get_perm_split_reg(mem_type_prot_t mem_type); - -/** - * @brief Detects whether any of the memory protection interrupts is enabled - * - * @return true/false - */ -bool esp_memprot_is_intr_ena_any(void); - -/** - * @brief Gets interrupt-enabled flag for given memory region - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return Interrupt-enabled value - */ -uint32_t esp_memprot_get_intr_ena_bit(mem_type_prot_t mem_type); - -/** - * @brief Gets interrupt-active flag for given memory region - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return Interrupt-active value - */ -uint32_t esp_memprot_get_intr_on_bit(mem_type_prot_t mem_type); - -/** - * @brief Gets interrupt-clear request flag for given memory region - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * - * @return Interrupt-clear request value - */ -uint32_t esp_memprot_get_intr_clr_bit(mem_type_prot_t mem_type); - -/** - * @brief Gets read permission value for specified block and memory region - * - * Returns read permission bit value for required unified-management block (0-3) in given memory region. - * Applicable to all memory types. - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * @param block Memory block identifier (0-3) - * - * @return Read permission value for required block - */ -uint32_t esp_memprot_get_uni_block_read_bit(mem_type_prot_t mem_type, uint32_t block); - -/** - * @brief Gets write permission value for specified block and memory region - * - * Returns write permission bit value for required unified-management block (0-3) in given memory region. - * Applicable to all memory types. - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * @param block Memory block identifier (0-3) - * - * @return Write permission value for required block - */ -uint32_t esp_memprot_get_uni_block_write_bit(mem_type_prot_t mem_type, uint32_t block); - -/** - * @brief Gets execute permission value for specified block and memory region - * - * Returns execute permission bit value for required unified-management block (0-3) in given memory region. - * Applicable only to IRAM memory types - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * @param block Memory block identifier (0-3) - * - * @return Execute permission value for required block - */ -uint32_t esp_memprot_get_uni_block_exec_bit(mem_type_prot_t mem_type, uint32_t block); - -/** - * @brief Sets permissions for specified block in DRAM region - * - * Sets Read and Write permission for specified unified-management block (0-3) in given memory region. - * Applicable only to DRAM memory types - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * @param block Memory block identifier (0-3) - * @param write_perm Write permission flag - * @param read_perm Read permission flag - */ -void esp_memprot_set_uni_block_perm_dram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm); - -/** - * @brief Sets permissions for high and low memory segment in DRAM region - * - * Sets Read and Write permission for both low and high memory segments given by splitting address. - * The splitting address must be equal to or higher then beginning of block 5 - * Applicable only to DRAM 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_dram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr); - -/** - * @brief Sets permissions for specified block in IRAM region - * - * Sets Read, Write and Execute permission for specified unified-management block (0-3) in given memory region. - * Applicable only to IRAM memory types - * - * @param mem_type Memory protection area type (see mem_type_prot_t enum) - * @param block Memory block identifier (0-3) - * @param write_perm Write permission flag - * @param exec_perm Execute permission flag - */ -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); - -/** - * @brief Sets permissions for high and low memory segment in IRAM region - * - * Sets Read, Write and Execute permission for both low and high memory segments given by splitting address. - * The splitting address must be equal to or higher then beginning of block 5 - * Applicable only to IRAM 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_iram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx); - -/** - * @brief Activates memory protection for all supported memory region types - * - * @note The feature is disabled when JTAG interface is connected - * - * @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) - */ -void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature); - -/** - * @brief Get permission settings bits for IRAM split mgmt based on current split address - * - * @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_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 - * - * @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_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr); +void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type); +void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask); +void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void *split_addr, uint32_t *mem_type_mask); #ifdef __cplusplus } diff --git a/components/esp32c3/ld/esp32c3.project.ld.in b/components/esp32c3/ld/esp32c3.project.ld.in index cf536223b5..aa74835ef8 100644 --- a/components/esp32c3/ld/esp32c3.project.ld.in +++ b/components/esp32c3/ld/esp32c3.project.ld.in @@ -359,7 +359,8 @@ SECTIONS /* Marks the end of IRAM code segment */ .iram0.text_end (NOLOAD) : { - . = ALIGN (16); + /* C3 memprot requires 512 B alignment for split lines */ + . = ALIGN (0x200); _iram_text_end = ABSOLUTE(.); } > iram0_0_seg diff --git a/components/esp32c3/memprot.c b/components/esp32c3/memprot.c new file mode 100644 index 0000000000..f5547af908 --- /dev/null +++ b/components/esp32c3/memprot.c @@ -0,0 +1,520 @@ +// 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. + +/* INTERNAL API + * implementation of PMS memory protection features + */ + +#include +#include "sdkconfig.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 "esp32c3/memprot.h" +#include "hal/memprot_ll.h" +#include "riscv/interrupt.h" +#include "esp_log.h" + +extern int _iram_text_end; + +const char *mem_type_to_str(mem_type_prot_t mem_type) +{ + switch (mem_type) { + case MEMPROT_NONE: + return "MEMPROT_NONE"; + case MEMPROT_IRAM0_SRAM: + return "MEMPROT_IRAM0_SRAM"; + case MEMPROT_DRAM0_SRAM: + return "MEMPROT_DRAM0_SRAM"; + case MEMPROT_ALL: + return "MEMPROT_ALL"; + default: + return "UNKNOWN"; + } +} + +const char *split_line_to_str(split_line_t line_type) +{ + switch (line_type) { + case MEMPROT_IRAM0_DRAM0_SPLITLINE: + return "MEMPROT_IRAM0_DRAM0_SPLITLINE"; + case MEMPROT_IRAM0_LINE_0_SPLITLINE: + return "MEMPROT_IRAM0_LINE_0_SPLITLINE"; + case MEMPROT_IRAM0_LINE_1_SPLITLINE: + return "MEMPROT_IRAM0_LINE_1_SPLITLINE"; + case MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE: + return "MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE"; + case MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE: + return "MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE"; + default: + return "UNKNOWN"; + } +} + +const char *pms_to_str(pms_area_t area_type) +{ + switch (area_type) { + case MEMPROT_IRAM0_PMS_AREA_0: + return "MEMPROT_IRAM0_PMS_AREA_0"; + case MEMPROT_IRAM0_PMS_AREA_1: + return "MEMPROT_IRAM0_PMS_AREA_1"; + case MEMPROT_IRAM0_PMS_AREA_2: + return "MEMPROT_IRAM0_PMS_AREA_2"; + case MEMPROT_IRAM0_PMS_AREA_3: + return "MEMPROT_IRAM0_PMS_AREA_3"; + case MEMPROT_DRAM0_PMS_AREA_0: + return "MEMPROT_DRAM0_PMS_AREA_0"; + case MEMPROT_DRAM0_PMS_AREA_1: + return "MEMPROT_DRAM0_PMS_AREA_1"; + case MEMPROT_DRAM0_PMS_AREA_2: + return "MEMPROT_DRAM0_PMS_AREA_2"; + case MEMPROT_DRAM0_PMS_AREA_3: + return "MEMPROT_DRAM0_PMS_AREA_3"; + default: + return "UNKNOWN"; + } +} + + +/* split lines */ + +void *esp_memprot_get_main_split_addr() +{ + return &_iram_text_end; +} + +void esp_memprot_set_split_line_lock(bool lock) +{ + memprot_ll_set_iram0_dram0_split_line_lock(lock); +} + +bool esp_memprot_get_split_line_lock() +{ + return memprot_ll_get_iram0_dram0_split_line_lock(); +} + +void esp_memprot_set_split_line(split_line_t line_type, const void *line_addr) +{ + uint32_t addr = (uint32_t)line_addr; + ESP_LOGD(TAG, "Setting split line %s, addr: 0x%08X", split_line_to_str(line_type), addr); + + //split-line must be divisible by 512 + assert( addr % 0x200 == 0 ); + + switch ( line_type ) { + case MEMPROT_IRAM0_DRAM0_SPLITLINE: + memprot_ll_set_iram0_split_line_main_I_D(line_addr); + break; + case MEMPROT_IRAM0_LINE_0_SPLITLINE: + memprot_ll_set_iram0_split_line_I_0(line_addr); + break; + case MEMPROT_IRAM0_LINE_1_SPLITLINE: + memprot_ll_set_iram0_split_line_I_1(line_addr); + break; + case MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE: + memprot_ll_set_dram0_split_line_D_0(line_addr); + break; + case MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE: + memprot_ll_set_dram0_split_line_D_1(line_addr); + break; + default: + ESP_LOGE(TAG, "Invalid split line type, aborting: 0x%08X", addr); + abort(); + } +} + +// TODO - get split lines + + +/* PMS */ + +void esp_memprot_set_pms_lock(mem_type_prot_t mem_type, bool lock) +{ + ESP_LOGD(TAG, "esp_memprot_set_pms_lock(%s, %s)", mem_type_to_str(mem_type), lock ? "true" : "false"); + + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + memprot_ll_iram0_set_pms_lock(lock); + break; + case MEMPROT_DRAM0_SRAM: + memprot_ll_dram0_set_pms_lock(lock); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type) +{ + ESP_LOGD(TAG, "esp_memprot_get_pms_lock(%s)", mem_type_to_str(mem_type)); + + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return memprot_ll_iram0_get_pms_lock(); + case MEMPROT_DRAM0_SRAM: + return memprot_ll_dram0_get_pms_lock(); + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +void esp_memprot_iram_set_pms_area(pms_area_t area_type, bool r, bool w, bool x) +{ + ESP_LOGD(TAG, "esp_memprot_iram_set_pms_area(area:%s r:%u w:%u, x:%u)", pms_to_str(area_type), r, w, x); + + switch ( area_type ) { + case MEMPROT_IRAM0_PMS_AREA_0: + memprot_ll_iram0_set_pms_area_0(r, w, x); + break; + case MEMPROT_IRAM0_PMS_AREA_1: + memprot_ll_iram0_set_pms_area_1(r, w, x); + break; + case MEMPROT_IRAM0_PMS_AREA_2: + memprot_ll_iram0_set_pms_area_2(r, w, x); + break; + case MEMPROT_IRAM0_PMS_AREA_3: + memprot_ll_iram0_set_pms_area_3(r, w, x); + break; + default: + ESP_LOGE(TAG, "Invalid area_type %d", pms_to_str(area_type)); + abort(); + } +} + +void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w) +{ + ESP_LOGD(TAG, "esp_memprot_dram_set_pms_area(area:%s r:%u w:%u)", pms_to_str(area_type), r, w); + + switch ( area_type ) { + case MEMPROT_DRAM0_PMS_AREA_0: + memprot_ll_dram0_set_pms_area_0(r, w); + break; + case MEMPROT_DRAM0_PMS_AREA_1: + memprot_ll_dram0_set_pms_area_1(r, w); + break; + case MEMPROT_DRAM0_PMS_AREA_2: + memprot_ll_dram0_set_pms_area_2(r, w); + break; + case MEMPROT_DRAM0_PMS_AREA_3: + memprot_ll_dram0_set_pms_area_3(r, w); + break; + default: + ESP_LOGE(TAG, "Invalid area_type %d", pms_to_str(area_type)); + abort(); + } +} + +/* TODO - get single areas */ + + +/* monitor */ + +void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type, bool lock) +{ + ESP_LOGD(TAG, "esp_memprot_set_monitor_lock(%s, %s)", mem_type_to_str(mem_type), lock ? "true" : "false"); + + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + memprot_ll_iram0_set_monitor_lock(lock); + break; + case MEMPROT_DRAM0_SRAM: + memprot_ll_dram0_set_monitor_lock(lock); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type) +{ + ESP_LOGD(TAG, "esp_memprot_get_monitor_lock(%s)", mem_type_to_str(mem_type)); + + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return memprot_ll_iram0_get_monitor_lock(); + case MEMPROT_DRAM0_SRAM: + return memprot_ll_dram0_get_monitor_lock(); + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable) +{ + ESP_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", mem_type_to_str(mem_type)); + + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + memprot_ll_iram0_set_monitor_en(enable); + break; + case MEMPROT_DRAM0_SRAM: + memprot_ll_dram0_set_monitor_en(enable); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +bool esp_memprot_get_monitor_en(mem_type_prot_t mem_type) +{ + ESP_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", mem_type_to_str(mem_type)); + + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return memprot_ll_iram0_get_monitor_en(); + case MEMPROT_DRAM0_SRAM: + return memprot_ll_dram0_get_monitor_en(); + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +bool esp_memprot_is_intr_ena_any() +{ + return esp_memprot_get_monitor_en(MEMPROT_IRAM0_SRAM) || esp_memprot_get_monitor_en(MEMPROT_DRAM0_SRAM); +} + +void esp_memprot_monitor_clear_intr(mem_type_prot_t mem_type) +{ + ESP_LOGD(TAG, "esp_memprot_monitor_clear_intr(%s)", mem_type_to_str(mem_type)); + + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + memprot_ll_iram0_clear_monitor_intr(); + break; + case MEMPROT_DRAM0_SRAM: + memprot_ll_dram0_clear_monitor_intr(); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +mem_type_prot_t esp_memprot_get_active_intr_memtype() +{ + if ( memprot_ll_iram0_get_monitor_status_intr() > 0 ) { + return MEMPROT_IRAM0_SRAM; + } else if ( memprot_ll_dram0_get_monitor_status_intr() ) { + return MEMPROT_DRAM0_SRAM; + } + + return MEMPROT_NONE; +} + +bool esp_memprot_is_locked_any() +{ + return + esp_memprot_get_split_line_lock() || + esp_memprot_get_pms_lock(MEMPROT_IRAM0_SRAM) || + esp_memprot_get_pms_lock(MEMPROT_DRAM0_SRAM) || + esp_memprot_get_monitor_lock(MEMPROT_IRAM0_SRAM) || + esp_memprot_get_monitor_lock(MEMPROT_DRAM0_SRAM); +} + +uint32_t esp_memprot_get_violate_intr_on(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return memprot_ll_iram0_get_monitor_status_intr(); + case MEMPROT_DRAM0_SRAM: + return memprot_ll_dram0_get_monitor_status_intr(); + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +uint32_t esp_memprot_get_violate_addr(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return memprot_ll_iram0_get_monitor_status_fault_addr(); + case MEMPROT_DRAM0_SRAM: + return memprot_ll_dram0_get_monitor_status_fault_addr(); + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +uint32_t esp_memprot_get_violate_world(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return memprot_ll_iram0_get_monitor_status_fault_world(); + case MEMPROT_DRAM0_SRAM: + return memprot_ll_dram0_get_monitor_status_fault_world(); + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +uint32_t esp_memprot_get_violate_wr(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return memprot_ll_iram0_get_monitor_status_fault_wr(); + case MEMPROT_DRAM0_SRAM: + return memprot_ll_dram0_get_monitor_status_fault_wr(); + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +uint32_t esp_memprot_get_violate_loadstore(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return memprot_ll_iram0_get_monitor_status_fault_loadstore(); + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +uint32_t esp_memprot_get_violate_byte_en(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_DRAM0_SRAM: + return memprot_ll_dram0_get_monitor_status_fault_byte_en(); + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } +} + +int esp_memprot_intr_get_cpuid() +{ + return PRO_CPU_NUM; +} + +void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type) +{ + ESP_LOGD(TAG, "esp_memprot_set_intr_matrix(%s)", mem_type_to_str(mem_type)); + + ESP_INTR_DISABLE(ETS_MEMPROT_ERR_INUM); + + switch (mem_type) { + case MEMPROT_IRAM0_SRAM: + intr_matrix_set(esp_memprot_intr_get_cpuid(), memprot_ll_iram0_get_intr_source_num(), ETS_MEMPROT_ERR_INUM); + break; + case MEMPROT_DRAM0_SRAM: + intr_matrix_set(esp_memprot_intr_get_cpuid(), memprot_ll_dram0_get_intr_source_num(), ETS_MEMPROT_ERR_INUM); + break; + default: + ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + abort(); + } + + /* Set the type and priority to cache error interrupts. */ + esprv_intc_int_set_type(BIT(ETS_MEMPROT_ERR_INUM), INTR_TYPE_LEVEL); + esprv_intc_int_set_priority(ETS_MEMPROT_ERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); + + ESP_INTR_ENABLE(ETS_MEMPROT_ERR_INUM); +} + +void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask) +{ + esp_memprot_set_prot_int(invoke_panic_handler, lock_feature, NULL, mem_type_mask); +} + +void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void *split_addr, uint32_t *mem_type_mask) +{ + ESP_LOGD(TAG, "esp_memprot_set_prot(panic_handler: %u, lock: %u, split.addr: 0x%08X, mem.types: 0x%08X", invoke_panic_handler, lock_feature, (uint32_t)split_addr, (uint32_t)mem_type_mask); + + 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; + bool use_dram0 = required_mem_prot & MEMPROT_DRAM0_SRAM; + + if (required_mem_prot == MEMPROT_NONE) { + return; + } + + //disable protection + if (use_iram0) { + esp_memprot_set_monitor_en(MEMPROT_IRAM0_SRAM, false); + } + if (use_dram0) { + esp_memprot_set_monitor_en(MEMPROT_DRAM0_SRAM, false); + } + + //panic handling + if (invoke_panic_handler) { + if (use_iram0) { + esp_memprot_set_intr_matrix(MEMPROT_IRAM0_SRAM); + } + if (use_dram0) { + esp_memprot_set_intr_matrix(MEMPROT_DRAM0_SRAM); + } + } + + //set split lines (must-have for all mem_types) + const void *line_addr = split_addr == NULL ? esp_memprot_get_main_split_addr() : split_addr; + esp_memprot_set_split_line(MEMPROT_IRAM0_LINE_1_SPLITLINE, line_addr); + esp_memprot_set_split_line(MEMPROT_IRAM0_LINE_0_SPLITLINE, line_addr); + esp_memprot_set_split_line(MEMPROT_IRAM0_DRAM0_SPLITLINE, line_addr); + esp_memprot_set_split_line(MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE, (void *)(MAP_IRAM_TO_DRAM((uint32_t)line_addr))); + esp_memprot_set_split_line(MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE, (void *)(MAP_IRAM_TO_DRAM((uint32_t)line_addr))); + + //set permissions + if (required_mem_prot & MEMPROT_IRAM0_SRAM) { + esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_0, true, false, true); + esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_1, true, false, true); + esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_2, true, false, true); + esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_3, true, true, false); + } + if (required_mem_prot & MEMPROT_DRAM0_SRAM) { + esp_memprot_dram_set_pms_area( MEMPROT_DRAM0_PMS_AREA_0, true, false ); + esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_1, true, true); + esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_2, true, true); + esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_3, true, true); + } + + //reenable protection + if (use_iram0) { + esp_memprot_monitor_clear_intr(MEMPROT_IRAM0_SRAM); + esp_memprot_set_monitor_en(MEMPROT_IRAM0_SRAM, true); + } + if (use_dram0) { + esp_memprot_monitor_clear_intr(MEMPROT_DRAM0_SRAM); + esp_memprot_set_monitor_en(MEMPROT_DRAM0_SRAM, true); + } + + //lock if required + if (lock_feature) { + esp_memprot_set_split_line_lock(true); + if (use_iram0) { + esp_memprot_set_pms_lock(MEMPROT_IRAM0_SRAM, true); + esp_memprot_set_monitor_lock(MEMPROT_IRAM0_SRAM, true); + } + if (use_dram0) { + esp_memprot_set_pms_lock(MEMPROT_DRAM0_SRAM, true); + esp_memprot_set_monitor_lock(MEMPROT_DRAM0_SRAM, true); + } + } +} diff --git a/components/esp32s2/Kconfig b/components/esp32s2/Kconfig index 1928ac5498..9ff302f698 100644 --- a/components/esp32s2/Kconfig +++ b/components/esp32s2/Kconfig @@ -29,29 +29,6 @@ menu "ESP32S2-specific" default 160 if ESP32S2_DEFAULT_CPU_FREQ_160 default 240 if ESP32S2_DEFAULT_CPU_FREQ_240 - menu "Memory protection" - - config ESP32S2_MEMPROT_FEATURE - bool "Enable memory protection" - default "y" - help - If enabled, permission control module watches all memory access and fires panic handler - if permission violation is detected. This feature automatically splits - memory into data and instruction segments and sets Read/Execute permissions - for instruction part (below splitting address) and Read/Write permissions - for data part (above splitting address). The memory protection is effective - on all access through IRAM0 and DRAM0 buses. - - config ESP32S2_MEMPROT_FEATURE_LOCK - depends on ESP32S2_MEMPROT_FEATURE - bool "Lock memory protection settings" - default "y" - help - Once locked, memory protection settings cannot be changed anymore. - The lock is reset only on the chip startup. - - endmenu # Memory protection - menu "Cache config" choice ESP32S2_INSTRUCTION_CACHE_SIZE diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index c99f5ef60c..16171815e8 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -98,4 +98,28 @@ menu "ESP System Settings" If enabled, the CPU will be powered down in light sleep. Enabling this option will consume 1.68 KB of internal RAM and will reduce sleep current consumption by about 100 uA. + menu "Memory protection" + + config ESP_SYSTEM_MEMPROT_FEATURE + bool "Enable memory protection" + depends on IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S2 + default "y" + help + If enabled, the permission control module watches all the memory access and fires the panic handler + if a permission violation is detected. This feature automatically splits + the SRAM memory into data and instruction segments and sets Read/Execute permissions + for the instruction part (below given splitting address) and Read/Write permissions + for the data part (above the splitting address). The memory protection is effective + on all access through the IRAM0 and DRAM0 buses. + + config ESP_SYSTEM_MEMPROT_FEATURE_LOCK + depends on ESP_SYSTEM_MEMPROT_FEATURE + bool "Lock memory protection settings" + default "y" + help + Once locked, memory protection settings cannot be changed anymore. + The lock is reset only on the chip startup. + + endmenu # Memory protection + endmenu # ESP System Settings diff --git a/components/esp_system/port/arch/riscv/panic_arch.c b/components/esp_system/port/arch/riscv/panic_arch.c index bae6dc202a..31814ba23c 100644 --- a/components/esp_system/port/arch/riscv/panic_arch.c +++ b/components/esp_system/port/arch/riscv/panic_arch.c @@ -22,6 +22,9 @@ #if CONFIG_IDF_TARGET_ESP32C3 #include "esp32c3/cache_err_int.h" #endif +#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE +#include "esp32c3/memprot.h" +#endif #define DIM(array) (sizeof(array)/sizeof(*array)) @@ -33,7 +36,7 @@ */ typedef struct { const uint32_t bit; - const char* msg; + const char *msg; } register_bit_t; /** @@ -45,8 +48,8 @@ typedef struct { * be set in the register will have its associated message printed. */ static inline bool test_and_print_register_bits(const uint32_t status, - const register_bit_t* reg_bits, - const uint32_t size) + const register_bit_t *reg_bits, + const uint32_t size) { /* Browse the flag/bit array and test each one with the given status * register. */ @@ -69,7 +72,7 @@ static inline bool test_and_print_register_bits(const uint32_t status, * Function called when a cache error occurs. It prints details such as the * explanation of why the panic occured. */ -static inline void print_cache_err_details(const void* frame) +static inline void print_cache_err_details(const void *frame) { /* Define the array that contains the status (bits) to test on the register * EXTMEM_CORE0_ACS_CACHE_INT_ST_REG. each bit is accompanied by a small @@ -145,6 +148,47 @@ static inline void print_cache_err_details(const void* frame) } } + +/** + * Function called when a memory protection error occurs (PMS). It prints details such as the + * explanation of why the panic occured. + */ +#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE +static inline void print_memprot_err_details(const void *frame) +{ + //common memprot fault info + mem_type_prot_t mem_type = esp_memprot_get_active_intr_memtype(); + panic_print_str( " memory type: "); + panic_print_str( mem_type_to_str(mem_type) ); + panic_print_str( "\r\n faulting address: "); + panic_print_hex( esp_memprot_get_violate_addr(mem_type) ); + panic_print_str( "\r\n world: "); + panic_print_hex( esp_memprot_get_violate_world(mem_type) ); + + char operation = 0; + // IRAM fault: check instruction-fetch flag + if ( mem_type == MEMPROT_IRAM0_SRAM ) { + if ( esp_memprot_get_violate_loadstore(mem_type) == 1 ) { + operation = 'X'; + } + } + // W/R - common + if ( operation == 0 ) { + operation = esp_memprot_get_violate_wr(mem_type) == 1 ? 'W' : 'R'; + } + panic_print_str( "\r\n operation type: "); + panic_print_char( operation ); + + // DRAM/DMA fault: check byte-enables + if ( mem_type == MEMPROT_DRAM0_SRAM ) { + panic_print_str("\r\n byte-enables: " ); + panic_print_hex(esp_memprot_get_violate_byte_en(mem_type)); + } + + panic_print_str("\r\n"); +} +#endif + void panic_print_registers(const void *f, int core) { uint32_t *regs = (uint32_t *)f; @@ -190,7 +234,10 @@ void panic_soc_fill_info(void *f, panic_info_t *info) #if SOC_CPU_NUM > 1 "Interrupt wdt timeout on CPU1", #endif - "Cache error" + "Cache error", +#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE + "Memory protection fault", +#endif }; info->reason = pseudo_reason[0]; @@ -204,14 +251,16 @@ void panic_soc_fill_info(void *f, panic_info_t *info) * assign function print_cache_err_details to our structure's * details field. As its name states, it will give more details * about why the error happened. */ + info->core = esp_cache_err_get_cpuid(); info->reason = pseudo_reason[PANIC_RSN_CACHEERR]; info->details = print_cache_err_details; + } else if (frame->mcause == ETS_T1_WDT_INUM) { /* Watchdog interrupt occured, get the core on which it happened * and update the reason/message accordingly. */ - const int core = esp_cache_err_get_cpuid(); + const int core = esp_cache_err_get_cpuid(); info->core = core; info->exception = PANIC_EXCEPTION_IWDT; @@ -221,6 +270,14 @@ void panic_soc_fill_info(void *f, panic_info_t *info) #endif info->reason = pseudo_reason[PANIC_RSN_INTWDT_CPU0 + core]; } +#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE + else if ( frame->mcause == ETS_MEMPROT_ERR_INUM ) { + + info->core = esp_memprot_intr_get_cpuid(); + info->reason = pseudo_reason[PANIC_RSN_MEMPROT]; + info->details = print_memprot_err_details; + } +#endif } void panic_arch_fill_info(void *frame, panic_info_t *info) diff --git a/components/esp_system/port/arch/xtensa/panic_arch.c b/components/esp_system/port/arch/xtensa/panic_arch.c index e4afe8256d..9576eb8855 100644 --- a/components/esp_system/port/arch/xtensa/panic_arch.c +++ b/components/esp_system/port/arch/xtensa/panic_arch.c @@ -31,11 +31,15 @@ #include "soc/rtc_cntl_reg.h" #if CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/cache_err_int.h" +#ifdef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE #include "esp32s2/memprot.h" +#endif #elif CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/cache_err_int.h" +#ifdef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE #include "esp32s3/memprot.h" #endif +#endif #endif // CONFIG_IDF_TARGET_ESP32 void panic_print_registers(const void *f, int core) @@ -261,6 +265,7 @@ static inline void print_cache_err_details(const void *f) } } +#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE static inline void print_memprot_err_details(const void *f) { uint32_t *fault_addr; @@ -278,6 +283,7 @@ static inline void print_memprot_err_details(const void *f) panic_print_hex( (uint32_t)fault_addr ); panic_print_str(" not permitted.\r\n"); } +#endif #elif CONFIG_IDF_TARGET_ESP32S3 static inline void print_cache_err_details(const void* f) @@ -346,10 +352,6 @@ static inline void print_cache_err_details(const void* f) } panic_print_str("\r\n"); } - -static inline void print_memprot_err_details(const void *f) -{ -} #endif @@ -429,10 +431,13 @@ void panic_soc_fill_info(void *f, panic_info_t *info) #if CONFIG_IDF_TARGET_ESP32S2 if (frame->exccause == PANIC_RSN_CACHEERR) { +#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE if ( esp_memprot_is_intr_ena_any() ) { info->details = print_memprot_err_details; info->reason = "Memory protection fault"; - } else { + } else +#endif + { info->details = print_cache_err_details; } } diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 7042ead5cf..e14cef2c4e 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -63,6 +63,7 @@ #include "esp32s3/rom/cache.h" #include "esp32c3/rom/rtc.h" #include "soc/cache_memory.h" +#include "esp32c3/memprot.h" #endif #include "bootloader_flash_config.h" @@ -253,11 +254,11 @@ void IRAM_ATTR call_start_cpu0(void) // (This should be the first thing IDF app does, as any other piece of code could be // relaxed by the linker to access something relative to __global_pointer$) __asm__ __volatile__ ( - ".option push\n" + ".option push\n" ".option norelax\n" "la gp, __global_pointer$\n" ".option pop" - ); + ); #endif // Move exception vectors to IRAM @@ -453,14 +454,12 @@ void IRAM_ATTR call_start_cpu0(void) esp_cache_err_int_init(); -#if CONFIG_IDF_TARGET_ESP32S2 -#if CONFIG_ESP32S2_MEMPROT_FEATURE -#if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK +#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE +#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK esp_memprot_set_prot(true, true, NULL); #else esp_memprot_set_prot(true, false, NULL); #endif -#endif #endif bootloader_flash_update_id(); diff --git a/components/esp_system/port/panic_handler.c b/components/esp_system/port/panic_handler.c index fad73a8390..a5fcd09a69 100644 --- a/components/esp_system/port/panic_handler.c +++ b/components/esp_system/port/panic_handler.c @@ -37,6 +37,9 @@ #elif CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/memprot.h" #include "esp32s3/cache_err_int.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/memprot.h" +#include "esp32c3/cache_err_int.h" #endif #include "esp_private/panic_internal.h" @@ -47,7 +50,7 @@ extern int _invalid_pc_placeholder; -extern void esp_panic_handler(panic_info_t*); +extern void esp_panic_handler(panic_info_t *); static wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; @@ -181,10 +184,9 @@ static void panic_handler(void *frame, bool pseudo_excause) #endif if (panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU0 #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE - || panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU1 + || panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU1 #endif - ) - { + ) { wdt_hal_write_protect_disable(&wdt0_context); wdt_hal_handle_intr(&wdt0_context); wdt_hal_write_protect_enable(&wdt0_context); @@ -221,7 +223,7 @@ void __attribute__((noreturn)) panic_restart(void) digital_reset_needed = true; } #endif -#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_ESP_SYSTEM_CONFIG_MEMPROT_FEATURE if (esp_memprot_is_intr_ena_any() || esp_memprot_is_locked_any()) { digital_reset_needed = true; } diff --git a/components/esp_system/sdkconfig.rename b/components/esp_system/sdkconfig.rename index 92bec97110..33bdd49f17 100644 --- a/components/esp_system/sdkconfig.rename +++ b/components/esp_system/sdkconfig.rename @@ -10,5 +10,9 @@ CONFIG_ESP32S2_PANIC_PRINT_HALT CONFIG_ESP_SYSTEM_PANIC_ CONFIG_ESP32S2_PANIC_PRINT_REBOOT CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT CONFIG_ESP32S2_PANIC_SILENT_REBOOT CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT CONFIG_ESP32S2_PANIC_GDBSTUB CONFIG_ESP_SYSTEM_PANIC_GDBSTUB +CONFIG_ESP32S2_MEMPROT_FEATURE CONFIG_ESP_SYSTEM_MEMPROT_FEATURE +CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK +CONFIG_ESP32C3_MEMPROT_FEATURE CONFIG_ESP_SYSTEM_MEMPROT_FEATURE +CONFIG_ESP32C3_MEMPROT_FEATURE_LOCK CONFIG_ESP_SYSTEM_MEMPROT_FEATURE_LOCK CONFIG_ESP32_RTC_XTAL_BOOTSTRAP_CYCLES CONFIG_ESP_SYSTEM_RTC_EXT_XTAL_BOOTSTRAP_CYCLES diff --git a/components/esp_system/system_api.c b/components/esp_system/system_api.c index 740940bd73..da96bf72e1 100644 --- a/components/esp_system/system_api.c +++ b/components/esp_system/system_api.c @@ -75,11 +75,15 @@ void IRAM_ATTR esp_restart(void) // Disable scheduler on this core. vTaskSuspendAll(); -#if CONFIG_IDF_TARGET_ESP32S2 + bool digital_reset_needed = false; +#if CONFIG_ESP_SYSTEM_CONFIG_MEMPROT_FEATURE if (esp_memprot_is_intr_ena_any() || esp_memprot_is_locked_any()) { - esp_restart_noos_dig(); + digital_reset_needed = true; } #endif + if (digital_reset_needed) { + esp_restart_noos_dig(); + } esp_restart_noos(); } diff --git a/components/hal/esp32c3/include/hal/memprot_ll.h b/components/hal/esp32c3/include/hal/memprot_ll.h new file mode 100644 index 0000000000..127d51b307 --- /dev/null +++ b/components/hal/esp32c3/include/hal/memprot_ll.h @@ -0,0 +1,446 @@ +// 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 + +#include "soc/sensitive_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * === globals ==== + */ +#ifndef SRAM_IRAM_START +#define SRAM_IRAM_START 0x4037C000 +#endif + +#ifndef SRAM_DRAM_START +#define SRAM_DRAM_START 0x3FC7C000 +#endif + +/* ICache size is fixed to 16KB on ESP32-C3 */ +#ifndef ICACHE_SIZE +#define ICACHE_SIZE 0x4000 +#endif + +#ifndef I_D_SRAM_SEGMENT_SIZE +#define I_D_SRAM_SEGMENT_SIZE 0x20000 +#endif + +#ifndef I_D_SRAM_OFFSET +#define I_D_SRAM_OFFSET (SRAM_IRAM_START - SRAM_DRAM_START) +#endif + +/* 2nd stage bootloader iram_loader_seg start address */ +#ifndef SRAM_DRAM_END +#define SRAM_DRAM_END (0x403D0000 - I_D_SRAM_OFFSET) +#endif + +#ifndef SRAM_IRAM_ORG +#define SRAM_IRAM_ORG (SRAM_IRAM_START + ICACHE_SIZE) +#endif + +#ifndef SRAM_DRAM_ORG +#define SRAM_DRAM_ORG (SRAM_DRAM_START + ICACHE_SIZE) +#endif + +#ifndef I_D_SRAM_SIZE +#define I_D_SRAM_SIZE SRAM_DRAM_END - SRAM_DRAM_ORG +#endif + +#define I_D_SPLIT_LINE_SHIFT 0x9 + +#define MAP_DRAM_TO_IRAM(addr) (addr - SRAM_DRAM_START + SRAM_IRAM_START) +#define MAP_IRAM_TO_DRAM(addr) (addr - SRAM_IRAM_START + SRAM_DRAM_START) + + +static inline void memprot_ll_set_iram0_dram0_split_line_lock(bool lock) +{ + REG_WRITE(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_0_REG, lock ? 1 : 0); +} + +static inline bool memprot_ll_get_iram0_dram0_split_line_lock(void) +{ + return REG_READ(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_0_REG) == 1; +} + + +/** + * === IRAM0 ==== + */ +//16kB (CACHE) +#define IRAM0_SRAM_LEVEL_0_LOW SRAM_IRAM_START //0x40370000 +#define IRAM0_SRAM_LEVEL_0_HIGH (IRAM0_SRAM_LEVEL_0_LOW + ICACHE_SIZE - 0x1) //0x4037FFFF + +//128kB (LEVEL 1) +#define IRAM0_SRAM_LEVEL_1_LOW (IRAM0_SRAM_LEVEL_0_HIGH + 0x1) //0x40380000 +#define IRAM0_SRAM_LEVEL_1_HIGH (IRAM0_SRAM_LEVEL_1_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x4039FFFF + +//128kB (LEVEL 2) +#define IRAM0_SRAM_LEVEL_2_LOW (IRAM0_SRAM_LEVEL_1_HIGH + 0x1) //0x403A0000 +#define IRAM0_SRAM_LEVEL_2_HIGH (IRAM0_SRAM_LEVEL_2_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x403BFFFF + +//128kB (LEVEL 3) +#define IRAM0_SRAM_LEVEL_3_LOW (IRAM0_SRAM_LEVEL_2_HIGH + 0x1) //0x403C0000 +#define IRAM0_SRAM_LEVEL_3_HIGH (IRAM0_SRAM_LEVEL_3_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x403DFFFF + +//permission bits +#define SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R 0x1 +#define SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W 0x2 +#define SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_F 0x4 + +static inline uint32_t memprot_ll_iram0_get_intr_source_num(void) +{ + return ETS_CORE0_IRAM0_PMS_INTR_SOURCE; +} + +/* SPLIT LINE */ + +static inline void memprot_ll_set_iram0_split_line(const void *line_addr, uint32_t sensitive_reg) +{ + uint32_t addr = (uint32_t)line_addr; + assert( addr >= IRAM0_SRAM_LEVEL_1_LOW && addr <= IRAM0_SRAM_LEVEL_3_HIGH ); + + uint32_t category[3] = {0}; + if (addr <= IRAM0_SRAM_LEVEL_1_HIGH) { + category[0] = 0x2; + category[1] = category[2] = 0x3; + } else if (addr >= IRAM0_SRAM_LEVEL_2_LOW && addr <= IRAM0_SRAM_LEVEL_2_HIGH) { + category[1] = 0x2; + category[2] = 0x3; + } else { + category[2] = 0x2; + } + + //category bits are the same for all areas + uint32_t category_bits = + (category[0] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_0_S) | + (category[1] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_1_S) | + (category[2] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_2_S); + + uint32_t conf_addr = ((addr >> I_D_SPLIT_LINE_SHIFT) & SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_V) << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_S; + + uint32_t reg_cfg = conf_addr | category_bits; + + REG_WRITE(sensitive_reg, reg_cfg); +} + +/* can be both IRAM0/DRAM0 address */ +static inline void memprot_ll_set_iram0_split_line_main_I_D(const void *line_addr) +{ + memprot_ll_set_iram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_1_REG); +} + +static inline void memprot_ll_set_iram0_split_line_I_0(const void *line_addr) +{ + memprot_ll_set_iram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_2_REG); +} + +static inline void memprot_ll_set_iram0_split_line_I_1(const void *line_addr) +{ + memprot_ll_set_iram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_3_REG); +} + + +/* PMS */ + +static inline void memprot_ll_iram0_set_pms_lock(bool lock) +{ + REG_WRITE(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG, lock ? 1 : 0); +} + +static inline bool memprot_ll_iram0_get_pms_lock(void) +{ + return REG_READ(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG) == 1; +} + +//world_0 permissions +static inline uint32_t memprot_ll_iram0_set_permissions(bool r, bool w, bool x) +{ + uint32_t permissions = 0; + if ( r ) { + permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R; + } + if ( w ) { + permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W; + } + if ( x ) { + permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_F; + } + + return permissions; +} + +static inline void memprot_ll_iram0_set_pms_area_0(bool r, bool w, bool x) +{ + REG_SET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_0, memprot_ll_iram0_set_permissions(r, w, x)); +} + +static inline void memprot_ll_iram0_set_pms_area_1(bool r, bool w, bool x) +{ + REG_SET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_1, memprot_ll_iram0_set_permissions(r, w, x)); +} + +static inline void memprot_ll_iram0_set_pms_area_2(bool r, bool w, bool x) +{ + REG_SET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_2, memprot_ll_iram0_set_permissions(r, w, x)); +} + +static inline void memprot_ll_iram0_set_pms_area_3(bool r, bool w, bool x) +{ + REG_SET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_3, memprot_ll_iram0_set_permissions(r, w, x)); +} + +/* MONITOR */ + +static inline void memprot_ll_iram0_set_monitor_lock(bool lock) +{ + REG_WRITE(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG, lock ? 1 : 0); +} + +static inline bool memprot_ll_iram0_get_monitor_lock(void) +{ + return REG_READ(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG) == 1; +} + +static inline void memprot_ll_iram0_set_monitor_en(bool enable) +{ + if ( enable ) { + REG_SET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_EN ); + } else { + REG_CLR_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_EN ); + } +} + +static inline bool memprot_ll_iram0_get_monitor_en(void) +{ + return REG_GET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_EN ) == 1; +} + +static inline void memprot_ll_iram0_clear_monitor_intr(void) +{ + REG_CLR_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_CLR ); +} + +static inline uint32_t memprot_ll_iram0_get_monitor_status_intr(void) +{ + return REG_GET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_INTR ); +} + +static inline uint32_t memprot_ll_iram0_get_monitor_status_fault_wr(void) +{ + return REG_GET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_STATUS_WR ); +} + +static inline uint32_t memprot_ll_iram0_get_monitor_status_fault_loadstore(void) +{ + return REG_GET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_STATUS_LOADSTORE ); +} + +static inline uint32_t memprot_ll_iram0_get_monitor_status_fault_world(void) +{ + return REG_GET_FIELD( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_STATUS_WORLD ); +} + +static inline uint32_t memprot_ll_iram0_get_monitor_status_fault_addr(void) +{ + return REG_GET_FIELD( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_STATUS_ADDR ); +} + + +/** + * === DRAM0 ==== + */ + +//cache not available from DRAM +#define DRAM0_SRAM_LEVEL_0_LOW SRAM_DRAM_START //0x3FC7C000 +#define DRAM0_SRAM_LEVEL_0_HIGH (DRAM0_SRAM_LEVEL_0_LOW + ICACHE_SIZE - 0x1) //0x3FC7FFFF + +//128kB +#define DRAM0_SRAM_LEVEL_1_LOW (DRAM0_SRAM_LEVEL_0_HIGH + 0x1) //0x3FC80000 +#define DRAM0_SRAM_LEVEL_1_HIGH (DRAM0_SRAM_LEVEL_1_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x3FC9FFFF + +//128kB +#define DRAM0_SRAM_LEVEL_2_LOW (DRAM0_SRAM_LEVEL_1_HIGH + 0x1) //0x3FCA0000 +#define DRAM0_SRAM_LEVEL_2_HIGH (DRAM0_SRAM_LEVEL_2_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x3FCBFFFF + +//128kB +#define DRAM0_SRAM_LEVEL_3_LOW (DRAM0_SRAM_LEVEL_2_HIGH + 0x1) //0x3FCC0000 +#define DRAM0_SRAM_LEVEL_3_HIGH (DRAM0_SRAM_LEVEL_3_LOW + I_D_SRAM_SEGMENT_SIZE - 0x1) //0x3FCDFFFF + +#define SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W 0x2 +#define SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R 0x1 + + +static inline uint32_t memprot_ll_dram0_get_intr_source_num(void) +{ + return ETS_CORE0_DRAM0_PMS_INTR_SOURCE; +} + + +/* SPLIT LINE */ + +static inline void memprot_ll_set_dram0_split_line(const void *line_addr, uint32_t sensitive_reg) +{ + uint32_t addr = (uint32_t)line_addr; + assert( addr >= DRAM0_SRAM_LEVEL_1_LOW && addr <= DRAM0_SRAM_LEVEL_3_HIGH ); + + uint32_t category[3] = {0}; + if (addr <= DRAM0_SRAM_LEVEL_1_HIGH) { + category[0] = 0x2; + category[1] = category[2] = 0x3; + } else if (addr >= DRAM0_SRAM_LEVEL_2_LOW && addr <= DRAM0_SRAM_LEVEL_2_HIGH) { + category[1] = 0x2; + category[2] = 0x3; + } else { + category[2] = 0x2; + } + + //category bits are the same for all areas + uint32_t category_bits = + (category[0] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_0_S) | + (category[1] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_1_S) | + (category[2] << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_CATEGORY_2_S); + + uint32_t conf_addr = ((addr >> I_D_SPLIT_LINE_SHIFT) & SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_V) << SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_S; + + uint32_t reg_cfg = conf_addr | category_bits; + + REG_WRITE(sensitive_reg, reg_cfg); +} + +static inline void memprot_ll_set_dram0_split_line_D_0(const void *line_addr) +{ + memprot_ll_set_dram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_2_REG); +} + +static inline void memprot_ll_set_dram0_split_line_D_1(const void *line_addr) +{ + memprot_ll_set_dram0_split_line(line_addr, SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_3_REG); +} + + +/* PMS */ + +static inline void memprot_ll_dram0_set_pms_lock(bool lock) +{ + REG_WRITE(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG, lock ? 1 : 0); +} + +static inline bool memprot_ll_dram0_get_pms_lock(void) +{ + return REG_READ(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG) == 1; +} + +static inline uint32_t memprot_ll_dram0_set_permissions(bool r, bool w) +{ + uint32_t permissions = 0; + if ( r ) { + permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R; + } + if ( w ) { + permissions |= SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W; + } + + return permissions; +} + +static inline void memprot_ll_dram0_set_pms_area_0(bool r, bool w) +{ + REG_SET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_0, memprot_ll_dram0_set_permissions(r, w)); +} + +static inline void memprot_ll_dram0_set_pms_area_1(bool r, bool w) +{ + REG_SET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_1, memprot_ll_dram0_set_permissions(r, w)); +} + +static inline void memprot_ll_dram0_set_pms_area_2(bool r, bool w) +{ + REG_SET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_2, memprot_ll_dram0_set_permissions(r, w)); +} + +static inline void memprot_ll_dram0_set_pms_area_3(bool r, bool w) +{ + REG_SET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_3, memprot_ll_dram0_set_permissions(r, w)); +} + + +/* MONITOR */ + +static inline void memprot_ll_dram0_set_monitor_lock(bool lock) +{ + REG_WRITE(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG, lock ? 1 : 0); +} + +static inline bool memprot_ll_dram0_get_monitor_lock(void) +{ + return REG_READ(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG) == 1; +} + +static inline void memprot_ll_dram0_set_monitor_en(bool enable) +{ + if ( enable ) { + REG_SET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_EN ); + } else { + REG_CLR_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_EN ); + } +} + +static inline bool memprot_ll_dram0_get_monitor_en(void) +{ + return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_EN ) == 1; +} + +static inline void memprot_ll_dram0_clear_monitor_intr(void) +{ + REG_CLR_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_CLR ); +} + +static inline uint32_t memprot_ll_dram0_get_monitor_status_intr(void) +{ + return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_INTR ); +} + +static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_lock(void) +{ + return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_LOCK ); +} + +static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_world(void) +{ + return REG_GET_FIELD( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_WORLD ); +} + +static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_addr(void) +{ + return REG_GET_FIELD( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_ADDR ); +} + +static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_wr(void) +{ + return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_3_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_WR ); +} + +static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_byte_en(void) +{ + return REG_GET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_BYTEEN ); +} + + +#ifdef __cplusplus +} +#endif diff --git a/components/heap/test/test_malloc_caps.c b/components/heap/test/test_malloc_caps.c index fbf8e7e7e1..fd3dc02286 100644 --- a/components/heap/test/test_malloc_caps.c +++ b/components/heap/test/test_malloc_caps.c @@ -11,7 +11,7 @@ #include #include -#ifndef CONFIG_ESP32S2_MEMPROT_FEATURE +#ifndef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE TEST_CASE("Capabilities allocator test", "[heap]") { char *m1, *m2[10]; diff --git a/components/heap/test/test_realloc.c b/components/heap/test/test_realloc.c index a3fa2b1c30..60a7749fb0 100644 --- a/components/heap/test/test_realloc.c +++ b/components/heap/test/test_realloc.c @@ -23,7 +23,7 @@ TEST_CASE("realloc shrink buffer in place", "[heap]") #endif -#ifndef CONFIG_ESP32S2_MEMPROT_FEATURE +#ifndef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE TEST_CASE("realloc shrink buffer with EXEC CAPS", "[heap]") { const size_t buffer_size = 64; diff --git a/components/heap/test/test_runtime_heap_reg.c b/components/heap/test/test_runtime_heap_reg.c index 5c0da3f625..92e81d8fdc 100644 --- a/components/heap/test/test_runtime_heap_reg.c +++ b/components/heap/test/test_runtime_heap_reg.c @@ -30,7 +30,7 @@ TEST_CASE("Allocate new heap at runtime", "[heap][ignore]") TEST_CASE("Allocate new heap with new capability", "[heap][ignore]") { const size_t BUF_SZ = 100; -#ifdef CONFIG_ESP32S2_MEMPROT_FEATURE +#ifdef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE const size_t ALLOC_SZ = 32; #else const size_t ALLOC_SZ = 64; // More than half of BUF_SZ diff --git a/components/riscv/include/esp_private/panic_reason.h b/components/riscv/include/esp_private/panic_reason.h index 89d061c444..6cb14d8c5c 100644 --- a/components/riscv/include/esp_private/panic_reason.h +++ b/components/riscv/include/esp_private/panic_reason.h @@ -20,5 +20,8 @@ enum _panic_reasons { PANIC_RSN_INTWDT_CPU1, #endif PANIC_RSN_CACHEERR, +#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE + PANIC_RSN_MEMPROT, +#endif PANIC_RSN_COUNT } panic_reasons; diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index a0ba847a15..2e1c7c477f 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -125,8 +125,13 @@ _vector_table: j _interrupt_handler /* 24 identical entries, all pointing to the interrupt handler */ .endr j _panic_handler /* Call panic handler for ETS_T1_WDT_INUM interrupt (soc-level panic)*/ - j _panic_handler /* Call panic handler for ETS_CACHEERR_INUM interrupt (soc-level panic)*/ + j _panic_handler /* Call panic handler for ETS_CACHEERR_INUM interrupt (soc-level panic)*/ + #ifdef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE + j _panic_handler /* Call panic handler for ETS_MEMPROT_ERR_INUM interrupt (soc-level panic)*/ + .rept (ETS_MAX_INUM - ETS_MEMPROT_ERR_INUM) + #else .rept (ETS_MAX_INUM - ETS_CACHEERR_INUM) + #endif j _interrupt_handler /* 6 identical entries, all pointing to the interrupt handler */ .endr diff --git a/components/soc/esp32c3/include/soc/soc.h b/components/soc/esp32c3/include/soc/soc.h index 3b8847418c..c85b764e43 100644 --- a/components/soc/esp32c3/include/soc/soc.h +++ b/components/soc/esp32c3/include/soc/soc.h @@ -20,6 +20,8 @@ #include "esp_bit_defs.h" #endif +#include "sdkconfig.h" + #define PRO_CPU_NUM (0) #define DR_REG_SYSTEM_BASE 0x600c0000 @@ -314,6 +316,9 @@ #define ETS_FRC1_INUM 22 #define ETS_T1_WDT_INUM 24 #define ETS_CACHEERR_INUM 25 +#ifdef CONFIG_IDF_TARGET_ESP32C3 +#define ETS_MEMPROT_ERR_INUM 26 +#endif #define ETS_DPORT_INUM 28 //CPU0 Max valid interrupt number diff --git a/components/soc/esp32c3/soc_memory_layout.c b/components/soc/esp32c3/soc_memory_layout.c index 1b9ca32c31..f9616cf950 100644 --- a/components/soc/esp32c3/soc_memory_layout.c +++ b/components/soc/esp32c3/soc_memory_layout.c @@ -45,7 +45,7 @@ const soc_memory_type_desc_t soc_memory_types[] = { { "FAKEDRAM", { MALLOC_CAP_8BIT|MALLOC_CAP_DEFAULT, MALLOC_CAP_INTERNAL|MALLOC_CAP_32BIT, 0 }, false, false}, }; -#ifdef CONFIG_ESP32C3_MEMPROT_FEATURE //TODO ESP32-C3 IDF-2092 +#ifdef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE #define SOC_MEMORY_TYPE_DEFAULT 0 #else #define SOC_MEMORY_TYPE_DEFAULT 2 diff --git a/components/soc/esp32s2/soc_memory_layout.c b/components/soc/esp32s2/soc_memory_layout.c index a3c4f97844..fb495e0531 100644 --- a/components/soc/esp32s2/soc_memory_layout.c +++ b/components/soc/esp32s2/soc_memory_layout.c @@ -55,7 +55,7 @@ const soc_memory_type_desc_t soc_memory_types[] = { { "RTCRAM", { MALLOC_CAP_8BIT|MALLOC_CAP_DEFAULT, MALLOC_CAP_INTERNAL|MALLOC_CAP_32BIT, 0 }, false, false}, }; -#ifdef CONFIG_ESP32S2_MEMPROT_FEATURE +#ifdef CONFIG_ESP_SYSTEM_MEMPROT_FEATURE #define SOC_MEMORY_TYPE_DEFAULT 0 #else #define SOC_MEMORY_TYPE_DEFAULT 2 diff --git a/tools/unit-test-app/sdkconfig.defaults.esp32c3 b/tools/unit-test-app/sdkconfig.defaults.esp32c3 new file mode 100644 index 0000000000..d0ea27a6c6 --- /dev/null +++ b/tools/unit-test-app/sdkconfig.defaults.esp32c3 @@ -0,0 +1 @@ +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n diff --git a/tools/unit-test-app/sdkconfig.defaults.esp32s2 b/tools/unit-test-app/sdkconfig.defaults.esp32s2 index 0e3343e532..1175b0ca77 100644 --- a/tools/unit-test-app/sdkconfig.defaults.esp32s2 +++ b/tools/unit-test-app/sdkconfig.defaults.esp32s2 @@ -1,5 +1,5 @@ CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y -CONFIG_ESP32S2_MEMPROT_FEATURE=n +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n CONFIG_ESP32S2_ULP_COPROC_ENABLED=y CONFIG_ESP32S2_ULP_COPROC_RISCV=y