Sfoglia il codice sorgente

esp32c3: memprot API upgrade and test application

Closes IDF-2641
Martin Vychodil 5 anni fa
parent
commit
6dfff2fdbd

+ 2 - 2
components/esp32c3/CMakeLists.txt

@@ -46,9 +46,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")
 

+ 372 - 11
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;
+
+typedef enum
+{
+    MEMPROT_PMS_OP_READ = 0,
+    MEMPROT_PMS_OP_WRITE,
+    MEMPROT_PMS_OP_FETCH,
+    MEMPROT_PMS_OP_INVALID = 0xFFFFFFFF
+} pms_operation_type_t;
+
+/**
+ * @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);
 
-const char *mem_type_to_str(mem_type_prot_t mem_type);
-const char *split_line_to_str(split_line_t line_type);
-const char *pms_to_str(pms_area_t area_type);
+/**
+ * @brief 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);
 
-void *esp_memprot_get_main_split_addr(void);
-void esp_memprot_set_split_line_lock(bool lock);
+/**
+ * @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

+ 2 - 0
components/esp32c3/ld/esp32c3.project.ld.in

@@ -369,6 +369,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
 

+ 134 - 85
components/esp32c3/memprot.c

@@ -22,34 +22,31 @@
 #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 "esp_log.h"
+#include "esp32c3/rom/ets_sys.h"
+
 
 extern int _iram_text_end;
 
-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 +64,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 +91,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)
+{
+    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(lock);
+    memprot_ll_set_iram0_dram0_split_line_lock();
 }
 
 bool esp_memprot_get_split_line_lock()
@@ -111,11 +126,8 @@ 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_LOGD(TAG, "Setting split line %s, addr: 0x%08X", split_line_to_str(line_type), addr);
-
-    //split-line must be divisible by 512
-    assert( addr % 0x200 == 0 );
+    //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,52 +146,41 @@ 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_LOGE(TAG, "Invalid split line type, aborting: 0x%08X", addr);
         abort();
     }
 }
 
-// TODO - get split lines
-
 
 /* PMS */
 
-void esp_memprot_set_pms_lock(mem_type_prot_t mem_type, bool lock)
+void esp_memprot_set_pms_lock(mem_type_prot_t mem_type)
 {
-    ESP_LOGD(TAG, "esp_memprot_set_pms_lock(%s, %s)", mem_type_to_str(mem_type), lock ? "true" : "false");
-
     switch ( mem_type ) {
     case MEMPROT_IRAM0_SRAM:
-        memprot_ll_iram0_set_pms_lock(lock);
+        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_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
 
 bool esp_memprot_get_pms_lock(mem_type_prot_t mem_type)
 {
-    ESP_LOGD(TAG, "esp_memprot_get_pms_lock(%s)", mem_type_to_str(mem_type));
-
     switch ( mem_type ) {
     case MEMPROT_IRAM0_SRAM:
         return memprot_ll_iram0_get_pms_lock();
     case MEMPROT_DRAM0_SRAM:
         return memprot_ll_dram0_get_pms_lock();
     default:
-        ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
 
 void esp_memprot_iram_set_pms_area(pms_area_t area_type, bool r, bool w, bool x)
 {
-    ESP_LOGD(TAG, "esp_memprot_iram_set_pms_area(area:%s r:%u w:%u, x:%u)", pms_to_str(area_type), r, w, x);
-
     switch ( area_type ) {
     case MEMPROT_IRAM0_PMS_AREA_0:
         memprot_ll_iram0_set_pms_area_0(r, w, x);
@@ -194,15 +195,32 @@ 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_LOGE(TAG, "Invalid area_type %d", pms_to_str(area_type));
         abort();
     }
 }
 
-void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w)
+void esp_memprot_iram_get_pms_area(pms_area_t area_type, bool *r, bool *w, bool *x)
 {
-    ESP_LOGD(TAG, "esp_memprot_dram_set_pms_area(area:%s r:%u w:%u)", pms_to_str(area_type), r, w);
+    switch ( area_type ) {
+    case MEMPROT_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:
+        abort();
+    }
+}
 
+void esp_memprot_dram_set_pms_area(pms_area_t area_type, bool r, bool w)
+{
     switch ( area_type ) {
     case MEMPROT_DRAM0_PMS_AREA_0:
         memprot_ll_dram0_set_pms_area_0(r, w);
@@ -217,52 +235,61 @@ 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_LOGE(TAG, "Invalid area_type %d", 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)
+{
+    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:
+        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_LOGD(TAG, "esp_memprot_set_monitor_lock(%s, %s)", mem_type_to_str(mem_type), lock ? "true" : "false");
-
     switch ( mem_type ) {
     case MEMPROT_IRAM0_SRAM:
-        memprot_ll_iram0_set_monitor_lock(lock);
+        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_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
 
 bool esp_memprot_get_monitor_lock(mem_type_prot_t mem_type)
 {
-    ESP_LOGD(TAG, "esp_memprot_get_monitor_lock(%s)", mem_type_to_str(mem_type));
-
     switch ( mem_type ) {
     case MEMPROT_IRAM0_SRAM:
         return memprot_ll_iram0_get_monitor_lock();
     case MEMPROT_DRAM0_SRAM:
         return memprot_ll_dram0_get_monitor_lock();
     default:
-        ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
 
 void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable)
 {
-    ESP_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", mem_type_to_str(mem_type));
-
     switch ( mem_type ) {
     case MEMPROT_IRAM0_SRAM:
         memprot_ll_iram0_set_monitor_en(enable);
@@ -271,22 +298,18 @@ void esp_memprot_set_monitor_en(mem_type_prot_t mem_type, bool enable)
         memprot_ll_dram0_set_monitor_en(enable);
         break;
     default:
-        ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
 
 bool esp_memprot_get_monitor_en(mem_type_prot_t mem_type)
 {
-    ESP_LOGD(TAG, "esp_memprot_set_monitor_en(%s)", mem_type_to_str(mem_type));
-
     switch ( mem_type ) {
     case MEMPROT_IRAM0_SRAM:
         return memprot_ll_iram0_get_monitor_en();
     case MEMPROT_DRAM0_SRAM:
         return memprot_ll_dram0_get_monitor_en();
     default:
-        ESP_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
@@ -298,17 +321,17 @@ bool esp_memprot_is_intr_ena_any()
 
 void esp_memprot_monitor_clear_intr(mem_type_prot_t mem_type)
 {
-    ESP_LOGD(TAG, "esp_memprot_monitor_clear_intr(%s)", mem_type_to_str(mem_type));
 
     switch ( mem_type ) {
     case MEMPROT_IRAM0_SRAM:
         memprot_ll_iram0_clear_monitor_intr();
+        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_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
@@ -334,15 +357,14 @@ 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_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
@@ -355,44 +377,50 @@ 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_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
 
-uint32_t esp_memprot_get_violate_world(mem_type_prot_t mem_type)
+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_LOGE(TAG, "Invalid mem_type (%s), aborting", 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_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
 
-uint32_t esp_memprot_get_violate_loadstore(mem_type_prot_t mem_type)
+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_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
@@ -403,7 +431,6 @@ 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_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 }
@@ -415,8 +442,6 @@ int esp_memprot_intr_get_cpuid()
 
 void esp_memprot_set_intr_matrix(mem_type_prot_t mem_type)
 {
-    ESP_LOGD(TAG, "esp_memprot_set_intr_matrix(%s)", mem_type_to_str(mem_type));
-
     ESP_INTR_DISABLE(ETS_MEMPROT_ERR_INUM);
 
     switch (mem_type) {
@@ -427,7 +452,6 @@ 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_LOGE(TAG, "Invalid mem_type (%s), aborting", mem_type_to_str(mem_type));
         abort();
     }
 
@@ -445,8 +469,6 @@ void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature, uint32_t
 
 void esp_memprot_set_prot_int(bool invoke_panic_handler, bool lock_feature, void *split_addr, uint32_t *mem_type_mask)
 {
-    ESP_LOGD(TAG, "esp_memprot_set_prot(panic_handler: %u, lock: %u, split.addr: 0x%08X, mem.types: 0x%08X", invoke_panic_handler, lock_feature, (uint32_t)split_addr, (uint32_t)mem_type_mask);
-
     uint32_t required_mem_prot = mem_type_mask == NULL ? (uint32_t)MEMPROT_ALL : *mem_type_mask;
     bool use_iram0 = required_mem_prot & MEMPROT_IRAM0_SRAM;
     bool use_dram0 = required_mem_prot & MEMPROT_DRAM0_SRAM;
@@ -474,7 +496,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 +529,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();
+    }
+}

+ 26 - 0
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

+ 3 - 1
components/esp32s2/ld/esp32s2.project.ld.in

@@ -93,7 +93,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):
@@ -186,6 +186,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

+ 7 - 7
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)

+ 7 - 7
components/esp_system/port/arch/riscv/panic_arch.c

@@ -154,27 +154,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 );

+ 194 - 69
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);
 }
 
+static inline void* memprot_ll_get_iram0_split_line_main_I_D(void)
+{
+    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);
+}
+
 
-/* PMS */
+///////////////////////////////////
+// IRAM0 - PMS CONFIGURATION
+///////////////////////////////////
 
-static inline void memprot_ll_iram0_set_pms_lock(bool lock)
+// lock
+static inline void memprot_ll_iram0_set_pms_lock(void)
 {
-    REG_WRITE(SENSITIVE_CORE_X_IRAM0_PMS_CONSTRAIN_0_REG, lock ? 1 : 0);
+    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_get_permissions(uint32_t perms, bool *r, bool *w, bool *x)
+{
+    *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_set_monitor_lock(bool lock)
+static inline void memprot_ll_iram0_get_pms_area_1(bool *r, bool *w, bool *x)
 {
-    REG_WRITE(SENSITIVE_CORE_0_IRAM0_PMS_MONITOR_0_REG, lock ? 1 : 0);
+    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);
 }
 
+static inline void* memprot_ll_get_dram0_split_line_D_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_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);
+}
+
 
-/* PMS */
+///////////////////////////////////
+// DRAM0 - PMS CONFIGURATION
+///////////////////////////////////
 
-static inline void memprot_ll_dram0_set_pms_lock(bool lock)
+// lock
+static inline void memprot_ll_dram0_set_pms_lock(void)
 {
-    REG_WRITE(SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_0_REG, lock ? 1 : 0);
+    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));
 }
 
+static inline void memprot_ll_dram0_get_permissions(uint32_t perms, bool *r, bool *w )
+{
+    *r = perms & SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_R;
+    *w = perms & SENSITIVE_CORE_X_DRAM0_PMS_CONSTRAIN_SRAM_WORLD_0_W;
+}
 
-/* MONITOR */
+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_set_monitor_lock(bool lock)
+static inline void memprot_ll_dram0_get_pms_area_1(bool *r, bool *w)
 {
-    REG_WRITE(SENSITIVE_CORE_0_DRAM0_PMS_MONITOR_0_REG, lock ? 1 : 0);
+    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
 }

+ 27 - 26
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;

+ 13 - 12
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;

+ 6 - 0
tools/ci/config/target-test.yml

@@ -348,6 +348,12 @@ test_app_test_004:
     - ESP32S2
     - Example_GENERIC
 
+test_app_test_005:
+  extends: .test_app_template
+  tags:
+    - ESP32C3
+    - Example_GENERIC
+
 test_app_test_esp32_generic:
   extends: .test_app_template
   parallel: 4

+ 1 - 1
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)
 

+ 2 - 2
tools/test_apps/system/memprot/README.md

@@ -1,2 +1,2 @@
-| Supported Targets | ESP32-S2 |
-| ----------------- | -------- |
+| Supported Targets | ESP32-S2 | ESP32-C3 |
+| ----------------- | -------- | -------- |

+ 18 - 3
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')

+ 6 - 1
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()

+ 4 - 0
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

+ 71 - 0
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

+ 392 - 0
tools/test_apps/system/memprot/main/esp32c3/test_memprot_main.c

@@ -0,0 +1,392 @@
+/* MEMPROT (PMS) testing code */
+#include <stdio.h>
+#include "sdkconfig.h"
+#include "esp32c3/memprot.h"
+#include "esp_rom_sys.h"
+#include <string.h>
+
+/**
+ * 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);
+}

+ 52 - 0
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);
+    }
+}

+ 114 - 73
tools/test_apps/system/memprot/main/test_memprot_main.c → 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
  */

+ 0 - 0
tools/test_apps/system/memprot/main/test_panic.c → tools/test_apps/system/memprot/main/esp32s2/test_panic.c


+ 4 - 4
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