From f27c9c513904d4c0ce9bcaae0eb27cba43cfe105 Mon Sep 17 00:00:00 2001 From: Martin Vychodil Date: Wed, 27 Jan 2021 22:03:07 +0100 Subject: [PATCH] esp32c3: memprot API upgrade and test application Closes IDF-2641 --- .gitlab/ci/target-test.yml | 11 + components/esp32c3/CMakeLists.txt | 4 +- components/esp32c3/include/esp32c3/memprot.h | 383 ++++++++++++++++- components/esp32c3/ld/esp32c3.project.ld.in | 2 + components/esp32c3/memprot.c | 240 +++++++---- components/esp32s2/include/esp32s2/memprot.h | 26 ++ components/esp32s2/ld/esp32s2.project.ld.in | 4 +- components/esp32s2/memprot.c | 14 +- .../esp_system/port/arch/riscv/panic_arch.c | 14 +- .../hal/esp32c3/include/hal/memprot_ll.h | 277 +++++++++---- .../hal/esp32s2/include/hal/memprot_ll.h | 53 +-- .../hal/esp32s2/include/hal/memprot_peri_ll.h | 25 +- tools/test_apps/system/memprot/CMakeLists.txt | 2 +- tools/test_apps/system/memprot/README.md | 4 +- tools/test_apps/system/memprot/app_test.py | 21 +- .../system/memprot/main/CMakeLists.txt | 7 +- .../system/memprot/main/Kconfig.projbuild | 4 + .../memprot/main/esp32c3/return_from_panic.S | 71 ++++ .../memprot/main/esp32c3/test_memprot_main.c | 392 ++++++++++++++++++ .../system/memprot/main/esp32c3/test_panic.c | 52 +++ .../main/{ => esp32s2}/test_memprot_main.c | 187 +++++---- .../memprot/main/{ => esp32s2}/test_panic.c | 0 tools/test_apps/system/memprot/sdkconfig.ci | 8 +- 23 files changed, 1503 insertions(+), 298 deletions(-) create mode 100644 tools/test_apps/system/memprot/main/Kconfig.projbuild create mode 100644 tools/test_apps/system/memprot/main/esp32c3/return_from_panic.S create mode 100644 tools/test_apps/system/memprot/main/esp32c3/test_memprot_main.c create mode 100644 tools/test_apps/system/memprot/main/esp32c3/test_panic.c rename tools/test_apps/system/memprot/main/{ => esp32s2}/test_memprot_main.c (68%) rename tools/test_apps/system/memprot/main/{ => esp32s2}/test_panic.c (100%) diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index b55c157001..2504d0a724 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -281,6 +281,11 @@ example_test_C3_FLASH_ENC_OTA: - .test_app_template - .rules:test:custom_test-esp32s2 +.test_app_esp32c3_template: + extends: + - .test_app_template + - .rules:test:custom_test-esp32c3 + test_app_test_001: extends: .test_app_esp32_template tags: @@ -311,6 +316,12 @@ test_app_test_004: - ESP32S2 - Example_GENERIC +test_app_test_005: + extends: .test_app_esp32c3_template + tags: + - ESP32C3 + - Example_GENERIC + test_app_test_esp32_generic: extends: .test_app_esp32_template parallel: 4 diff --git a/components/esp32c3/CMakeLists.txt b/components/esp32c3/CMakeLists.txt index 59dc113a24..a785c520dc 100644 --- a/components/esp32c3/CMakeLists.txt +++ b/components/esp32c3/CMakeLists.txt @@ -38,9 +38,9 @@ else() # Process the template file through the linker script generation mechanism, and use the output for linking the # final binary target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/ld/esp32c3.project.ld.in" - PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32c3.project.ld") - + PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32c3.project.ld") target_linker_script(${COMPONENT_LIB} INTERFACE "ld/esp32c3.peripherals.ld") + target_link_libraries(${COMPONENT_LIB} PUBLIC gcc) target_link_libraries(${COMPONENT_LIB} INTERFACE "-u call_user_start_cpu0") diff --git a/components/esp32c3/include/esp32c3/memprot.h b/components/esp32c3/include/esp32c3/memprot.h index 9085fd8e06..094f28f42e 100644 --- a/components/esp32c3/include/esp32c3/memprot.h +++ b/components/esp32c3/include/esp32c3/memprot.h @@ -26,6 +26,22 @@ extern "C" { #endif +#ifndef IRAM_SRAM_START +#define IRAM_SRAM_START 0x4037C000 +#endif + +#ifndef DRAM_SRAM_START +#define DRAM_SRAM_START 0x3FC7C000 +#endif + +#ifndef MAP_DRAM_TO_IRAM +#define MAP_DRAM_TO_IRAM(addr) (addr - DRAM_SRAM_START + IRAM_SRAM_START) +#endif + +#ifndef MAP_IRAM_TO_DRAM +#define MAP_IRAM_TO_DRAM(addr) (addr - IRAM_SRAM_START + DRAM_SRAM_START) +#endif + typedef enum { MEMPROT_NONE = 0x00000000, MEMPROT_IRAM0_SRAM = 0x00000001, @@ -34,6 +50,7 @@ typedef enum { } mem_type_prot_t; typedef enum { + MEMPROT_SPLITLINE_NONE = 0, MEMPROT_IRAM0_DRAM0_SPLITLINE, MEMPROT_IRAM0_LINE_0_SPLITLINE, MEMPROT_IRAM0_LINE_1_SPLITLINE, @@ -42,6 +59,7 @@ typedef enum { } split_line_t; typedef enum { + MEMPROT_PMS_AREA_NONE = 0, MEMPROT_IRAM0_PMS_AREA_0, MEMPROT_IRAM0_PMS_AREA_1, MEMPROT_IRAM0_PMS_AREA_2, @@ -52,43 +70,386 @@ typedef enum { MEMPROT_DRAM0_PMS_AREA_3 } pms_area_t; +typedef enum +{ + MEMPROT_PMS_WORLD_0 = 0, + MEMPROT_PMS_WORLD_1, + MEMPROT_PMS_WORLD_2, + MEMPROT_PMS_WORLD_INVALID = 0xFFFFFFFF +} pms_world_t; -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); +typedef enum +{ + MEMPROT_PMS_OP_READ = 0, + MEMPROT_PMS_OP_WRITE, + MEMPROT_PMS_OP_FETCH, + MEMPROT_PMS_OP_INVALID = 0xFFFFFFFF +} pms_operation_type_t; -void *esp_memprot_get_main_split_addr(void); -void esp_memprot_set_split_line_lock(bool lock); +/** + * @brief Converts Memory protection type to string + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + */ +const char *esp_memprot_mem_type_to_str(mem_type_prot_t mem_type); + +/** + * @brief Converts Split line type to string + * + * @param line_type Split line type (see split_line_t enum) + */ +const char *esp_memprot_split_line_to_str(split_line_t line_type); + +/** + * @brief Converts PMS Area type to string + * + * @param area_type PMS Area type (see pms_area_t enum) + */ +const char *esp_memprot_pms_to_str(pms_area_t area_type); + +/** + * @brief Returns PMS splitting address for given Split line type + * + * The value is taken from PMS configuration registers (IRam0 range) + * For details on split lines see 'esp_memprot_set_prot_int' function description + * + * @param line_type Split line type (see split_line_t enum) + * + * @return appropriate split line address + */ +uint32_t *esp_memprot_get_split_addr(split_line_t line_type); + +/** + * @brief Returns default main IRAM/DRAM splitting address + * + * The address value is given by _iram_text_end global (IRam0 range) + + * @return Main I/D split line (IRam0_DRam0_Split_Addr) + */ +void *esp_memprot_get_default_main_split_addr(void); + +/** + * @brief Sets a lock for the main IRAM/DRAM splitting address + * + * Locks can be unlocked only by digital system reset + */ +void esp_memprot_set_split_line_lock(void); + +/** + * @brief Gets a lock status for the main IRAM/DRAM splitting address + * + * @return true/false (locked/unlocked) + */ bool esp_memprot_get_split_line_lock(void); + +/** + * @brief Sets required split line address + * + * @param line_type Split line type (see split_line_t enum) + * @param line_addr target address from a memory range relevant to given line_type (IRAM/DRAM) + */ void esp_memprot_set_split_line(split_line_t line_type, const void *line_addr); -void esp_memprot_set_pms_lock(mem_type_prot_t mem_type, bool lock); +/** + * @brief Sets a lock for PMS Area settings of required Memory type + * + * Locks can be unlocked only by digital system reset + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + */ +void esp_memprot_set_pms_lock(mem_type_prot_t mem_type); + +/** + * @brief Gets a lock status for PMS Area settings of required Memory type + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * + * @return true/false (locked/unlocked) + */ bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type); + +/** + * @brief Sets permissions for given PMS Area in IRam0 memory range (MEMPROT_IRAM0_SRAM) + * + * @param area_type IRam0 PMS Area type (see pms_area_t enum) + * @param r Read permission flag + * @param w Write permission flag + * @param x Execute permission flag + */ void esp_memprot_iram_set_pms_area(pms_area_t area_type, bool r, bool w, bool x); + +/** + * @brief Gets current permissions for given PMS Area in IRam0 memory range (MEMPROT_IRAM0_SRAM) + * + * @param area_type IRam0 PMS Area type (see pms_area_t enum) + * @param r Read permission flag holder + * @param w Write permission flag holder + * @param x Execute permission flag holder + */ +void esp_memprot_iram_get_pms_area(pms_area_t area_type, bool *r, bool *w, bool *x); + +/** + * @brief Sets permissions for given PMS Area in DRam0 memory range (MEMPROT_DRAM0_SRAM) + * + * @param area_type DRam0 PMS Area type (see pms_area_t enum) + * @param r Read permission flag + * @param w Write permission flag + */ void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w); -void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type, bool lock); +/** + * @brief Gets current permissions for given PMS Area in DRam0 memory range (MEMPROT_DRAM0_SRAM) + * + * @param area_type DRam0 PMS Area type (see pms_area_t enum) + * @param r Read permission flag holder + * @param w Write permission flag holder + */ +void esp_memprot_dram_get_pms_area(pms_area_t area_type, bool *r, bool *w); + +/** + * @brief Sets a lock for PMS interrupt monitor settings of required Memory type + * + * Locks can be unlocked only by digital system reset + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + */ +void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type); + +/** + * @brief Gets a lock status for PMS interrupt monitor settings of required Memory type + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * + * @return true/false (locked/unlocked) + */ bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type); + +/** + * @brief Enable PMS violation interrupt monitoring of required Memory type + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * @param enable/disable + */ void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable); + +/** + * @brief Gets enable/disable status for PMS interrupt monitor settings of required Memory type + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * + * @return true/false (enabled/disabled) + */ bool esp_memprot_get_monitor_en(mem_type_prot_t mem_type); +/** + * @brief Gets CPU ID for currently active PMS violation interrupt + * + * @return CPU ID (CPU_PRO for ESP32C3) + */ int IRAM_ATTR esp_memprot_intr_get_cpuid(void); + +/** + * @brief Clears current interrupt ON flag for given Memory type + * + * Interrupt clearing happens in two steps: + * 1. Interrupt CLR flag is set (to clear the interrupt ON status) + * 2. Interrupt CLR flag is reset (to allow further monitoring) + * This operation is non-atomic by PMS module design + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + */ void IRAM_ATTR esp_memprot_monitor_clear_intr(mem_type_prot_t mem_type); + +/** + * @brief Returns active PMS violation interrupt (if any) + * + * This function iterates through supported Memory type status registers + * and returns the first interrupt-on flag. If none is found active, + * MEMPROT_NONE is returned. + * Order of checking (in current version): + * 1. MEMPROT_IRAM0_SRAM + * 2. MEMPROT_DRAM0_SRAM + * + * @return mem_type Memory protection type related to active interrupt found (see mem_type_prot_t enum) + */ mem_type_prot_t IRAM_ATTR esp_memprot_get_active_intr_memtype(void); + +/** + * @brief Checks whether any violation interrupt is active + * + * @return true/false (yes/no) + */ bool IRAM_ATTR esp_memprot_is_locked_any(void); + +/** + * @brief Checks whether any violation interrupt is enabled + * + * @return true/false (yes/no) + */ bool IRAM_ATTR esp_memprot_is_intr_ena_any(void); -uint32_t IRAM_ATTR esp_memprot_get_violate_intr_on(mem_type_prot_t mem_type); +/** + * @brief Checks whether any violation interrupt is enabled + * + * @return true/false (yes/no) + */ +bool IRAM_ATTR esp_memprot_get_violate_intr_on(mem_type_prot_t mem_type); + +/** + * @brief Returns the address which caused the violation interrupt (if any) + * + * The address is taken from appropriate PMS violation status register, based given Memory type + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * + * @return faulting address + */ 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); + +/** + * @brief Returns the World identifier of the code causing the violation interrupt (if any) + * + * The value is taken from appropriate PMS violation status register, based given Memory type + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * + * @return World identifier (see pms_world_t enum) + */ +pms_world_t IRAM_ATTR esp_memprot_get_violate_world(mem_type_prot_t mem_type); + +/** + * @brief Returns Read or Write operation type which caused the violation interrupt (if any) + * + * The value (bit) is taken from appropriate PMS violation status register, based given Memory type + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * + * @return PMS operation type relevant to mem_type parameter (se pms_operation_type_t) + */ +pms_operation_type_t IRAM_ATTR esp_memprot_get_violate_wr(mem_type_prot_t mem_type); + +/** + * @brief Returns LoadStore flag of the operation type which caused the violation interrupt (if any) + * + * The value (bit) is taken from appropriate PMS violation status register, based given Memory type + * Effective only on IRam0 access + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * + * @return true/false (LoadStore bit on/off) + */ +bool IRAM_ATTR esp_memprot_get_violate_loadstore(mem_type_prot_t mem_type); + +/** + * @brief Returns byte-enables for the address which caused the violation interrupt (if any) + * + * The value is taken from appropriate PMS violation status register, based given Memory type + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * + * @return byte-enables + */ uint32_t IRAM_ATTR esp_memprot_get_violate_byte_en(mem_type_prot_t mem_type); +/** + * @brief Returns raw contents of DRam0 status register 1 + * + * @return 32-bit register value + */ +uint32_t IRAM_ATTR esp_memprot_get_dram_status_reg_1(void); + +/** + * @brief Returns raw contents of DRam0 status register 2 + * + * @return 32-bit register value + */ +uint32_t IRAM_ATTR esp_memprot_get_dram_status_reg_2(void); + +/** + * @brief Returns raw contents of IRam0 status register + * + * @return 32-bit register value + */ +uint32_t IRAM_ATTR esp_memprot_get_iram_status_reg(void); + +/** + * @brief Register PMS violation interrupt in global interrupt matrix for given Memory type + * + * Memory protection components uses specific interrupt number, see ETS_MEMPROT_ERR_INUM + * The registration makes the panic-handler routine being called when the interrupt appears + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + */ void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type); + +/** + * @brief Convenient routine for setting the PMS defaults + * + * Called on application startup, depending on CONFIG_ESP_SYSTEM_MEMPROT_FEATURE Kconfig settings + * For implementation details see 'esp_memprot_set_prot_int' description + * + * @param invoke_panic_handler register all interrupts for panic handling (true/false) + * @param lock_feature lock the defaults to prevent further PMS settings changes (true/false) + * @param mem_type_mask 32-bit field of specific PMS parts to configure (see 'esp_memprot_set_prot_int') + */ void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t *mem_type_mask); + +/** + * @brief Internal routine for setting the PMS defaults + * + * Called on application startup from within 'esp_memprot_set_prot'. Allows setting a specific splitting address + * (main I/D split line) - see the parameter 'split_addr'. If the 'split_addr' equals to NULL, default I/D split line + * is used (&_iram_text_end) and all the remaining lines share the same address. + * The function sets all the split lines and PMS areas to the same space, + * ie there is a single instruction space and single data space at the end. + * The PMS split lines and permission areas scheme described below: + * + * DRam0/DMA IRam0 + * ----------------------------------------------- + * ... | IRam0_PMS_0 | + * DRam0_PMS_0 ----------------------------------------------- IRam0_line1_Split_addr + * ... | IRam0_PMS_1 | + * ... ----------------------------------------------- IRam0_line0_Split_addr + * | IRam0_PMS_2 | + * =============================================== IRam0_DRam0_Split_addr (main I/D) + * | DRam0_PMS_1 | + * DRam0_DMA_line0_Split_addr ----------------------------------------------- ... + * | DRam0_PMS_2 | ... + * DRam0_DMA_line1_Split_addr ----------------------------------------------- IRam0_PMS_3 + * | DRam0_PMS_3 | ... + * ----------------------------------------------- + * + * Default settings provided by 'esp_memprot_set_prot_int' are as follows: + * + * DRam0/DMA IRam0 + * ----------------------------------------------- + * | IRam0_PMS_0 = IRam0_PMS_1 = IRam0_PMS_2 | + * | DRam0_PMS_0 | IRam0_line1_Split_addr + * DRam0_DMA_line0_Split_addr | | = + * = =============================================== IRam0_line0_Split_addr + * DRam0_DMA_line1_Split_addr | | = + * | DRam0_PMS_1 = DRam0_PMS_2 = DRam0_PMS_3 | IRam0_DRam0_Split_addr (main I/D) + * | IRam0_PMS_3 | + * ----------------------------------------------- + * + * Once the memprot feature is locked, it can be unlocked only by digital system reset + * + * @param invoke_panic_handler register all the violation interrupts for panic handling (true/false) + * @param lock_feature lock the defaults to prevent further PMS settings changes (true/false) + * @param split_addr specific main I/D adrees or NULL to use default ($_iram_text_end) + * @param mem_type_mask 32-bit field of specific PMS parts to configure (members of mem_type_prot_t) + */ void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void *split_addr, uint32_t *mem_type_mask); +/** + * @brief Returns raw contents of PMS interrupt monitor register for given Memory type + * + * @param mem_type Memory protection type (see mem_type_prot_t enum) + * + * @return 32-bit register value + */ +uint32_t esp_memprot_get_monitor_enable_reg(mem_type_prot_t mem_type); + #ifdef __cplusplus } #endif diff --git a/components/esp32c3/ld/esp32c3.project.ld.in b/components/esp32c3/ld/esp32c3.project.ld.in index db96123e73..a34486c8e3 100644 --- a/components/esp32c3/ld/esp32c3.project.ld.in +++ b/components/esp32c3/ld/esp32c3.project.ld.in @@ -340,6 +340,8 @@ SECTIONS { /* C3 memprot requires 512 B alignment for split lines */ . = ALIGN (0x200); + /* iram_end_test section exists for use by memprot unit tests only */ + *(.iram_end_test) _iram_text_end = ABSOLUTE(.); } > iram0_0_seg diff --git a/components/esp32c3/memprot.c b/components/esp32c3/memprot.c index 85e01e5d44..20cc054ad5 100644 --- a/components/esp32c3/memprot.c +++ b/components/esp32c3/memprot.c @@ -22,34 +22,32 @@ #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 "esp32c3/memprot.h" #include "riscv/interrupt.h" +#include "esp32c3/rom/ets_sys.h" #include "esp_log.h" extern int _iram_text_end; +static const char *TAG = "memprot"; -const char *mem_type_to_str(mem_type_prot_t mem_type) +const char *esp_memprot_mem_type_to_str(mem_type_prot_t mem_type) { switch (mem_type) { case MEMPROT_NONE: - return "MEMPROT_NONE"; + return "NONE"; case MEMPROT_IRAM0_SRAM: - return "MEMPROT_IRAM0_SRAM"; + return "IRAM0_SRAM"; case MEMPROT_DRAM0_SRAM: - return "MEMPROT_DRAM0_SRAM"; + return "DRAM0_SRAM"; case MEMPROT_ALL: - return "MEMPROT_ALL"; + return "ALL"; default: return "UNKNOWN"; } } -const char *split_line_to_str(split_line_t line_type) +const char *esp_memprot_split_line_to_str(split_line_t line_type) { switch (line_type) { case MEMPROT_IRAM0_DRAM0_SPLITLINE: @@ -67,7 +65,7 @@ const char *split_line_to_str(split_line_t line_type) } } -const char *pms_to_str(pms_area_t area_type) +const char *esp_memprot_pms_to_str(pms_area_t area_type) { switch (area_type) { case MEMPROT_IRAM0_PMS_AREA_0: @@ -94,14 +92,32 @@ const char *pms_to_str(pms_area_t area_type) /* split lines */ -void *esp_memprot_get_main_split_addr() +void *esp_memprot_get_default_main_split_addr() { return &_iram_text_end; } -void esp_memprot_set_split_line_lock(bool lock) +uint32_t *esp_memprot_get_split_addr(split_line_t line_type) { - memprot_ll_set_iram0_dram0_split_line_lock(lock); + switch ( line_type ) { + case MEMPROT_IRAM0_DRAM0_SPLITLINE: + return memprot_ll_get_iram0_split_line_main_I_D(); + case MEMPROT_IRAM0_LINE_0_SPLITLINE: + return memprot_ll_get_iram0_split_line_I_0(); + case MEMPROT_IRAM0_LINE_1_SPLITLINE: + return memprot_ll_get_iram0_split_line_I_1(); + case MEMPROT_DRAM0_DMA_LINE_0_SPLITLINE: + return memprot_ll_get_dram0_split_line_D_0(); + case MEMPROT_DRAM0_DMA_LINE_1_SPLITLINE: + return memprot_ll_get_dram0_split_line_D_1(); + default: + abort(); + } +} + +void esp_memprot_set_split_line_lock() +{ + memprot_ll_set_iram0_dram0_split_line_lock(); } bool esp_memprot_get_split_line_lock() @@ -111,11 +127,10 @@ bool esp_memprot_get_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_EARLY_LOGD(TAG, "Setting split line %s, addr: 0x%08X", split_line_to_str(line_type), addr); + ESP_EARLY_LOGD(TAG, "Setting split line %s, addr: 0x%08X", esp_memprot_split_line_to_str(line_type), (uint32_t)line_addr); - //split-line must be divisible by 512 - assert( addr % 0x200 == 0 ); + //split-line must be divisible by 512 (PMS module restriction) + assert( ((uint32_t)line_addr) % 0x200 == 0 ); switch ( line_type ) { case MEMPROT_IRAM0_DRAM0_SPLITLINE: @@ -134,36 +149,34 @@ void esp_memprot_set_split_line(split_line_t line_type, const void *line_addr) memprot_ll_set_dram0_split_line_D_1(line_addr); break; default: - ESP_EARLY_LOGE(TAG, "Invalid split line type, aborting: 0x%08X", addr); + ESP_EARLY_LOGE(TAG, "Invalid split line type, aborting: 0x%08X", (uint32_t)line_addr); abort(); } } -// TODO - get split lines - /* PMS */ -void esp_memprot_set_pms_lock(mem_type_prot_t mem_type, bool lock) +void esp_memprot_set_pms_lock(mem_type_prot_t mem_type) { - ESP_EARLY_LOGD(TAG, "esp_memprot_set_pms_lock(%s, %s)", mem_type_to_str(mem_type), lock ? "true" : "false"); + ESP_EARLY_LOGD(TAG, "esp_memprot_set_pms_lock(%s)", esp_memprot_mem_type_to_str(mem_type)); switch ( mem_type ) { case MEMPROT_IRAM0_SRAM: - memprot_ll_iram0_set_pms_lock(lock); + memprot_ll_iram0_set_pms_lock(); break; case MEMPROT_DRAM0_SRAM: - memprot_ll_dram0_set_pms_lock(lock); + memprot_ll_dram0_set_pms_lock(); break; default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type) { - ESP_EARLY_LOGD(TAG, "esp_memprot_get_pms_lock(%s)", mem_type_to_str(mem_type)); + ESP_EARLY_LOGD(TAG, "esp_memprot_get_pms_lock(%s)", esp_memprot_mem_type_to_str(mem_type)); switch ( mem_type ) { case MEMPROT_IRAM0_SRAM: @@ -171,14 +184,14 @@ bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type) case MEMPROT_DRAM0_SRAM: return memprot_ll_dram0_get_pms_lock(); default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_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_EARLY_LOGD(TAG, "esp_memprot_iram_set_pms_area(area:%s r:%u w:%u, x:%u)", pms_to_str(area_type), r, w, x); + ESP_EARLY_LOGD(TAG, "esp_memprot_iram_set_pms_area(area:%s r:%u w:%u, x:%u)", esp_memprot_pms_to_str(area_type), r, w, x); switch ( area_type ) { case MEMPROT_IRAM0_PMS_AREA_0: @@ -194,14 +207,37 @@ void esp_memprot_iram_set_pms_area(pms_area_t area_type, bool r, bool w, bool x) memprot_ll_iram0_set_pms_area_3(r, w, x); break; default: - ESP_EARLY_LOGE(TAG, "Invalid area_type %d", pms_to_str(area_type)); + ESP_EARLY_LOGE(TAG, "Invalid area_type %d", esp_memprot_pms_to_str(area_type)); + abort(); + } +} + +void esp_memprot_iram_get_pms_area(pms_area_t area_type, bool *r, bool *w, bool *x) +{ + ESP_EARLY_LOGD(TAG, "esp_memprot_iram_get_pms_area(area:%s r:%u w:%u)", esp_memprot_pms_to_str(area_type), r, w); + + switch ( area_type ) { + case MEMPROT_IRAM0_PMS_AREA_0: + memprot_ll_iram0_get_pms_area_0(r, w, x); + break; + case MEMPROT_IRAM0_PMS_AREA_1: + memprot_ll_iram0_get_pms_area_1(r, w, x); + break; + case MEMPROT_IRAM0_PMS_AREA_2: + memprot_ll_iram0_get_pms_area_2(r, w, x); + break; + case MEMPROT_IRAM0_PMS_AREA_3: + memprot_ll_iram0_get_pms_area_3(r, w, x); + break; + default: + ESP_EARLY_LOGE(TAG, "Invalid area_type %d", esp_memprot_pms_to_str(area_type)); abort(); } } void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w) { - ESP_EARLY_LOGD(TAG, "esp_memprot_dram_set_pms_area(area:%s r:%u w:%u)", pms_to_str(area_type), r, w); + ESP_EARLY_LOGD(TAG, "esp_memprot_dram_set_pms_area(area:%s r:%u w:%u)", esp_memprot_pms_to_str(area_type), r, w); switch ( area_type ) { case MEMPROT_DRAM0_PMS_AREA_0: @@ -217,36 +253,57 @@ void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w) memprot_ll_dram0_set_pms_area_3(r, w); break; default: - ESP_EARLY_LOGE(TAG, "Invalid area_type %d", pms_to_str(area_type)); + ESP_EARLY_LOGE(TAG, "Invalid area_type %d", esp_memprot_pms_to_str(area_type)); abort(); } } -/* TODO - get single areas */ +void esp_memprot_dram_get_pms_area(pms_area_t area_type, bool *r, bool *w) +{ + ESP_EARLY_LOGD(TAG, "esp_memprot_dram_get_pms_area(area:%s r:%u w:%u)", esp_memprot_pms_to_str(area_type), r, w); + + switch ( area_type ) { + case MEMPROT_DRAM0_PMS_AREA_0: + memprot_ll_dram0_get_pms_area_0(r, w); + break; + case MEMPROT_DRAM0_PMS_AREA_1: + memprot_ll_dram0_get_pms_area_1(r, w); + break; + case MEMPROT_DRAM0_PMS_AREA_2: + memprot_ll_dram0_get_pms_area_2(r, w); + break; + case MEMPROT_DRAM0_PMS_AREA_3: + memprot_ll_dram0_get_pms_area_3(r, w); + break; + default: + ESP_EARLY_LOGE(TAG, "Invalid area_type %d", esp_memprot_pms_to_str(area_type)); + abort(); + } +} /* monitor */ -void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type, bool lock) +void esp_memprot_set_monitor_lock(mem_type_prot_t mem_type) { - ESP_EARLY_LOGD(TAG, "esp_memprot_set_monitor_lock(%s, %s)", mem_type_to_str(mem_type), lock ? "true" : "false"); + ESP_EARLY_LOGD(TAG, "esp_memprot_set_monitor_lock(%s)", esp_memprot_mem_type_to_str(mem_type)); switch ( mem_type ) { case MEMPROT_IRAM0_SRAM: - memprot_ll_iram0_set_monitor_lock(lock); + memprot_ll_iram0_set_monitor_lock(); break; case MEMPROT_DRAM0_SRAM: - memprot_ll_dram0_set_monitor_lock(lock); + memprot_ll_dram0_set_monitor_lock(); break; default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type) { - ESP_EARLY_LOGD(TAG, "esp_memprot_get_monitor_lock(%s)", mem_type_to_str(mem_type)); + ESP_EARLY_LOGD(TAG, "esp_memprot_get_monitor_lock(%s)", esp_memprot_mem_type_to_str(mem_type)); switch ( mem_type ) { case MEMPROT_IRAM0_SRAM: @@ -254,14 +311,14 @@ bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type) case MEMPROT_DRAM0_SRAM: return memprot_ll_dram0_get_monitor_lock(); default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable) { - ESP_EARLY_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", mem_type_to_str(mem_type)); + ESP_EARLY_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", esp_memprot_mem_type_to_str(mem_type)); switch ( mem_type ) { case MEMPROT_IRAM0_SRAM: @@ -271,14 +328,14 @@ void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable) memprot_ll_dram0_set_monitor_en(enable); break; default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } bool esp_memprot_get_monitor_en(mem_type_prot_t mem_type) { - ESP_EARLY_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", mem_type_to_str(mem_type)); + ESP_EARLY_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", esp_memprot_mem_type_to_str(mem_type)); switch ( mem_type ) { case MEMPROT_IRAM0_SRAM: @@ -286,7 +343,7 @@ bool esp_memprot_get_monitor_en(mem_type_prot_t mem_type) case MEMPROT_DRAM0_SRAM: return memprot_ll_dram0_get_monitor_en(); default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } @@ -298,17 +355,19 @@ bool esp_memprot_is_intr_ena_any() void esp_memprot_monitor_clear_intr(mem_type_prot_t mem_type) { - ESP_EARLY_LOGD(TAG, "esp_memprot_monitor_clear_intr(%s)", mem_type_to_str(mem_type)); + ESP_EARLY_LOGD(TAG, "esp_memprot_monitor_clear_intr(%s)", esp_memprot_mem_type_to_str(mem_type)); switch ( mem_type ) { case MEMPROT_IRAM0_SRAM: memprot_ll_iram0_clear_monitor_intr(); + memprot_ll_iram0_reset_clear_monitor_intr(); break; case MEMPROT_DRAM0_SRAM: memprot_ll_dram0_clear_monitor_intr(); + memprot_ll_dram0_reset_clear_monitor_intr(); break; default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } @@ -334,15 +393,15 @@ bool esp_memprot_is_locked_any() esp_memprot_get_monitor_lock(MEMPROT_DRAM0_SRAM); } -uint32_t esp_memprot_get_violate_intr_on(mem_type_prot_t mem_type) +bool 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(); + return memprot_ll_iram0_get_monitor_status_intr() == 1; case MEMPROT_DRAM0_SRAM: - return memprot_ll_dram0_get_monitor_status_intr(); + return memprot_ll_dram0_get_monitor_status_intr() == 1; default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } @@ -355,44 +414,54 @@ uint32_t esp_memprot_get_violate_addr(mem_type_prot_t mem_type) case MEMPROT_DRAM0_SRAM: return memprot_ll_dram0_get_monitor_status_fault_addr(); default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } -uint32_t esp_memprot_get_violate_world(mem_type_prot_t mem_type) +pms_world_t esp_memprot_get_violate_world(mem_type_prot_t mem_type) { + uint32_t world = 0; + switch ( mem_type ) { case MEMPROT_IRAM0_SRAM: - return memprot_ll_iram0_get_monitor_status_fault_world(); + world = memprot_ll_iram0_get_monitor_status_fault_world(); + break; case MEMPROT_DRAM0_SRAM: - return memprot_ll_dram0_get_monitor_status_fault_world(); + world = memprot_ll_dram0_get_monitor_status_fault_world(); + break; default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } + + switch ( world ) { + case 0x01: return MEMPROT_PMS_WORLD_0; + case 0x10: return MEMPROT_PMS_WORLD_1; + default: return MEMPROT_PMS_WORLD_INVALID; + } } -uint32_t esp_memprot_get_violate_wr(mem_type_prot_t mem_type) +pms_operation_type_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(); + return memprot_ll_iram0_get_monitor_status_fault_wr() == 1 ? MEMPROT_PMS_OP_WRITE : MEMPROT_PMS_OP_READ; case MEMPROT_DRAM0_SRAM: - return memprot_ll_dram0_get_monitor_status_fault_wr(); + return memprot_ll_dram0_get_monitor_status_fault_wr() == 1 ? MEMPROT_PMS_OP_WRITE : MEMPROT_PMS_OP_READ; default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } -uint32_t esp_memprot_get_violate_loadstore(mem_type_prot_t mem_type) +bool 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(); + return memprot_ll_iram0_get_monitor_status_fault_loadstore() == 1; default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } @@ -403,7 +472,7 @@ uint32_t esp_memprot_get_violate_byte_en(mem_type_prot_t mem_type) case MEMPROT_DRAM0_SRAM: return memprot_ll_dram0_get_monitor_status_fault_byte_en(); default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } } @@ -415,7 +484,7 @@ int esp_memprot_intr_get_cpuid() void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type) { - ESP_EARLY_LOGD(TAG, "esp_memprot_set_intr_matrix(%s)", mem_type_to_str(mem_type)); + ESP_EARLY_LOGD(TAG, "esp_memprot_set_intr_matrix(%s)", esp_memprot_mem_type_to_str(mem_type)); ESP_INTR_DISABLE(ETS_MEMPROT_ERR_INUM); @@ -427,7 +496,7 @@ void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type) intr_matrix_set(esp_memprot_intr_get_cpuid(), memprot_ll_dram0_get_intr_source_num(), ETS_MEMPROT_ERR_INUM); break; default: - ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type)); + ESP_EARLY_LOGE(TAG, "Invalid mem_type (%s), aborting", esp_memprot_mem_type_to_str(mem_type)); abort(); } @@ -474,7 +543,7 @@ void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void } //set split lines (must-have for all mem_types) - const void *line_addr = split_addr == NULL ? esp_memprot_get_main_split_addr() : split_addr; + const void *line_addr = split_addr == NULL ? esp_memprot_get_default_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); @@ -507,14 +576,41 @@ void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void //lock if required if (lock_feature) { - esp_memprot_set_split_line_lock(true); + esp_memprot_set_split_line_lock(); if (use_iram0) { - esp_memprot_set_pms_lock(MEMPROT_IRAM0_SRAM, true); - esp_memprot_set_monitor_lock(MEMPROT_IRAM0_SRAM, true); + esp_memprot_set_pms_lock(MEMPROT_IRAM0_SRAM); + esp_memprot_set_monitor_lock(MEMPROT_IRAM0_SRAM); } if (use_dram0) { - esp_memprot_set_pms_lock(MEMPROT_DRAM0_SRAM, true); - esp_memprot_set_monitor_lock(MEMPROT_DRAM0_SRAM, true); + esp_memprot_set_pms_lock(MEMPROT_DRAM0_SRAM); + esp_memprot_set_monitor_lock(MEMPROT_DRAM0_SRAM); } } } + +uint32_t esp_memprot_get_dram_status_reg_1() +{ + return memprot_ll_dram0_get_monitor_status_register_1(); +} + +uint32_t esp_memprot_get_dram_status_reg_2() +{ + return memprot_ll_dram0_get_monitor_status_register_2(); +} + +uint32_t esp_memprot_get_iram_status_reg() +{ + return memprot_ll_iram0_get_monitor_status_register(); +} + +uint32_t esp_memprot_get_monitor_enable_reg(mem_type_prot_t mem_type) +{ + switch (mem_type) { + case MEMPROT_IRAM0_SRAM: + return memprot_ll_iram0_get_monitor_enable_register(); + case MEMPROT_DRAM0_SRAM: + return memprot_ll_dram0_get_monitor_enable_register(); + default: + abort(); + } +} diff --git a/components/esp32s2/include/esp32s2/memprot.h b/components/esp32s2/include/esp32s2/memprot.h index e86ebbe351..c63fb395e6 100644 --- a/components/esp32s2/include/esp32s2/memprot.h +++ b/components/esp32s2/include/esp32s2/memprot.h @@ -26,6 +26,32 @@ extern "C" { #endif +//convenient constants for better code readabilty +#define RD_ENA true +#define RD_DIS false +#define WR_ENA true +#define WR_DIS false +#define EX_ENA true +#define EX_DIS false +#define RD_LOW_ENA true +#define RD_LOW_DIS false +#define WR_LOW_ENA true +#define WR_LOW_DIS false +#define EX_LOW_ENA true +#define EX_LOW_DIS false +#define RD_HIGH_ENA true +#define RD_HIGH_DIS false +#define WR_HIGH_ENA true +#define WR_HIGH_DIS false +#define EX_HIGH_ENA true +#define EX_HIGH_DIS false +#define PANIC_HNDL_ON true +#define PANIC_HNDL_OFF false +#define MEMPROT_LOCK true +#define MEMPROT_UNLOCK false +#define DEF_SPLIT_LINE NULL + +//memory range types typedef enum { MEMPROT_NONE = 0x00000000, MEMPROT_IRAM0_SRAM = 0x00000001, //0x40020000-0x4006FFFF, RWX diff --git a/components/esp32s2/ld/esp32s2.project.ld.in b/components/esp32s2/ld/esp32s2.project.ld.in index f0739115e5..248cb8c39e 100644 --- a/components/esp32s2/ld/esp32s2.project.ld.in +++ b/components/esp32s2/ld/esp32s2.project.ld.in @@ -85,7 +85,7 @@ SECTIONS and will be retained during deep sleep. User data marked with RTC_NOINIT_ATTR will be placed into this section. See the file "esp_attr.h" for more information. - The memory location of the data is dependent on + The memory location of the data is dependent on CONFIG_ESP32S2_RTCDATA_IN_FAST_MEM option. */ .rtc_noinit (NOLOAD): @@ -178,6 +178,8 @@ SECTIONS /* align + add 16B for CPU dummy speculative instr. fetch */ . = ALIGN(4) + 16; + /* iram_end_test section exists for use by memprot unit tests only */ + *(.iram_end_test) _iram_text_end = ABSOLUTE(.); _iram_end = ABSOLUTE(.); } > iram0_0_seg diff --git a/components/esp32s2/memprot.c b/components/esp32s2/memprot.c index b25f92da26..96ce98c8eb 100644 --- a/components/esp32s2/memprot.c +++ b/components/esp32s2/memprot.c @@ -694,25 +694,25 @@ void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t //set permissions if (required_mem_prot & MEMPROT_IRAM0_SRAM) { - esp_memprot_set_prot_iram(MEMPROT_IRAM0_SRAM, NULL, false, true, true, true, true, true); + esp_memprot_set_prot_iram(MEMPROT_IRAM0_SRAM, DEF_SPLIT_LINE, WR_LOW_DIS, RD_LOW_ENA, EX_LOW_ENA, WR_HIGH_DIS, RD_HIGH_DIS, EX_HIGH_DIS); } if (required_mem_prot & MEMPROT_IRAM0_RTCFAST) { - esp_memprot_set_prot_iram(MEMPROT_IRAM0_RTCFAST, NULL, false, true, true, true, true, true); + esp_memprot_set_prot_iram(MEMPROT_IRAM0_RTCFAST, DEF_SPLIT_LINE, WR_LOW_DIS, RD_LOW_ENA, EX_LOW_ENA, WR_HIGH_DIS, RD_HIGH_DIS, EX_HIGH_DIS); } if (required_mem_prot & MEMPROT_DRAM0_SRAM) { - esp_memprot_set_prot_dram(MEMPROT_DRAM0_SRAM, NULL, false, true, true, true); + esp_memprot_set_prot_dram(MEMPROT_DRAM0_SRAM, DEF_SPLIT_LINE, WR_LOW_DIS, RD_LOW_ENA, WR_HIGH_ENA, RD_HIGH_ENA); } if (required_mem_prot & MEMPROT_DRAM0_RTCFAST) { - esp_memprot_set_prot_dram(MEMPROT_DRAM0_RTCFAST, NULL, false, true, true, true); + esp_memprot_set_prot_dram(MEMPROT_DRAM0_RTCFAST, DEF_SPLIT_LINE, WR_LOW_DIS, RD_LOW_ENA, WR_HIGH_ENA, RD_HIGH_ENA); } if (required_mem_prot & MEMPROT_PERI1_RTCSLOW) { - esp_memprot_set_prot_peri1(MEMPROT_PERI1_RTCSLOW, NULL, true, true, true, true); + esp_memprot_set_prot_peri1(MEMPROT_PERI1_RTCSLOW, DEF_SPLIT_LINE, WR_LOW_DIS, RD_LOW_DIS, WR_HIGH_DIS, RD_HIGH_DIS); } if (required_mem_prot & MEMPROT_PERI2_RTCSLOW_0) { - esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_0, NULL, true, true, false, true, true, false); + esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_0, DEF_SPLIT_LINE, WR_LOW_ENA, RD_LOW_ENA, EX_LOW_DIS, WR_HIGH_ENA, RD_HIGH_ENA, EX_HIGH_DIS); } 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_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_1, DEF_SPLIT_LINE, WR_LOW_DIS, RD_LOW_DIS, EX_LOW_DIS, WR_HIGH_DIS, RD_HIGH_DIS, EX_HIGH_DIS); } //reenable protection (bus based) diff --git a/components/esp_system/port/arch/riscv/panic_arch.c b/components/esp_system/port/arch/riscv/panic_arch.c index 2d9ad55c08..2ae38dea6b 100644 --- a/components/esp_system/port/arch/riscv/panic_arch.c +++ b/components/esp_system/port/arch/riscv/panic_arch.c @@ -151,27 +151,27 @@ static inline void print_cache_err_details(const void *frame) * explanation of why the panic occured. */ #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE -static inline void print_memprot_err_details(const void *frame) +static inline void print_memprot_err_details(const void *frame __attribute__((unused))) { //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_str( esp_memprot_mem_type_to_str(mem_type) ); + panic_print_str( "\r\n faulting address: 0x"); 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) ); + panic_print_str( "\r\n world:"); + panic_print_dec( 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 ) { + if ( esp_memprot_get_violate_loadstore(mem_type) ) { operation = 'X'; } } // W/R - common if ( operation == 0 ) { - operation = esp_memprot_get_violate_wr(mem_type) == 1 ? 'W' : 'R'; + operation = esp_memprot_get_violate_wr(mem_type) == MEMPROT_PMS_OP_WRITE ? 'W' : 'R'; } panic_print_str( "\r\n operation type: "); panic_print_char( operation ); diff --git a/components/hal/esp32c3/include/hal/memprot_ll.h b/components/hal/esp32c3/include/hal/memprot_ll.h index 127d51b307..5da2b452d3 100644 --- a/components/hal/esp32c3/include/hal/memprot_ll.h +++ b/components/hal/esp32c3/include/hal/memprot_ll.h @@ -15,21 +15,19 @@ #pragma once #include "soc/sensitive_reg.h" +#include "soc/cache_memory.h" #ifdef __cplusplus extern "C" { #endif -/** - * === globals ==== +/* ****************************************************************************************************** + * *** GLOBALS *** + * NOTE: in this version, all the configurations apply only to WORLD_0 */ -#ifndef SRAM_IRAM_START -#define SRAM_IRAM_START 0x4037C000 -#endif -#ifndef SRAM_DRAM_START -#define SRAM_DRAM_START 0x3FC7C000 -#endif +#define IRAM_SRAM_START 0x4037C000 +#define DRAM_SRAM_START 0x3FC7C000 /* ICache size is fixed to 16KB on ESP32-C3 */ #ifndef ICACHE_SIZE @@ -40,36 +38,12 @@ extern "C" { #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 I_D_FAULT_ADDR_SHIFT 0x2 -#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) +static inline void memprot_ll_set_iram0_dram0_split_line_lock(void) { - REG_WRITE(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_0_REG, lock ? 1 : 0); + REG_WRITE(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_0_REG, 1); } static inline bool memprot_ll_get_iram0_dram0_split_line_lock(void) @@ -77,12 +51,19 @@ 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; } +static inline void* memprot_ll_get_split_addr_from_reg(uint32_t regval, uint32_t base) +{ + return (void*) + (base + ((regval & SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_M) + >> (SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SRAM_SPLITADDR_S - I_D_SPLIT_LINE_SHIFT))); +} -/** - * === IRAM0 ==== +/* ****************************************************************************************************** + * *** IRAM0 *** */ + //16kB (CACHE) -#define IRAM0_SRAM_LEVEL_0_LOW SRAM_IRAM_START //0x40370000 +#define IRAM0_SRAM_LEVEL_0_LOW IRAM_SRAM_START //0x40370000 #define IRAM0_SRAM_LEVEL_0_HIGH (IRAM0_SRAM_LEVEL_0_LOW + ICACHE_SIZE - 0x1) //0x4037FFFF //128kB (LEVEL 1) @@ -107,7 +88,10 @@ static inline uint32_t memprot_ll_iram0_get_intr_source_num(void) return ETS_CORE0_IRAM0_PMS_INTR_SOURCE; } -/* SPLIT LINE */ + +/////////////////////////////////// +// IRAM0 - SPLIT LINES +/////////////////////////////////// static inline void memprot_ll_set_iram0_split_line(const void *line_addr, uint32_t sensitive_reg) { @@ -125,7 +109,7 @@ static inline void memprot_ll_set_iram0_split_line(const void *line_addr, uint32 category[2] = 0x2; } - //category bits are the same for all areas + //NOTE: category & split line address bits are the same for all the 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) | @@ -154,12 +138,30 @@ 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) +static inline void* memprot_ll_get_iram0_split_line_main_I_D(void) { - REG_WRITE(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG, lock ? 1 : 0); + return memprot_ll_get_split_addr_from_reg(REG_READ(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_1_REG), SOC_DIRAM_IRAM_LOW); +} + +static inline void* memprot_ll_get_iram0_split_line_I_0(void) +{ + return memprot_ll_get_split_addr_from_reg(REG_READ(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_2_REG), SOC_DIRAM_IRAM_LOW); +} + +static inline void* memprot_ll_get_iram0_split_line_I_1(void) +{ + return memprot_ll_get_split_addr_from_reg(REG_READ(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_3_REG), SOC_DIRAM_IRAM_LOW); +} + + +/////////////////////////////////// +// IRAM0 - PMS CONFIGURATION +/////////////////////////////////// + +// lock +static inline void memprot_ll_iram0_set_pms_lock(void) +{ + REG_WRITE(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG, 1); } static inline bool memprot_ll_iram0_get_pms_lock(void) @@ -167,7 +169,7 @@ 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 +// permission settings static inline uint32_t memprot_ll_iram0_set_permissions(bool r, bool w, bool x) { uint32_t permissions = 0; @@ -204,11 +206,46 @@ 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) +static inline void memprot_ll_iram0_get_permissions(uint32_t perms, bool *r, bool *w, bool *x) { - REG_WRITE(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG, lock ? 1 : 0); + *r = perms & SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R; + *w = perms & SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W; + *x = perms & SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_F; +} + +static inline void memprot_ll_iram0_get_pms_area_0(bool *r, bool *w, bool *x) +{ + uint32_t permissions = REG_GET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_0); + memprot_ll_iram0_get_permissions( permissions, r, w, x); +} + +static inline void memprot_ll_iram0_get_pms_area_1(bool *r, bool *w, bool *x) +{ + uint32_t permissions = REG_GET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_1); + memprot_ll_iram0_get_permissions( permissions, r, w, x); +} + +static inline void memprot_ll_iram0_get_pms_area_2(bool *r, bool *w, bool *x) +{ + uint32_t permissions = REG_GET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_2); + memprot_ll_iram0_get_permissions( permissions, r, w, x); +} + +static inline void memprot_ll_iram0_get_pms_area_3(bool *r, bool *w, bool *x) +{ + uint32_t permissions = REG_GET_FIELD(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_2_REG, SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_3); + memprot_ll_iram0_get_permissions( permissions, r, w, x); +} + + +/////////////////////////////////// +// IRAM0 - MONITOR +/////////////////////////////////// + +// lock +static inline void memprot_ll_iram0_set_monitor_lock(void) +{ + REG_WRITE(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG, 1); } static inline bool memprot_ll_iram0_get_monitor_lock(void) @@ -216,6 +253,7 @@ static inline bool memprot_ll_iram0_get_monitor_lock(void) return REG_READ(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG) == 1; } +// interrupt enable/clear static inline void memprot_ll_iram0_set_monitor_en(bool enable) { if ( enable ) { @@ -227,27 +265,38 @@ static inline void memprot_ll_iram0_set_monitor_en(bool enable) 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; + return REG_GET_FIELD( 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_SET_BIT( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_CLR ); +} + +static inline void memprot_ll_iram0_reset_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_enable_register(void) +{ + return REG_READ(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_1_REG); +} + +// // permission violation status 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 ); + return REG_GET_FIELD( 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 ); + return REG_GET_FIELD( 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 ); + return REG_GET_FIELD( 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) @@ -257,16 +306,22 @@ static inline uint32_t memprot_ll_iram0_get_monitor_status_fault_world(void) 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 ); + uint32_t addr = REG_GET_FIELD( SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_VIOLATE_STATUS_ADDR ); + return addr > 0 ? (addr << I_D_FAULT_ADDR_SHIFT) + IRAM0_ADDRESS_LOW : 0; +} + +static inline uint32_t memprot_ll_iram0_get_monitor_status_register(void) +{ + return REG_READ(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_2_REG); } -/** - * === DRAM0 ==== +/* ****************************************************************************************************** + * *** DRAM0 *** */ -//cache not available from DRAM -#define DRAM0_SRAM_LEVEL_0_LOW SRAM_DRAM_START //0x3FC7C000 +//cache not available from DRAM (!) +#define DRAM0_SRAM_LEVEL_0_LOW DRAM_SRAM_START //0x3FC7C000 #define DRAM0_SRAM_LEVEL_0_HIGH (DRAM0_SRAM_LEVEL_0_LOW + ICACHE_SIZE - 0x1) //0x3FC7FFFF //128kB @@ -291,7 +346,9 @@ static inline uint32_t memprot_ll_dram0_get_intr_source_num(void) } -/* SPLIT LINE */ +/////////////////////////////////// +// DRAM0 - SPLIT LINES +/////////////////////////////////// static inline void memprot_ll_set_dram0_split_line(const void *line_addr, uint32_t sensitive_reg) { @@ -309,7 +366,7 @@ static inline void memprot_ll_set_dram0_split_line(const void *line_addr, uint32 category[2] = 0x2; } - //category bits are the same for all areas + //NOTE: line address & category bits, shifts and masks are the same for all the 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) | @@ -332,12 +389,25 @@ 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) +static inline void* memprot_ll_get_dram0_split_line_D_0(void) { - REG_WRITE(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG, lock ? 1 : 0); + return memprot_ll_get_split_addr_from_reg(REG_READ(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_2_REG), SOC_DIRAM_DRAM_LOW); +} + +static inline void* memprot_ll_get_dram0_split_line_D_1(void) +{ + return memprot_ll_get_split_addr_from_reg(REG_READ(SENSITIVE_CORE_X_IRAM0_DRAM0_DMA_SPLIT_LINE_CONSTRAIN_3_REG), SOC_DIRAM_DRAM_LOW); +} + + +/////////////////////////////////// +// DRAM0 - PMS CONFIGURATION +/////////////////////////////////// + +// lock +static inline void memprot_ll_dram0_set_pms_lock(void) +{ + REG_WRITE(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG, 1); } static inline bool memprot_ll_dram0_get_pms_lock(void) @@ -345,6 +415,7 @@ static inline bool memprot_ll_dram0_get_pms_lock(void) return REG_READ(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG) == 1; } +// permission settings static inline uint32_t memprot_ll_dram0_set_permissions(bool r, bool w) { uint32_t permissions = 0; @@ -378,12 +449,44 @@ 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) +static inline void memprot_ll_dram0_get_permissions(uint32_t perms, bool *r, bool *w ) { - REG_WRITE(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG, lock ? 1 : 0); + *r = perms & SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R; + *w = perms & SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W; +} + +static inline void memprot_ll_dram0_get_pms_area_0(bool *r, bool *w) +{ + uint32_t permissions = REG_GET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_0); + memprot_ll_dram0_get_permissions( permissions, r, w); +} + +static inline void memprot_ll_dram0_get_pms_area_1(bool *r, bool *w) +{ + uint32_t permissions = REG_GET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_1); + memprot_ll_dram0_get_permissions( permissions, r, w); +} + +static inline void memprot_ll_dram0_get_pms_area_2(bool *r, bool *w) +{ + uint32_t permissions = REG_GET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_2); + memprot_ll_dram0_get_permissions( permissions, r, w); +} + +static inline void memprot_ll_dram0_get_pms_area_3(bool *r, bool *w) +{ + uint32_t permissions = REG_GET_FIELD(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_1_REG, SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_PMS_3); + memprot_ll_dram0_get_permissions( permissions, r, w); +} + +/////////////////////////////////// +// DRAM0 - MONITOR +/////////////////////////////////// + +// lock +static inline void memprot_ll_dram0_set_monitor_lock(void) +{ + REG_WRITE(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG, 1); } static inline bool memprot_ll_dram0_get_monitor_lock(void) @@ -391,6 +494,7 @@ static inline bool memprot_ll_dram0_get_monitor_lock(void) return REG_READ(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG) == 1; } +// interrupt enable/clear static inline void memprot_ll_dram0_set_monitor_en(bool enable) { if ( enable ) { @@ -406,18 +510,29 @@ static inline bool memprot_ll_dram0_get_monitor_en(void) } static inline void memprot_ll_dram0_clear_monitor_intr(void) +{ + REG_SET_BIT( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_CLR ); +} + +static inline void memprot_ll_dram0_reset_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_enable_register(void) +{ + return REG_READ(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_1_REG); +} + +// permission violation status 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 ); + return REG_GET_FIELD( 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 ); + return REG_GET_FIELD( 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) @@ -427,19 +542,29 @@ static inline uint32_t memprot_ll_dram0_get_monitor_status_fault_world(void) 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 ); + uint32_t addr = REG_GET_FIELD( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_ADDR ); + return addr > 0 ? (addr << I_D_FAULT_ADDR_SHIFT) + DRAM0_ADDRESS_LOW : 0; } 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 ); + return REG_GET_FIELD( 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 ); + return REG_GET_FIELD( SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG, SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_VIOLATE_STATUS_BYTEEN ); } +static inline uint32_t memprot_ll_dram0_get_monitor_status_register_1(void) +{ + return REG_READ(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_2_REG); +} + +static inline uint32_t memprot_ll_dram0_get_monitor_status_register_2(void) +{ + return REG_READ(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_3_REG); +} #ifdef __cplusplus } diff --git a/components/hal/esp32s2/include/hal/memprot_ll.h b/components/hal/esp32s2/include/hal/memprot_ll.h index ee7ea2a068..0fbf575337 100644 --- a/components/hal/esp32s2/include/hal/memprot_ll.h +++ b/components/hal/esp32s2/include/hal/memprot_ll.h @@ -26,10 +26,12 @@ extern "C" { //IRAM0 interrupt status bitmasks #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 CONF_REG_ADDRESS_SHIFT 2 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); + DPORT_CLEAR_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) @@ -104,6 +106,7 @@ static inline uint32_t esp_memprot_iram0_get_lock_bit(void) * === IRAM0 SRAM * ======================================================================================== */ +#define IRAM0_SRAM_BASE_ADDRESS 0x40000000 #define IRAM0_SRAM_ADDRESS_LOW 0x40020000 #define IRAM0_SRAM_ADDRESS_HIGH 0x4006FFFF @@ -126,6 +129,7 @@ static inline uint32_t esp_memprot_iram0_get_lock_bit(void) #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 +#define IRAM0_SRAM_ADDR_TO_CONF_REG(addr) (((addr >> CONF_REG_ADDRESS_SHIFT) & DPORT_PMS_PRO_IRAM0_SRAM_4_SPLTADDR) << DPORT_PMS_PRO_IRAM0_SRAM_4_SPLTADDR_S) static inline uint32_t *esp_memprot_iram0_sram_get_fault_address(void) { @@ -290,6 +294,7 @@ static inline void esp_memprot_iram0_sram_set_prot(uint32_t *split_addr, bool lw { uint32_t addr = (uint32_t)split_addr; assert(addr <= IRAM0_SRAM_SPL_BLOCK_HIGH); + assert(addr % 0x4 == 0); //find possible split.address in low region blocks int uni_blocks_low = -1; @@ -339,11 +344,7 @@ static inline void esp_memprot_iram0_sram_set_prot(uint32_t *split_addr, bool lw uint32_t reg_split_addr = 0; if (addr >= IRAM0_SRAM_SPL_BLOCK_LOW) { - - //[16:0] - reg_split_addr = addr >> 2; - assert(addr == (reg_split_addr << 2)); - reg_split_addr &= DPORT_PMS_PRO_IRAM0_SRAM_4_SPLTADDR_M; + reg_split_addr = IRAM0_SRAM_ADDR_TO_CONF_REG( addr ); //cfg reg - [16:0] } //prepare high & low permission mask (bits: [22:20] high range, [19:17] low range) @@ -406,9 +407,11 @@ static inline void esp_memprot_iram0_sram_set_exec_perm(bool lx, bool hx) * === 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 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 IRAM0_RTCFAST_ADDR_TO_CONF_REG(addr) (((addr >> CONF_REG_ADDRESS_SHIFT) & DPORT_PMS_PRO_IRAM0_RTCFAST_SPLTADDR) << DPORT_PMS_PRO_IRAM0_RTCFAST_SPLTADDR_S) static inline uint32_t *esp_memprot_iram0_rtcfast_get_fault_address(void) @@ -434,14 +437,10 @@ static inline uint32_t esp_memprot_iram0_rtcfast_get_perm_split_reg(void) 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; + assert( addr % 0x4 == 0 ); - //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; + //conf reg [10:0] + uint32_t reg_split_addr = IRAM0_RTCFAST_ADDR_TO_CONF_REG(addr); //prepare high & low permission mask (bits: [16:14] high range, [13:11] low range) uint32_t permission_mask = 0; @@ -531,6 +530,7 @@ static inline bool esp_memprot_dram0_is_assoc_intr(void) static inline void esp_memprot_dram0_clear_intr(void) { DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_CLR); + DPORT_CLEAR_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_CLR); } static inline uint32_t esp_memprot_dram0_get_intr_ena_bit(void) @@ -606,6 +606,8 @@ static inline void esp_memprot_dram0_get_fault_op_type(uint32_t *op_type, uint32 #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 +#define DRAM0_SRAM_ADDR_TO_CONF_REG(addr) (((addr >> CONF_REG_ADDRESS_SHIFT) & DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR) << DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_S) + static inline uint32_t *esp_memprot_dram0_sram_get_fault_address(void) { @@ -716,6 +718,7 @@ static inline void esp_memprot_dram0_sram_set_prot(uint32_t *split_addr, bool lw //low boundary check provided by LD script. see comment in esp_memprot_iram0_sram_set_prot() assert( addr <= DRAM0_SRAM_SPL_BLOCK_HIGH ); + assert( addr % 0x4 == 0 ); //set low region int uni_blocks_low = -1; @@ -753,10 +756,8 @@ static inline void esp_memprot_dram0_sram_set_prot(uint32_t *split_addr, bool lw } } - //[24:8] - uint32_t reg_split_addr = addr >> 2; - assert(addr == (reg_split_addr << 2)); - reg_split_addr = (reg_split_addr & DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_V) << DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_S; + //conf reg [24:8] + uint32_t reg_split_addr = DRAM0_SRAM_ADDR_TO_CONF_REG(addr); //prepare high & low permission mask uint32_t permission_mask = 0; @@ -803,9 +804,10 @@ static inline void esp_memprot_dram0_sram_set_write_perm(bool lw, bool hw) * === 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 +#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 +#define DRAM0_RTCFAST_ADDR_TO_CONF_REG(addr) (((addr >> CONF_REG_ADDRESS_SHIFT) & DPORT_PMS_PRO_DRAM0_RTCFAST_SPLTADDR) << DPORT_PMS_PRO_DRAM0_RTCFAST_SPLTADDR_S) static inline uint32_t *esp_memprot_dram0_rtcfast_get_fault_address(void) @@ -826,11 +828,10 @@ static inline bool esp_memprot_dram0_rtcfast_is_intr_mine(void) 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; + assert( addr % 0x4 == 0 ); - //[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; + //conf reg [10:0] + uint32_t reg_split_addr = DRAM0_RTCFAST_ADDR_TO_CONF_REG( addr ); //prepare high & low permission mask uint32_t permission_mask = 0; diff --git a/components/hal/esp32s2/include/hal/memprot_peri_ll.h b/components/hal/esp32s2/include/hal/memprot_peri_ll.h index 35dc03cefc..f8abd751c6 100644 --- a/components/hal/esp32s2/include/hal/memprot_peri_ll.h +++ b/components/hal/esp32s2/include/hal/memprot_peri_ll.h @@ -31,9 +31,11 @@ extern "C" { #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); + DPORT_CLEAR_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) @@ -116,6 +118,7 @@ static inline uint32_t esp_memprot_peri1_get_lock_bit(void) #define PERI1_RTCSLOW_ADDRESS_HIGH PERI1_RTCSLOW_ADDRESS_LOW + RTCSLOW_MEMORY_SIZE #define PERI1_RTCSLOW_INTR_ST_FAULTADDR_HI_0 0x3F400000 +#define PERI1_RTCSLOW_ADDR_TO_CONF_REG(addr) (((addr >> CONF_REG_ADDRESS_SHIFT) & DPORT_PMS_PRO_DPORT_RTCSLOW_SPLTADDR) << DPORT_PMS_PRO_DPORT_RTCSLOW_SPLTADDR_S) static inline uint32_t *esp_memprot_peri1_rtcslow_get_fault_address(void) { @@ -137,11 +140,9 @@ static inline bool esp_memprot_peri1_rtcslow_is_intr_mine(void) 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; + assert( addr % 0x4 == 0 ); - //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; + uint32_t reg_split_addr = PERI1_RTCSLOW_ADDR_TO_CONF_REG(addr); //prepare high & low permission mask uint32_t permission_mask = 0; @@ -201,6 +202,7 @@ static inline uint32_t esp_memprot_peri1_rtcslow_get_conf_reg(void) 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); + DPORT_CLEAR_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) @@ -286,6 +288,8 @@ static inline uint32_t *esp_memprot_peri2_rtcslow_get_fault_address(void) #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 +#define PERI2_RTCSLOW_0_ADDR_TO_CONF_REG(addr) (((addr >> CONF_REG_ADDRESS_SHIFT) & DPORT_PMS_PRO_AHB_RTCSLOW_0_SPLTADDR) << DPORT_PMS_PRO_AHB_RTCSLOW_0_SPLTADDR_S) + static inline bool esp_memprot_peri2_rtcslow_0_is_intr_mine(void) { if (esp_memprot_peri2_is_assoc_intr()) { @@ -298,11 +302,9 @@ static inline bool esp_memprot_peri2_rtcslow_0_is_intr_mine(void) 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; + assert( addr % 0x4 == 0 ); - //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; + uint32_t reg_split_addr = PERI2_RTCSLOW_0_ADDR_TO_CONF_REG(addr); //prepare high & low permission mask uint32_t permission_mask = 0; @@ -371,6 +373,7 @@ static inline uint32_t esp_memprot_peri2_rtcslow_0_get_conf_reg(void) #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 +#define PERI2_RTCSLOW_1_ADDR_TO_CONF_REG(addr) (((addr >> CONF_REG_ADDRESS_SHIFT) & DPORT_PMS_PRO_AHB_RTCSLOW_1_SPLTADDR) << DPORT_PMS_PRO_AHB_RTCSLOW_1_SPLTADDR_S) static inline bool esp_memprot_peri2_rtcslow_1_is_intr_mine(void) { @@ -384,11 +387,9 @@ static inline bool esp_memprot_peri2_rtcslow_1_is_intr_mine(void) 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; + assert( addr % 0x4 == 0 ); - //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; + uint32_t reg_split_addr = PERI2_RTCSLOW_1_ADDR_TO_CONF_REG(addr); //prepare high & low permission mask uint32_t permission_mask = 0; diff --git a/tools/test_apps/system/memprot/CMakeLists.txt b/tools/test_apps/system/memprot/CMakeLists.txt index 2d649a57e8..c1fbe08208 100644 --- a/tools/test_apps/system/memprot/CMakeLists.txt +++ b/tools/test_apps/system/memprot/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) -if(IDF_TARGET STREQUAL "esp32s2") +if((IDF_TARGET STREQUAL "esp32s2") OR (IDF_TARGET STREQUAL "esp32c3")) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(test_memprot) diff --git a/tools/test_apps/system/memprot/README.md b/tools/test_apps/system/memprot/README.md index 5d650cc9d3..98655f12ea 100644 --- a/tools/test_apps/system/memprot/README.md +++ b/tools/test_apps/system/memprot/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-S2 | -| ----------------- | -------- | +| Supported Targets | ESP32-S2 | ESP32-C3 | +| ----------------- | -------- | -------- | diff --git a/tools/test_apps/system/memprot/app_test.py b/tools/test_apps/system/memprot/app_test.py index 42e731db9f..9a4e3fd3e2 100644 --- a/tools/test_apps/system/memprot/app_test.py +++ b/tools/test_apps/system/memprot/app_test.py @@ -3,7 +3,7 @@ import ttfw_idf from tiny_test_fw import Utility -mem_test = [ +MEM_TEST_S2 = [ ['IRAM0_SRAM', 'WRX'], ['IRAM0_RTCFAST', 'WRX'], ['DRAM0_SRAM', 'WR'], @@ -13,14 +13,29 @@ mem_test = [ ['PERI2_RTCSLOW_1', 'WRX'] ] +MEM_TEST_C3 = [ + ['IRAM0_SRAM', 'WRX'], + ['DRAM0_SRAM', 'WR'] +] -@ttfw_idf.idf_custom_test(env_tag='Example_GENERIC', target='esp32s2', group='test-apps') + +@ttfw_idf.idf_custom_test(env_tag='Example_GENERIC', target=['esp32c3', '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: + mem_test_cfg = [] + current_target = dut.app.get_sdkconfig()['CONFIG_IDF_TARGET'].replace('"','').lower() + + if current_target == 'esp32c3': + mem_test_cfg = MEM_TEST_C3 + elif current_target == 'esp32s2': + mem_test_cfg = MEM_TEST_S2 + + Utility.console_log('Test cfg: ' + current_target) + + for i in mem_test_cfg: if 'R' in i[1]: dut.expect(i[0] + ' read low: OK') dut.expect(i[0] + ' read high: OK') diff --git a/tools/test_apps/system/memprot/main/CMakeLists.txt b/tools/test_apps/system/memprot/main/CMakeLists.txt index 1d663d917b..3b4a00a98b 100644 --- a/tools/test_apps/system/memprot/main/CMakeLists.txt +++ b/tools/test_apps/system/memprot/main/CMakeLists.txt @@ -1,2 +1,7 @@ -idf_component_register(SRCS "test_memprot_main.c" "test_panic.c" +if( IDF_TARGET STREQUAL "esp32s2" ) + idf_component_register(SRCS "esp32s2/test_memprot_main.c" "esp32s2/test_panic.c" INCLUDE_DIRS "") +elseif( IDF_TARGET STREQUAL "esp32c3" ) + idf_component_register(SRCS "esp32c3/test_memprot_main.c" "esp32c3/test_panic.c" "esp32c3/return_from_panic.S" + INCLUDE_DIRS "") +endif() diff --git a/tools/test_apps/system/memprot/main/Kconfig.projbuild b/tools/test_apps/system/memprot/main/Kconfig.projbuild new file mode 100644 index 0000000000..e12919cc1e --- /dev/null +++ b/tools/test_apps/system/memprot/main/Kconfig.projbuild @@ -0,0 +1,4 @@ +config ESP_SYSTEM_MEMPROT_IRAM_TESTBUF + bool + default y if IDF_TARGET_ESP32C3 + default n if !IDF_TARGET_ESP32C3 diff --git a/tools/test_apps/system/memprot/main/esp32c3/return_from_panic.S b/tools/test_apps/system/memprot/main/esp32c3/return_from_panic.S new file mode 100644 index 0000000000..3884073046 --- /dev/null +++ b/tools/test_apps/system/memprot/main/esp32c3/return_from_panic.S @@ -0,0 +1,71 @@ +// Copyright 2021 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 "riscv/rvruntime-frames.h" + +/* The riscv panic handler in components/riscv/vectors.S doesn't allow the panic + handler function to return. + + However, for the purposes of this test we want to allow the panic handler to return. + + There is functionality in vectors.S restore the CPU state, but it only + restores when CONTEXT_SIZE registers are + pushed onto the stack not RV_STK_FRMSZ registers + + Instead of messing with that, implement a full "restore from RvExcFrame" + function here which restores the CPU and then + returns from exception. + + Called as return_from_panic_handler(RvExcFrame *frame) +*/ +.global return_from_panic_handler +return_from_panic_handler: + or t0, a0, a0 /* use t0 as the working register */ + + /* save general registers */ + lw ra, RV_STK_RA(t0) + lw sp, RV_STK_SP(t0) + lw gp, RV_STK_GP(t0) + lw tp, RV_STK_TP(t0) + lw s0, RV_STK_S0(t0) + lw s1, RV_STK_S1(t0) + lw a0, RV_STK_A0(t0) + lw a1, RV_STK_A1(t0) + lw a2, RV_STK_A2(t0) + lw a3, RV_STK_A3(t0) + lw a4, RV_STK_A4(t0) + lw a5, RV_STK_A5(t0) + lw a6, RV_STK_A6(t0) + lw a7, RV_STK_A7(t0) + lw s2, RV_STK_S2(t0) + lw s3, RV_STK_S3(t0) + lw s4, RV_STK_S4(t0) + lw s5, RV_STK_S5(t0) + lw s6, RV_STK_S6(t0) + lw s7, RV_STK_S7(t0) + lw s8, RV_STK_S8(t0) + lw s9, RV_STK_S9(t0) + lw s10, RV_STK_S10(t0) + lw s11, RV_STK_S11(t0) + lw t3, RV_STK_T3(t0) + lw t4, RV_STK_T4(t0) + lw t5, RV_STK_T5(t0) + lw t6, RV_STK_T6(t0) + + lw t2, RV_STK_MEPC(t0) + csrw mepc, t2 + + lw t1, RV_STK_T1(t0) + lw t2, RV_STK_T2(t0) + lw t0, RV_STK_T0(t0) + mret diff --git a/tools/test_apps/system/memprot/main/esp32c3/test_memprot_main.c b/tools/test_apps/system/memprot/main/esp32c3/test_memprot_main.c new file mode 100644 index 0000000000..817e13680a --- /dev/null +++ b/tools/test_apps/system/memprot/main/esp32c3/test_memprot_main.c @@ -0,0 +1,392 @@ +/* MEMPROT (PMS) testing code */ +#include +#include "sdkconfig.h" +#include "esp32c3/memprot.h" +#include "esp_rom_sys.h" +#include + +/** + * ESP32C3 MEMORY PROTECTION MODULE TEST + * ===================================== + * + * In order to safely test all the memprot features, this test application uses memprot default settings + * plus proprietary testing buffers: + * - iram_test_buffer (.iram_end_test, 1kB) - all low region operations + * - dram_test_buffer (.dram0.data, 1kB) - all high region operations + * Testing addresses are set to the middle of the testing buffers: + * - test_ptr_low = iram_test_buffer + 0x200 + * - test_ptr_high = dram_test_buffer + 0x200 + * Each operation is tested at both low & high region addresses. + * Each test result checked against expected status of PMS violation interrupt status and + * against expected value stored in the memory tested (where applicable) + * + * Testing scheme is depicted below: + * + * DRam0/DMA IRam0 + * ----------------------------------------------- + * | IRam0_PMS_0 = IRam0_PMS_1 = IRam0_PMS_2 | + * | DRam0_PMS_0 | + * | | + * | | + * | - - - - - - - iram_test_buffer - - - - - - -| IRam0_line1_Split_addr + * DRam0_DMA_line0_Split_addr | -- test_ptr_low -- | = + * = =============================================== IRam0_line0_Split_addr + * DRam0_DMA_line1_Split_addr | | = + * | - - - - - - - dram_test_buffer - - - - - - -| IRam0_DRam0_Split_addr (main I/D) + * | -- test_ptr_high -- | + * | - - - - - - - - - - - - - - - - - - - - - - | + * | | + * | DRam0_PMS_1 = DRam0_PMS_2 = DRam0_PMS_3 | + * | IRam0_PMS_3 | + * ----------------------------------------------- + * + * For more details on PMS memprot settings see 'esp_memprot_set_prot_int' function in esp32c3/memprot.h + */ + + +/* Binary code for the following asm [int func(int x) { return x+x; }] + slli a0,a0,0x1 + ret + */ +static uint8_t fnc_buff[] = { 0x06, 0x05, 0x82, 0x80 }; +typedef int (*fnc_ptr)(int); + +#define SRAM_TEST_BUFFER_SIZE 0x400 +#define SRAM_TEST_OFFSET 0x200 + +static uint8_t __attribute__((section(".iram_end_test"))) iram_test_buffer[SRAM_TEST_BUFFER_SIZE] = {0}; +static uint8_t dram_test_buffer[SRAM_TEST_BUFFER_SIZE] = {0}; +extern volatile bool g_override_illegal_instruction; + + +static void *test_memprot_addr_low(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return (void*)((uint32_t)iram_test_buffer + SRAM_TEST_OFFSET); + case MEMPROT_DRAM0_SRAM: + return (void*)MAP_IRAM_TO_DRAM((uint32_t)iram_test_buffer + SRAM_TEST_OFFSET); + default: + abort(); + } +} + +static void *test_memprot_addr_high(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return (void*)MAP_DRAM_TO_IRAM((uint32_t)dram_test_buffer + SRAM_TEST_OFFSET); + case MEMPROT_DRAM0_SRAM: + return (void*)((uint32_t)dram_test_buffer + SRAM_TEST_OFFSET); + default: + abort(); + } +} + +static void __attribute__((unused)) dump_status_register(mem_type_prot_t 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) ) { + operation = 'X'; + } + } + + // W/R - common + if ( operation == 0 ) { + operation = esp_memprot_get_violate_wr(mem_type) == MEMPROT_PMS_OP_WRITE ? 'W' : 'R'; + } + + esp_rom_printf( + " FAULT [ world: %u, fault addr: 0x%08X, operation: %c", + esp_memprot_get_violate_world(mem_type), + esp_memprot_get_violate_addr(mem_type), + operation + ); + + // DRAM/DMA fault: check byte-enables + if ( mem_type == MEMPROT_DRAM0_SRAM ) { + esp_rom_printf( ", byte en: 0x%08X", esp_memprot_get_violate_byte_en(mem_type) ); + } + + esp_rom_printf( " ]\n" ); +} + +static void check_test_result(mem_type_prot_t mem_type, bool expected_status) +{ + bool test_result = + expected_status ? + !esp_memprot_get_violate_intr_on(mem_type) : + esp_memprot_get_violate_intr_on(mem_type); + + if ( test_result ) { + esp_rom_printf("OK\n"); + } else { + dump_status_register(mem_type); + } +} + +static void test_memprot_get_permissions(bool low, mem_type_prot_t mem_type, bool *read, bool *write, bool *exec ) +{ + bool _r, _w, _x; + pms_area_t area = MEMPROT_PMS_AREA_NONE; + + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + area = low ? MEMPROT_IRAM0_PMS_AREA_2 : MEMPROT_IRAM0_PMS_AREA_3; + esp_memprot_iram_get_pms_area(area, &_r, &_w, &_x); + break; + case MEMPROT_DRAM0_SRAM: + area = low ? MEMPROT_DRAM0_PMS_AREA_0 : MEMPROT_DRAM0_PMS_AREA_1; + esp_memprot_dram_get_pms_area(area, &_r, &_w); + break; + default: + abort(); + } + + if ( read ) { + *read = _r; + } + if ( write ) { + *write = _w; + } + if ( exec ) { + *exec = _x; + } +} + +static void test_memprot_set_permissions(bool low, mem_type_prot_t mem_type, bool read, bool write, bool *exec) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: { + bool _ex; + if (!exec) { + test_memprot_get_permissions( low, mem_type, NULL, NULL, &_ex); + exec = &_ex; + } + if (low) { + esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_0, read, write, *exec); + esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_1, read, write, *exec); + esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_2, read, write, *exec); + } else { + esp_memprot_iram_set_pms_area(MEMPROT_IRAM0_PMS_AREA_3, read, write, *exec); + } + } + break; + case MEMPROT_DRAM0_SRAM: { + if (low) { + esp_memprot_dram_set_pms_area( MEMPROT_DRAM0_PMS_AREA_0, read, write ); + } else { + esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_1, read, write); + esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_2, read, write); + esp_memprot_dram_set_pms_area(MEMPROT_DRAM0_PMS_AREA_3, read, write); + } + } + break; + default: + abort(); + } +} + +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, exec_perm_low, exec_perm_high; + test_memprot_get_permissions(true, mem_type, &read_perm_low, &write_perm_low, mem_type == MEMPROT_IRAM0_SRAM ? &exec_perm_low : NULL); + test_memprot_get_permissions(false, mem_type, &read_perm_high, &write_perm_high, mem_type == MEMPROT_IRAM0_SRAM ? &exec_perm_high : NULL); + + //get testing pointers for low & high regions + volatile uint32_t *ptr_low = test_memprot_addr_low(mem_type); + volatile uint32_t *ptr_high = test_memprot_addr_high(mem_type); + const uint32_t test_val = 100; + + //temporarily allow WRITE for setting the test values + esp_memprot_set_monitor_en(mem_type, false); + test_memprot_set_permissions(true, mem_type, read_perm_low, true, mem_type == MEMPROT_IRAM0_SRAM ? &exec_perm_low : NULL); + test_memprot_set_permissions(false, mem_type, read_perm_high, true, mem_type == MEMPROT_IRAM0_SRAM ? &exec_perm_high : NULL); + + *ptr_low = test_val; + *ptr_high = test_val + 1; + + test_memprot_set_permissions(true, mem_type, read_perm_low, write_perm_low, mem_type == MEMPROT_IRAM0_SRAM ? &exec_perm_low : NULL); + test_memprot_set_permissions(false, mem_type, read_perm_high, write_perm_high, mem_type == MEMPROT_IRAM0_SRAM ? &exec_perm_high : NULL); + esp_memprot_set_monitor_en(mem_type, true); + + //perform READ test in low region + esp_rom_printf("%s read low: ", esp_memprot_mem_type_to_str(mem_type)); + esp_memprot_monitor_clear_intr(mem_type); + + volatile uint32_t val = *ptr_low; + + if ( read_perm_low && val != test_val ) { + esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val ); + dump_status_register(mem_type); + } else { + check_test_result(mem_type, read_perm_low); + } + + //perform READ in high region + esp_rom_printf("%s read high: ", esp_memprot_mem_type_to_str(mem_type)); + esp_memprot_monitor_clear_intr(mem_type); + + val = *ptr_high; + + if ( read_perm_high && val != (test_val + 1) ) { + esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); + dump_status_register(mem_type); + } else { + check_test_result(mem_type, read_perm_high); + } +} + +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; + test_memprot_get_permissions(true, mem_type, &read_perm_low, &write_perm_low, NULL); + test_memprot_get_permissions(false, mem_type, &read_perm_high, &write_perm_high, NULL); + + //ensure READ enabled + esp_memprot_set_monitor_en(mem_type, false); + test_memprot_set_permissions(true, mem_type, true, write_perm_low, NULL); + test_memprot_set_permissions(false, mem_type, true, write_perm_high, NULL); + esp_memprot_set_monitor_en(mem_type, true); + + //get testing pointers for low & high regions + volatile uint32_t *ptr_low = test_memprot_addr_low(mem_type); + volatile uint32_t *ptr_high = test_memprot_addr_high(mem_type); + const uint32_t test_val = 10; + + //perform WRITE in low region + esp_rom_printf("%s write low: ", esp_memprot_mem_type_to_str(mem_type)); + esp_memprot_monitor_clear_intr(mem_type); + + volatile uint32_t val = 0; + *ptr_low = test_val; + val = *ptr_low; + + 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_mem_type_to_str(mem_type)); + esp_memprot_monitor_clear_intr(mem_type); + + val = 0; + *ptr_high = test_val + 1; + val = *ptr_high; + + 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); + } + + //restore original permissions + esp_memprot_set_monitor_en(mem_type, false); + test_memprot_set_permissions(true, mem_type, true, read_perm_low, NULL); + test_memprot_set_permissions(false, mem_type, true, read_perm_high, NULL); + esp_memprot_set_monitor_en(mem_type, true); +} + +static void test_memprot_exec(mem_type_prot_t mem_type) +{ + if ( mem_type != MEMPROT_IRAM0_SRAM ) { + esp_rom_printf("Error: EXEC test available only for IRAM access.\n" ); + return; + } + + bool write_perm_low, write_perm_high, read_perm_low, read_perm_high, exec_perm_low, exec_perm_high; + + //temporarily enable READ/WRITE + test_memprot_get_permissions(true, mem_type, &read_perm_low, &write_perm_low, &exec_perm_low); + test_memprot_get_permissions(false, mem_type, &read_perm_high, &write_perm_high, &exec_perm_high); + esp_memprot_set_monitor_en(mem_type, false); + test_memprot_set_permissions(true, mem_type, true, true, &exec_perm_low); + test_memprot_set_permissions(false, mem_type, true, true, &exec_perm_high); + esp_memprot_set_monitor_en(mem_type, true); + + //get testing pointers for low & high regions, zero 8B slot + void *fnc_ptr_low = test_memprot_addr_low(mem_type); + void *fnc_ptr_high = test_memprot_addr_high(mem_type); + memset( fnc_ptr_low, 0, 8); + memset( fnc_ptr_high, 0, 8); + + //inject the code to both low & high segments + memcpy( (void *)fnc_ptr_low, (const void *)fnc_buff, sizeof(fnc_buff) ); + memcpy( (void *)fnc_ptr_high, (const void *)fnc_buff, sizeof(fnc_buff) ); + + uint32_t res = 0; + + //LOW REGION: clear the intr flag & try to execute the code injected + esp_rom_printf("%s exec low: ", esp_memprot_mem_type_to_str(mem_type)); + esp_memprot_monitor_clear_intr(mem_type); + + fnc_ptr fnc = (fnc_ptr)fnc_ptr_low; + + g_override_illegal_instruction = true; + res = fnc( 5 ); + 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, false); + } else { + esp_rom_printf(" FAULT [injected code not executed]\n"); + } + } + + //HIGH REGION: clear the intr-on flag & try to execute the code injected + esp_rom_printf("%s exec high: ", esp_memprot_mem_type_to_str(mem_type)); + esp_memprot_monitor_clear_intr(mem_type); + + fnc = (fnc_ptr)fnc_ptr_high; + + g_override_illegal_instruction = true; + res = fnc( 6 ); + 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, false); + } else { + esp_rom_printf(" FAULT [injected code not executed]\n"); + } + } + + //restore original permissions + esp_memprot_set_monitor_en(mem_type, false); + test_memprot_set_permissions(true, mem_type, read_perm_low, write_perm_low, &exec_perm_low); + test_memprot_set_permissions(false, mem_type, read_perm_high, write_perm_high, &exec_perm_high); + esp_memprot_set_monitor_en(mem_type, true); +} + + +/* ******************************************************************************************** + * main test runner + */ +void app_main(void) +{ + esp_memprot_set_prot_int(false, false, NULL, NULL); + + test_memprot_read(MEMPROT_IRAM0_SRAM); + test_memprot_write(MEMPROT_IRAM0_SRAM); + test_memprot_exec(MEMPROT_IRAM0_SRAM); + + test_memprot_read(MEMPROT_DRAM0_SRAM); + test_memprot_write(MEMPROT_DRAM0_SRAM); +} diff --git a/tools/test_apps/system/memprot/main/esp32c3/test_panic.c b/tools/test_apps/system/memprot/main/esp32c3/test_panic.c new file mode 100644 index 0000000000..31295e0e21 --- /dev/null +++ b/tools/test_apps/system/memprot/main/esp32c3/test_panic.c @@ -0,0 +1,52 @@ +// 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 "riscv/rvruntime-frames.h" +#include "esp_private/panic_internal.h" + +#define MCAUSE_ILLEGAL_INSTRUCTION 2 + +extern void esp_panic_handler(panic_info_t *info); +volatile bool g_override_illegal_instruction = false; + +void __real_esp_panic_handler(panic_info_t *info); + +void return_from_panic_handler(RvExcFrame *frm) __attribute__((noreturn)); + +/* 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 + * Illegal instruction 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 Illegal instruction comes from a different source than the testing code + * the behavior is undefined + * */ +void __wrap_esp_panic_handler(panic_info_t *info) +{ + RvExcFrame *frm = (RvExcFrame *)info->frame; + if ( frm->mcause == MCAUSE_ILLEGAL_INSTRUCTION && g_override_illegal_instruction == true ) { + /* Return from exception to the return address that called the faulting function. + */ + frm->mepc = frm->ra; + + /* Restore the CPU state and return from the exception. + */ + return_from_panic_handler(frm); + } else { + __real_esp_panic_handler(info); + } +} diff --git a/tools/test_apps/system/memprot/main/test_memprot_main.c b/tools/test_apps/system/memprot/main/esp32s2/test_memprot_main.c similarity index 68% rename from tools/test_apps/system/memprot/main/test_memprot_main.c rename to tools/test_apps/system/memprot/main/esp32s2/test_memprot_main.c index 6571d3ce0c..1ad8333ea6 100644 --- a/tools/test_apps/system/memprot/main/test_memprot_main.c +++ b/tools/test_apps/system/memprot/main/esp32s2/test_memprot_main.c @@ -10,51 +10,53 @@ * 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: + * In order to safely test all the mem_prot features configuration, this test uses a combination of + * proprietary settings and ESP-IDF defaults. + * Each operation is tested at both low region and high region testing address. + * Complete testing scheme is depicted below: * * ******************************************************************************************** * * 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 + * |-------------------------| + * | iram_test_buffer (1kB) | + * <---------- test addr low -------> iram_test_buffer + 0x200 + * | | + * _iram_text_end <======== real splt.addr ========> _data_start (real splt.addr == test splt.addr) + * | | + * <---|-------------------------|--> + * | dram_test_buffer (1kB) | + * <--------- test addr high -------> dram_test_buffer + 0x200 * | ... | * |-------------------------| * | | * =========================== * * RTC_FAST (8kB) - * (_rtc_text_end) =========================== (_rtc_dummy_end) - * 0x40070000 <-------- real splt.addr --------> 0x3FF9E000 - * | | - * | test buffer (7 kB) | - * | ... | - * 0x40070E00 <-------- test splt.addr --------> 0x3FF9EE00 - * | ... | + * =========================== + * _rtc_text_end <======== real splt.addr ========> _rtc_dummy_end + * | rtcfast_dummy_buffer | + * | (2kB) | + * <---------- test addr low -------> test_buffer - 0x200 + * <-------- test splt.addr --------> test_buffer = rtcfast_dummy_buffer / 2 + * <---------- test addr low -------> test_buffer + 0x200 * |-------------------------| * | | * =========================== * * ******************************************************************************************** * - * PERIBUS_1 RTC_SLOW (8/768kB) PERIBUS_2_0 PERIBUS_2_1 + * 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 - * | ... | + * 0x3F421000 <======== real splt.addr ========> 0x50000000 0x60021000 + * | rtcslow_dummy_buffer | + * | (2kB) | + * <---------- test addr low -------> test_buffer - 0x200 + * <-------- test splt.addr --------> test_buffer = rtcslow_dummy_buffer / 2 + * <---------- test addr low -------> test_buffer + 0x200 * |-------------------------| * | | * =========================== @@ -90,39 +92,30 @@ */ 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}; +#define MAP_DRAM_TO_IRAM(addr) (addr - SOC_DIRAM_DRAM_LOW + SOC_DIRAM_IRAM_LOW) +#define MAP_IRAM_TO_DRAM(addr) (addr - SOC_DIRAM_IRAM_LOW + SOC_DIRAM_DRAM_LOW) + +#define SRAM_TEST_BUFFER_SIZE 0x400 +#define SRAM_TEST_OFFSET 0x200 + +static uint8_t __attribute__((section(".iram_end_test"))) iram_test_buffer[SRAM_TEST_BUFFER_SIZE] = {0}; +static uint8_t dram_test_buffer[SRAM_TEST_BUFFER_SIZE] = {0}; +static uint8_t RTC_FAST_ATTR rtcfast_dummy_buffer[2 * SRAM_TEST_BUFFER_SIZE] = {0}; +static uint8_t RTC_SLOW_ATTR rtcslow_dummy_buffer[2 * SRAM_TEST_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 *) @@ -152,13 +145,58 @@ static uint32_t *test_memprot_peri2_rtcslow_1_get_min_split_addr(void) - esp_memprot_get_low_limit(MEMPROT_PERI2_RTCSLOW_0)); } +static uint32_t *test_memprot_addr_low(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return (uint32_t *)((uint32_t)iram_test_buffer + SRAM_TEST_OFFSET); + case MEMPROT_DRAM0_SRAM: + return (uint32_t *)MAP_IRAM_TO_DRAM((uint32_t)iram_test_buffer + SRAM_TEST_OFFSET); + case MEMPROT_IRAM0_RTCFAST: + return (uint32_t *)((uint32_t)test_memprot_iram0_rtcfast_get_min_split_addr() - SRAM_TEST_OFFSET); + case MEMPROT_DRAM0_RTCFAST: + return (uint32_t *)((uint32_t)test_memprot_dram0_rtcfast_get_min_split_addr() - SRAM_TEST_OFFSET); + case MEMPROT_PERI1_RTCSLOW: + return (uint32_t *)((uint32_t)test_memprot_peri1_rtcslow_get_min_split_addr() - SRAM_TEST_OFFSET); + case MEMPROT_PERI2_RTCSLOW_0: + return (uint32_t *)((uint32_t)test_memprot_peri2_rtcslow_0_get_min_split_addr() - SRAM_TEST_OFFSET); + case MEMPROT_PERI2_RTCSLOW_1: + return (uint32_t *)((uint32_t)test_memprot_peri2_rtcslow_1_get_min_split_addr() - SRAM_TEST_OFFSET); + default: + abort(); + } +} + +static uint32_t *test_memprot_addr_high(mem_type_prot_t mem_type) +{ + switch ( mem_type ) { + case MEMPROT_IRAM0_SRAM: + return (uint32_t *)MAP_DRAM_TO_IRAM((uint32_t)dram_test_buffer + SRAM_TEST_OFFSET); + case MEMPROT_DRAM0_SRAM: + return (uint32_t *)((uint32_t)dram_test_buffer + SRAM_TEST_OFFSET); + case MEMPROT_IRAM0_RTCFAST: + return (uint32_t *)((uint32_t)test_memprot_iram0_rtcfast_get_min_split_addr() + SRAM_TEST_OFFSET); + case MEMPROT_DRAM0_RTCFAST: + return (uint32_t *)((uint32_t)test_memprot_dram0_rtcfast_get_min_split_addr() + SRAM_TEST_OFFSET); + case MEMPROT_PERI1_RTCSLOW: + return (uint32_t *)((uint32_t)test_memprot_peri1_rtcslow_get_min_split_addr() + SRAM_TEST_OFFSET); + case MEMPROT_PERI2_RTCSLOW_0: + return (uint32_t *)((uint32_t)test_memprot_peri2_rtcslow_0_get_min_split_addr() + SRAM_TEST_OFFSET); + case MEMPROT_PERI2_RTCSLOW_1: + return (uint32_t *)((uint32_t)test_memprot_peri2_rtcslow_1_get_min_split_addr() + SRAM_TEST_OFFSET); + default: + abort(); + } +} + + 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(); + return esp_memprot_get_split_addr(MEMPROT_IRAM0_SRAM); case MEMPROT_DRAM0_SRAM: - return test_memprot_dram0_sram_get_min_split_addr(); + return esp_memprot_get_split_addr(MEMPROT_DRAM0_SRAM); case MEMPROT_IRAM0_RTCFAST: return test_memprot_iram0_rtcfast_get_min_split_addr(); case MEMPROT_DRAM0_RTCFAST: @@ -218,25 +256,25 @@ static void test_memprot_set_prot(uint32_t *mem_type_mask, bool use_panic_handle //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); + esp_memprot_set_prot_iram(MEMPROT_IRAM0_SRAM, DEF_SPLIT_LINE, WR_LOW_DIS, RD_LOW_ENA, EX_LOW_ENA, WR_HIGH_DIS, RD_HIGH_DIS, EX_HIGH_DIS); } 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); + esp_memprot_set_prot_iram(MEMPROT_IRAM0_RTCFAST, test_memprot_iram0_rtcfast_get_min_split_addr(), WR_LOW_DIS, RD_LOW_ENA, EX_LOW_ENA, WR_HIGH_DIS, RD_HIGH_DIS, EX_HIGH_DIS); } 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); + esp_memprot_set_prot_dram(MEMPROT_DRAM0_SRAM, DEF_SPLIT_LINE, WR_LOW_DIS, RD_LOW_ENA, WR_HIGH_ENA, RD_HIGH_ENA); } 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); + esp_memprot_set_prot_dram(MEMPROT_DRAM0_RTCFAST, test_memprot_dram0_rtcfast_get_min_split_addr(), WR_LOW_DIS, RD_LOW_ENA, WR_HIGH_ENA, RD_HIGH_ENA); } 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); + esp_memprot_set_prot_peri1(MEMPROT_PERI1_RTCSLOW, test_memprot_peri1_rtcslow_get_min_split_addr(), WR_LOW_DIS, RD_LOW_DIS, RD_HIGH_DIS, WR_HIGH_DIS); } 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); + esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_0, test_memprot_peri2_rtcslow_0_get_min_split_addr(), WR_LOW_ENA, RD_LOW_ENA, EX_LOW_DIS, WR_HIGH_ENA, RD_HIGH_ENA, EX_HIGH_DIS); } 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); + esp_memprot_set_prot_peri2(MEMPROT_PERI2_RTCSLOW_1, test_memprot_peri2_rtcslow_1_get_min_split_addr(), WR_LOW_DIS, RD_LOW_DIS, EX_LOW_DIS, WR_HIGH_DIS, RD_HIGH_DIS, EX_HIGH_DIS); } //reenable protection (bus based) @@ -304,23 +342,25 @@ 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_write(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); + volatile uint32_t *ptr_low = test_memprot_addr_low(mem_type); + volatile uint32_t *ptr_high = test_memprot_addr_high(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; + + const uint32_t test_val = 100; + *ptr_low = test_val; + *ptr_high = 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); + volatile uint32_t val = *ptr_low; if ( val != 0 && val != test_val ) { esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val ); dump_status_register(mem_type); @@ -331,7 +371,7 @@ static void test_memprot_read(mem_type_prot_t mem_type) //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); + val = *ptr_high; if ( val != 0 && val != (test_val + 1) ) { esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); dump_status_register(mem_type); @@ -344,14 +384,14 @@ 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_write(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); + volatile uint32_t *ptr_low = test_memprot_addr_low(mem_type); + volatile uint32_t *ptr_high = test_memprot_addr_high(mem_type); //perform WRITE in low region const uint32_t test_val = 10; @@ -359,8 +399,8 @@ static void test_memprot_write(mem_type_prot_t mem_type) esp_memprot_clear_intr(mem_type); volatile uint32_t val = 0; - *(ptr - 4) = test_val; - val = *(ptr - 4); + *ptr_low = test_val; + val = *ptr_low; if ( val != test_val && write_perm_low ) { esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); @@ -373,8 +413,8 @@ static void test_memprot_write(mem_type_prot_t mem_type) 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); + *ptr_high = test_val + 1; + val = *ptr_high; if ( val != (test_val + 1) && write_perm_high ) { esp_rom_printf( "UNEXPECTED VALUE 0x%08X -", val); @@ -382,6 +422,8 @@ static void test_memprot_write(mem_type_prot_t mem_type) } else { check_test_result(mem_type, write_perm_high); } + + esp_memprot_set_read_perm(mem_type, read_perm_low, read_perm_high); } static void test_memprot_exec(mem_type_prot_t mem_type) @@ -394,8 +436,8 @@ static void test_memprot_exec(mem_type_prot_t mem_type) 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); + volatile uint32_t *fnc_ptr_low = test_memprot_addr_low(mem_type); + volatile uint32_t *fnc_ptr_high = test_memprot_addr_high(mem_type); //enable WRITE permission for both segments esp_memprot_set_write_perm(mem_type, true, true); @@ -423,7 +465,7 @@ static void test_memprot_exec(mem_type_prot_t mem_type) check_test_result(mem_type, exec_perm_low); } else { if ( !exec_perm_low ) { - check_test_result(mem_type, true); + check_test_result(mem_type, false); } else { esp_rom_printf(" FAULT [injected code not executed]\n"); } @@ -442,14 +484,13 @@ static void test_memprot_exec(mem_type_prot_t mem_type) check_test_result(mem_type, exec_perm_high); } else { if ( !exec_perm_high ) { - check_test_result(mem_type, true); + check_test_result(mem_type, false); } else { esp_rom_printf(" FAULT [injected code not executed]\n"); } } } - /* ******************************************************************************************** * main test runner */ diff --git a/tools/test_apps/system/memprot/main/test_panic.c b/tools/test_apps/system/memprot/main/esp32s2/test_panic.c similarity index 100% rename from tools/test_apps/system/memprot/main/test_panic.c rename to tools/test_apps/system/memprot/main/esp32s2/test_panic.c diff --git a/tools/test_apps/system/memprot/sdkconfig.ci b/tools/test_apps/system/memprot/sdkconfig.ci index b77e5a7358..6ddc3a5c94 100644 --- a/tools/test_apps/system/memprot/sdkconfig.ci +++ b/tools/test_apps/system/memprot/sdkconfig.ci @@ -1,5 +1,5 @@ -# Esp32S2 only -CONFIG_IDF_TARGET="esp32s2" +CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n -# Disable automatic memory protection -CONFIG_ESP32S2_MEMPROT_FEATURE=n +# IDF-3090 +CONFIG_ESP32C3_REV_MIN_0=y +CONFIG_ESP32C3_REV_MIN=0