Parcourir la source

Merge branch 'feature/esp32s2_iram_dram_protection' into 'master'

esp32s2: IRAM/DRAM memory protection

See merge request espressif/esp-idf!8156
Ivan Grokhotkov il y a 5 ans
Parent
commit
275ed32a11

+ 3 - 3
components/esp32/cache_err_int.c

@@ -33,13 +33,13 @@
 void esp_cache_err_int_init(void)
 {
     uint32_t core_id = xPortGetCoreID();
-    ESP_INTR_DISABLE(ETS_CACHEERR_INUM);
+    ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM);
 
     // We do not register a handler for the interrupt because it is interrupt
     // level 4 which is not serviceable from C. Instead, xtensa_vectors.S has
     // a call to the panic handler for
     // this interrupt.
-    intr_matrix_set(core_id, ETS_CACHE_IA_INTR_SOURCE, ETS_CACHEERR_INUM);
+    intr_matrix_set(core_id, ETS_CACHE_IA_INTR_SOURCE, ETS_MEMACCESS_ERR_INUM);
 
     // Enable invalid cache access interrupt when the cache is disabled.
     // When the interrupt happens, we can not determine the CPU where the
@@ -67,7 +67,7 @@ void esp_cache_err_int_init(void)
             DPORT_CACHE_IA_INT_APP_IRAM0 |
             DPORT_CACHE_IA_INT_APP_IRAM1);
     }
-    ESP_INTR_ENABLE(ETS_CACHEERR_INUM);
+    ESP_INTR_ENABLE(ETS_MEMACCESS_ERR_INUM);
 }
 
 int IRAM_ATTR esp_cache_err_get_cpuid(void)

+ 1 - 1
components/esp32/include/esp32/cache_err_int.h

@@ -17,7 +17,7 @@
  * @brief initialize cache invalid access interrupt
  *
  * This function enables cache invalid access interrupt source and connects it
- * to interrupt input number ETS_CACHEERR_INUM (see soc/soc.h). It is called
+ * to interrupt input number ETS_MEMACCESS_ERR_INUM (see soc/soc.h). It is called
  * from the startup code.
  */
 void esp_cache_err_int_init(void);

+ 1 - 0
components/esp32s2/CMakeLists.txt

@@ -12,6 +12,7 @@ else()
     # Regular app build
 
     set(srcs "cache_err_int.c"
+             "memprot.c"
              "clk.c"
              "cpu_start.c"
              "crosscore_int.c"

+ 23 - 0
components/esp32s2/Kconfig

@@ -29,6 +29,29 @@ menu "ESP32S2-specific"
         default 160 if ESP32S2_DEFAULT_CPU_FREQ_160
         default 240 if ESP32S2_DEFAULT_CPU_FREQ_240
 
+    menu "Memory protection"
+
+        config ESP32S2_MEMPROT_FEATURE
+            bool "Enable memory protection"
+            default "y"
+            help
+                If enabled, permission control module watches all memory access and fires panic handler
+                if permission violation is detected. This feature automatically splits
+                memory into data and instruction segments and sets Read/Execute permissions
+                for instruction part (below splitting address) and Read/Write permissions
+                for data part (above splitting address). The memory protection is effective
+                on all access through IRAM0 and DRAM0 buses.
+
+        config ESP32S2_MEMPROT_FEATURE_LOCK
+            depends on ESP32S2_MEMPROT_FEATURE
+            bool "Lock memory protection settings"
+            default "y"
+            help
+                Once locked, memory protection settings cannot be changed anymore.
+                The lock is reset only on the chip startup.
+
+    endmenu  # Memory protection
+
     menu "Cache config"
 
         choice ESP32S2_INSTRUCTION_CACHE_SIZE

+ 3 - 3
components/esp32s2/cache_err_int.c

@@ -36,13 +36,13 @@
 void esp_cache_err_int_init(void)
 {
     uint32_t core_id = xPortGetCoreID();
-    ESP_INTR_DISABLE(ETS_CACHEERR_INUM);
+    ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM);
 
     // We do not register a handler for the interrupt because it is interrupt
     // level 4 which is not serviceable from C. Instead, xtensa_vectors.S has
     // a call to the panic handler for
     // this interrupt.
-    intr_matrix_set(core_id, ETS_CACHE_IA_INTR_SOURCE, ETS_CACHEERR_INUM);
+    intr_matrix_set(core_id, ETS_CACHE_IA_INTR_SOURCE, ETS_MEMACCESS_ERR_INUM);
 
     // Enable invalid cache access interrupt when the cache is disabled.
     // When the interrupt happens, we can not determine the CPU where the
@@ -73,7 +73,7 @@ void esp_cache_err_int_init(void)
                             EXTMEM_IC_SYNC_SIZE_FAULT_INT_ENA |
                             EXTMEM_CACHE_DBG_EN);
 
-    ESP_INTR_ENABLE(ETS_CACHEERR_INUM);
+    ESP_INTR_ENABLE(ETS_MEMACCESS_ERR_INUM);
 }
 
 int IRAM_ATTR esp_cache_err_get_cpuid(void)

+ 10 - 0
components/esp32s2/cpu_start.c

@@ -26,6 +26,7 @@
 #include "esp32s2/brownout.h"
 #include "esp32s2/cache_err_int.h"
 #include "esp32s2/spiram.h"
+#include "esp32s2/memprot.h"
 
 #include "soc/cpu.h"
 #include "soc/rtc.h"
@@ -317,6 +318,14 @@ void start_cpu0_default(void)
     err = esp_pthread_init();
     assert(err == ESP_OK && "Failed to init pthread module!");
 
+#if CONFIG_ESP32S2_MEMPROT_FEATURE
+#if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK
+    esp_memprot_set_prot(true, true);
+#else
+    esp_memprot_set_prot(true, false);
+#endif
+#endif
+
     do_global_ctors();
 #if CONFIG_ESP_INT_WDT
     esp_int_wdt_init();
@@ -353,6 +362,7 @@ void start_cpu0_default(void)
                         ESP_TASK_MAIN_STACK, NULL,
                         ESP_TASK_MAIN_PRIO, NULL, 0);
     assert(res == pdTRUE);
+
     ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
     vTaskStartScheduler();
     abort(); /* Only get to here if not enough free heap to start scheduler */

+ 1 - 1
components/esp32s2/include/esp32s2/cache_err_int.h

@@ -20,7 +20,7 @@ extern "C" {
  * @brief initialize cache invalid access interrupt
  *
  * This function enables cache invalid access interrupt source and connects it
- * to interrupt input number ETS_CACHEERR_INUM (see soc/soc.h). It is called
+ * to interrupt input number ETS_MEMACCESS_ERR_INUM (see soc/soc.h). It is called
  * from the startup code.
  */
 void esp_cache_err_int_init(void);

+ 353 - 0
components/esp32s2/include/esp32s2/memprot.h

@@ -0,0 +1,353 @@
+// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+/* INTERNAL API
+ * generic interface to MMU memory protection features
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    MEMPROT_IRAM0 =     0x00000000,
+    MEMPROT_DRAM0 =     0x00000001,
+    MEMPROT_UNKNOWN
+} mem_type_prot_t;
+
+
+/**
+ * @brief Returns splitting address for required memory region
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return Splitting address for the memory region required.
+ * The address is given by region-specific global symbol exported from linker script,
+ * it is not read out from related configuration register.
+ */
+uint32_t *IRAM_ATTR esp_memprot_get_split_addr(mem_type_prot_t mem_type);
+
+/**
+ * @brief Initializes illegal memory access control (MMU) for required memory section.
+ *
+ * All memory access interrupts share ETS_MEMACCESS_ERR_INUM input channel, it is caller's
+ * responsibility to properly detect actual intr. source as well as possible prioritization in case
+ * of multiple source reported during one intr.handling routine run
+ *
+ *  @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ */
+void esp_memprot_intr_init(mem_type_prot_t mem_type);
+
+/**
+ * @brief Enable/disable the memory protection interrupt
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param enable enable/disable
+ */
+void esp_memprot_intr_ena(mem_type_prot_t mem_type, bool enable);
+
+/**
+ * @brief Detects whether any of the memory protection interrupts is active
+ *
+ * @return true/false
+ */
+bool esp_memprot_is_assoc_intr_any(void);
+
+/**
+ * @brief Detects whether specific memory protection interrupt is active
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return true/false
+ */
+bool esp_memprot_is_assoc_intr(mem_type_prot_t mem_type);
+
+/**
+ * @brief Sets a request for clearing interrupt-on flag for specified memory region (register write)
+ *
+ * @note When called without actual interrupt-on flag set, subsequent occurrence of related interrupt is ignored.
+ * Should be used only after the real interrupt appears, typically as the last step in interrupt handler's routine.
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ */
+void esp_memprot_clear_intr(mem_type_prot_t mem_type);
+
+/**
+ * @brief Detects which memory protection interrupt is active, check order: IRAM0, DRAM0
+ *
+ * @return Memory protection area type (see mem_type_prot_t enum)
+ */
+mem_type_prot_t IRAM_ATTR esp_memprot_get_intr_memtype(void);
+
+/**
+ * @brief Gets interrupt status register contents for specified memory region
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return Contents of status register
+ */
+uint32_t esp_memprot_get_fault_reg(mem_type_prot_t mem_type);
+
+/**
+ * @brief Get details of given interrupt status
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param faulting_address Faulting address causing the interrupt [out]
+ * @param op_type Operation being processed at the faulting address [out]
+ *               IRAM0: 0 - read, 1 - write
+ *               DRAM0: 0 - read, 1 - write
+ * @param op_subtype Additional info for op_type [out]
+ *               IRAM0: 0 - instruction segment access, 1 - data segment access
+ *               DRAM0: 0 - non-atomic operation, 1 - atomic operation
+ */
+void IRAM_ATTR esp_memprot_get_fault_status(mem_type_prot_t mem_type, uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype);
+
+/**
+ * @brief Gets string representation of required memory region identifier
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return mem_type as string
+ */
+const char *IRAM_ATTR esp_memprot_type_to_str(mem_type_prot_t mem_type);
+
+/**
+ * @brief Detects whether any of the interrupt locks is active (requires digital system reset to unlock)
+ *
+ * @return true/false
+ */
+bool esp_memprot_is_locked_any(void);
+
+/**
+ * @brief Sets lock for specified memory region.
+ *
+ * Locks can be unlocked only by digital system reset
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ */
+void esp_memprot_set_lock(mem_type_prot_t mem_type);
+
+/**
+ * @brief Gets lock status for required memory region
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return true/false (locked/unlocked)
+ */
+bool esp_memprot_get_lock(mem_type_prot_t mem_type);
+
+/**
+ * @brief Gets interrupt permission control register contents for required memory region
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return Permission control register contents
+ */
+uint32_t esp_memprot_get_ena_reg(mem_type_prot_t mem_type);
+
+/**
+ * @brief Gets interrupt permission settings for unified management block
+ *
+ * Gets interrupt permission settings register contents for required memory region, returns settings for unified management blocks
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return Permission settings register contents
+ */
+uint32_t esp_memprot_get_perm_uni_reg(mem_type_prot_t mem_type);
+
+/**
+ * @brief Gets interrupt permission settings for split management block
+ *
+ * Gets interrupt permission settings register contents for required memory region, returns settings for split management blocks
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return Permission settings register contents
+ */
+uint32_t esp_memprot_get_perm_split_reg(mem_type_prot_t mem_type);
+
+/**
+ * @brief Detects whether any of the memory protection interrupts is enabled
+ *
+ * @return true/false
+ */
+bool esp_memprot_is_intr_ena_any(void);
+
+/**
+ * @brief Gets interrupt-enabled flag for given memory region
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return Interrupt-enabled value
+ */
+uint32_t esp_memprot_get_intr_ena_bit(mem_type_prot_t mem_type);
+
+/**
+ * @brief Gets interrupt-active flag for given memory region
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return Interrupt-active value
+ */
+uint32_t esp_memprot_get_intr_on_bit(mem_type_prot_t mem_type);
+
+/**
+ * @brief Gets interrupt-clear request flag for given memory region
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ *
+ * @return Interrupt-clear request value
+ */
+uint32_t esp_memprot_get_intr_clr_bit(mem_type_prot_t mem_type);
+
+/**
+ * @brief Gets read permission value for specified block and memory region
+ *
+ * Returns read permission bit value for required unified-management block (0-3) in given memory region.
+ * Applicable to all memory types.
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param block Memory block identifier (0-3)
+ *
+ * @return Read permission value for required block
+ */
+uint32_t esp_memprot_get_uni_block_read_bit(mem_type_prot_t mem_type, uint32_t block);
+
+/**
+ * @brief Gets write permission value for specified block and memory region
+ *
+ * Returns write permission bit value for required unified-management block (0-3) in given memory region.
+ * Applicable to all memory types.
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param block Memory block identifier (0-3)
+ *
+ * @return Write permission value for required block
+ */
+uint32_t esp_memprot_get_uni_block_write_bit(mem_type_prot_t mem_type, uint32_t block);
+
+/**
+ * @brief Gets execute permission value for specified block and memory region
+ *
+ * Returns execute permission bit value for required unified-management block (0-3) in given memory region.
+ * Applicable only to IRAM memory types
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param block Memory block identifier (0-3)
+ *
+ * @return Execute permission value for required block
+ */
+uint32_t esp_memprot_get_uni_block_exec_bit(mem_type_prot_t mem_type, uint32_t block);
+
+/**
+ * @brief Sets permissions for specified block in DRAM region
+ *
+ * Sets Read and Write permission for specified unified-management block (0-3) in given memory region.
+ * Applicable only to DRAM memory types
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param block Memory block identifier (0-3)
+ * @param write_perm Write permission flag
+ * @param read_perm Read permission flag
+ */
+void esp_memprot_set_uni_block_perm_dram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm);
+
+/**
+ * @brief Sets permissions for high and low memory segment in DRAM region
+ *
+ * Sets Read and Write permission for both low and high memory segments given by splitting address.
+ * The splitting address must be equal to or higher then beginning of block 5
+ * Applicable only to DRAM memory types
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param split_addr Address to split the memory region to lower and higher segment
+ * @param lw Low segment Write permission flag
+ * @param lr Low segment Read permission flag
+ * @param hw High segment Write permission flag
+ * @param hr High segment Read permission flag
+ */
+void esp_memprot_set_prot_dram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr);
+
+/**
+ * @brief Sets permissions for specified block in IRAM region
+ *
+ * Sets Read, Write and Execute permission for specified unified-management block (0-3) in given memory region.
+ * Applicable only to IRAM memory types
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param block Memory block identifier (0-3)
+ * @param write_perm Write permission flag
+ * @param exec_perm Execute permission flag
+ */
+void esp_memprot_set_uni_block_perm_iram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm, bool exec_perm);
+
+/**
+ * @brief Sets permissions for high and low memory segment in IRAM region
+ *
+ * Sets Read, Write and Execute permission for both low and high memory segments given by splitting address.
+ * The splitting address must be equal to or higher then beginning of block 5
+ * Applicable only to IRAM memory types
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param split_addr Address to split the memory region to lower and higher segment
+ * @param lw Low segment Write permission flag
+ * @param lr Low segment Read permission flag
+ * @param lx Low segment Execute permission flag
+ * @param hw High segment Write permission flag
+ * @param hr High segment Read permission flag
+ * @param hx High segment Execute permission flag
+ */
+void esp_memprot_set_prot_iram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx);
+
+/**
+ * @brief Activates memory protection for all supported memory region types
+ *
+ * @note The feature is disabled when JTAG interface is connected
+ *
+ * @param invoke_panic_handler map mem.prot interrupt to ETS_MEMACCESS_ERR_INUM and thus invokes panic handler when fired ('true' not suitable for testing)
+ * @param lock_feature sets LOCK bit, see esp_memprot_set_lock() ('true' not suitable for testing)
+ */
+void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature);
+
+/**
+ * @brief Get permission settings bits for IRAM split mgmt based on current split address
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param lw Low segment Write permission flag
+ * @param lr Low segment Read permission flag
+ * @param lx Low segment Execute permission flag
+ * @param hw High segment Write permission flag
+ * @param hr High segment Read permission flag
+ * @param hx High segment Execute permission flag
+ */
+void esp_memprot_get_perm_split_bits_iram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx);
+
+/**
+ * @brief Get permission settings bits for DRAM split mgmt based on current split address
+ *
+ * @param mem_type Memory protection area type (see mem_type_prot_t enum)
+ * @param lw Low segment Write permission flag
+ * @param lr Low segment Read permission flag
+ * @param hw High segment Write permission flag
+ * @param hr High segment Read permission flag
+ */
+void esp_memprot_get_perm_split_bits_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr);
+
+#ifdef __cplusplus
+}
+#endif

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

@@ -160,6 +160,8 @@ SECTIONS
 
     mapping[iram0_text]
 
+    /* align + add 16B for the possibly overlapping instructions */
+    . = ALIGN(4) + 16;
     _iram_text_end = ABSOLUTE(.);
     _iram_end = ABSOLUTE(.);
   } > iram0_0_seg

+ 491 - 0
components/esp32s2/memprot.c

@@ -0,0 +1,491 @@
+// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/* INTERNAL API
+ * implementation of generic interface to MMU memory protection features
+ */
+
+#include <stdio.h>
+#include "sdkconfig.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_system.h"
+#include "esp_spi_flash.h"
+#include "soc/sensitive_reg.h"
+#include "soc/dport_access.h"
+#include "soc/periph_defs.h"
+#include "esp_intr_alloc.h"
+#include "esp32s2/memprot.h"
+#include "hal/memprot_ll.h"
+#include "esp_fault.h"
+#include "esp_log.h"
+
+extern int _iram_text_end;
+extern int _data_start;
+static const char *TAG = "memprot";
+
+
+uint32_t *esp_memprot_iram0_get_min_split_addr(void)
+{
+    return (uint32_t *)&_iram_text_end;
+}
+
+uint32_t *esp_memprot_dram0_get_min_split_addr(void)
+{
+    return (uint32_t *)&_data_start;
+}
+
+uint32_t *esp_memprot_get_split_addr(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_min_split_addr();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_min_split_addr();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+const char *esp_memprot_type_to_str(mem_type_prot_t mem_type)
+{
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return "IRAM0";
+    case MEMPROT_DRAM0:
+        return "DRAM0";
+    default:
+        return "UNKOWN";
+    }
+}
+
+void esp_memprot_intr_init(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        intr_matrix_set(PRO_CPU_NUM, esp_memprot_iram0_get_intr_source_num(), ETS_MEMACCESS_ERR_INUM);
+        break;
+    case MEMPROT_DRAM0:
+        intr_matrix_set(PRO_CPU_NUM, esp_memprot_dram0_get_intr_source_num(), ETS_MEMACCESS_ERR_INUM);
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+
+    ESP_INTR_ENABLE(ETS_MEMACCESS_ERR_INUM);
+}
+
+void esp_memprot_intr_ena(mem_type_prot_t mem_type, bool enable)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        esp_memprot_iram0_intr_ena(enable);
+        break;
+    case MEMPROT_DRAM0:
+        esp_memprot_dram0_intr_ena(enable);
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+bool esp_memprot_is_assoc_intr_any()
+{
+    return esp_memprot_iram0_is_assoc_intr() || esp_memprot_dram0_is_assoc_intr();
+}
+
+mem_type_prot_t esp_memprot_get_intr_memtype()
+{
+    if ( esp_memprot_is_assoc_intr(MEMPROT_IRAM0) ) {
+        return MEMPROT_IRAM0;
+    } else if ( esp_memprot_is_assoc_intr(MEMPROT_DRAM0) ) {
+        return MEMPROT_DRAM0;
+    }
+
+    return MEMPROT_UNKNOWN;
+}
+
+bool esp_memprot_is_assoc_intr(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_is_assoc_intr();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_is_assoc_intr();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+void esp_memprot_clear_intr(mem_type_prot_t mem_type)
+{
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        esp_memprot_iram0_clear_intr();
+        break;
+    case MEMPROT_DRAM0:
+        esp_memprot_dram0_clear_intr();
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+void esp_memprot_set_lock(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        esp_memprot_iram0_set_lock();
+        break;
+    case MEMPROT_DRAM0:
+        esp_memprot_dram0_set_lock();
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+bool esp_memprot_get_lock(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_lock_reg() > 0;
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_lock_reg() > 0;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+bool esp_memprot_is_locked_any()
+{
+    return esp_memprot_iram0_get_lock_reg() > 0 || esp_memprot_iram0_get_lock_reg() > 0;
+}
+
+uint32_t esp_memprot_get_lock_bit(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_lock_bit();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_lock_bit();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+uint32_t esp_memprot_get_ena_reg(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_ena_reg();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_ena_reg();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+uint32_t esp_memprot_get_fault_reg(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_fault_reg();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_fault_reg();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+void esp_memprot_get_fault_status(mem_type_prot_t mem_type, uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        esp_memprot_iram0_get_fault_status(faulting_address, op_type, op_subtype);
+        break;
+    case MEMPROT_DRAM0:
+        esp_memprot_dram0_get_fault_status(faulting_address, op_type, op_subtype);
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+bool esp_memprot_is_intr_ena_any()
+{
+    return esp_memprot_iram0_get_intr_ena_bit() > 0 || esp_memprot_dram0_get_intr_ena_bit() > 0;
+}
+
+uint32_t esp_memprot_get_intr_ena_bit(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_intr_ena_bit();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_intr_ena_bit();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+uint32_t esp_memprot_get_intr_on_bit(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_intr_on_bit();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_intr_on_bit();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+uint32_t esp_memprot_get_intr_clr_bit(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_intr_clr_bit();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_intr_clr_bit();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+uint32_t esp_memprot_get_uni_block_read_bit(mem_type_prot_t mem_type, uint32_t block)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_uni_block_read_bit(block);
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_uni_block_read_bit(block);
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+uint32_t esp_memprot_get_uni_block_write_bit(mem_type_prot_t mem_type, uint32_t block)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_uni_block_write_bit(block);
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_uni_block_write_bit(block);
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+uint32_t esp_memprot_get_uni_block_exec_bit(mem_type_prot_t mem_type, uint32_t block)
+{
+    assert(mem_type == MEMPROT_IRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_uni_block_exec_bit(block);
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+void esp_memprot_set_uni_block_perm_dram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm)
+{
+    assert(mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_DRAM0:
+        esp_memprot_dram0_set_uni_block_perm(block, write_perm, read_perm);
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+uint32_t esp_memprot_get_perm_uni_reg(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_perm_uni_reg();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_perm_reg();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+uint32_t esp_memprot_get_perm_split_reg(mem_type_prot_t mem_type)
+{
+    assert(mem_type == MEMPROT_IRAM0 || mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        return esp_memprot_iram0_get_perm_split_reg();
+    case MEMPROT_DRAM0:
+        return esp_memprot_dram0_get_perm_reg();
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+void esp_memprot_set_prot_dram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr)
+{
+    assert(mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_DRAM0:
+        esp_memprot_dram0_set_prot(split_addr != NULL ? split_addr : esp_memprot_dram0_get_min_split_addr(), lw, lr, hw, hr);
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+void esp_memprot_set_uni_block_perm_iram(mem_type_prot_t mem_type, uint32_t block, bool write_perm, bool read_perm, bool exec_perm)
+{
+    assert(mem_type == MEMPROT_IRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        esp_memprot_iram0_set_uni_block_perm(block, write_perm, read_perm, exec_perm);
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+void esp_memprot_set_prot_iram(mem_type_prot_t mem_type, uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx)
+{
+    assert(mem_type == MEMPROT_IRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        esp_memprot_iram0_set_prot(split_addr != NULL ? split_addr : esp_memprot_iram0_get_min_split_addr(), lw, lr, lx, hw, hr, hx);
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+void esp_memprot_get_perm_split_bits_iram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx)
+{
+    assert(mem_type == MEMPROT_IRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_IRAM0:
+        esp_memprot_iram0_get_split_sgnf_bits(lw, lr, lx, hw, hr, hx);
+        break;
+    default:
+        assert(0);
+    }
+}
+
+void esp_memprot_get_perm_split_bits_dram(mem_type_prot_t mem_type, bool *lw, bool *lr, bool *hw, bool *hr)
+{
+    assert(mem_type == MEMPROT_DRAM0);
+
+    switch (mem_type) {
+    case MEMPROT_DRAM0:
+        esp_memprot_dram0_get_split_sgnf_bits(lw, lr, hw, hr);
+        break;
+    default:
+        ESP_LOGE(TAG, "Invalid mem_type %d", mem_type);
+        abort();
+    }
+}
+
+void esp_memprot_set_prot(bool invoke_panic_handler, bool lock_feature)
+{
+    esp_memprot_intr_ena(MEMPROT_DRAM0, false);
+    esp_memprot_intr_ena(MEMPROT_IRAM0, false);
+
+    if (!esp_cpu_in_ocd_debug_mode()) {
+
+        ESP_FAULT_ASSERT(!esp_cpu_in_ocd_debug_mode());
+
+        if ( invoke_panic_handler ) {
+            esp_memprot_intr_init(MEMPROT_DRAM0);
+            esp_memprot_intr_init(MEMPROT_IRAM0);
+        }
+
+        esp_memprot_set_prot_dram(MEMPROT_DRAM0, NULL, false, true, true, true);
+        esp_memprot_set_prot_iram(MEMPROT_IRAM0, NULL, false, true, true, true, true, false);
+
+        esp_memprot_intr_ena(MEMPROT_DRAM0, true);
+        esp_memprot_intr_ena(MEMPROT_IRAM0, true);
+
+        if ( lock_feature ) {
+            esp_memprot_set_lock(MEMPROT_DRAM0);
+            esp_memprot_set_lock(MEMPROT_IRAM0);
+        }
+    }
+}
+

+ 2 - 2
components/esp_system/port/esp32/dport_panic_highint_hdl.S

@@ -77,11 +77,11 @@ xt_highint4:
     /* Figure out reason, save into EXCCAUSE reg */
 
     rsr     a0, INTERRUPT
-    extui   a0, a0, ETS_CACHEERR_INUM, 1 /* get cacheerr int bit */
+    extui   a0, a0, ETS_MEMACCESS_ERR_INUM, 1 /* get cacheerr int bit */
     beqz    a0, 1f
     /* Kill this interrupt; we cannot reset it. */
     rsr     a0, INTENABLE
-    movi    a4, ~(1<<ETS_CACHEERR_INUM)
+    movi    a4, ~(1<<ETS_MEMACCESS_ERR_INUM)
     and     a0, a4, a0
     wsr     a0, INTENABLE
     movi    a0, PANIC_RSN_CACHEERR

+ 2 - 2
components/esp_system/port/esp32s2/dport_panic_highint_hdl.S

@@ -61,11 +61,11 @@ xt_highint4:
     /* Figure out reason, save into EXCCAUSE reg */
 
     rsr     a0, INTERRUPT
-    extui   a0, a0, ETS_CACHEERR_INUM, 1 /* get cacheerr int bit */
+    extui   a0, a0, ETS_MEMACCESS_ERR_INUM, 1 /* get cacheerr int bit */
     beqz    a0, 1f
     /* Kill this interrupt; we cannot reset it. */
     rsr     a0, INTENABLE
-    movi    a4, ~(1<<ETS_CACHEERR_INUM)
+    movi    a4, ~(1<<ETS_MEMACCESS_ERR_INUM)
     and     a0, a4, a0
     wsr     a0, INTENABLE
     movi    a0, PANIC_RSN_CACHEERR

+ 58 - 25
components/esp_system/port/panic_handler.c

@@ -43,6 +43,7 @@
 #elif CONFIG_IDF_TARGET_ESP32S2
 #include "esp32s2/cache_err_int.h"
 #include "esp32s2/rom/uart.h"
+#include "esp32s2/memprot.h"
 #include "soc/extmem_reg.h"
 #include "soc/cache_memory.h"
 #include "soc/rtc_cntl_reg.h"
@@ -50,11 +51,11 @@
 
 #include "panic_internal.h"
 
-extern void esp_panic_handler(panic_info_t*);
+extern void esp_panic_handler(panic_info_t *);
 
 static wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
 
-static XtExcFrame* xt_exc_frames[SOC_CPU_CORES_NUM] = {NULL};
+static XtExcFrame *xt_exc_frames[SOC_CPU_CORES_NUM] = {NULL};
 
 /*
   Panic handlers; these get called when an unhandled exception occurs or the assembly-level
@@ -65,9 +66,9 @@ static XtExcFrame* xt_exc_frames[SOC_CPU_CORES_NUM] = {NULL};
 /*
   Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
 */
-static void print_illegal_instruction_details(const void* f)
+static void print_illegal_instruction_details(const void *f)
 {
-    XtExcFrame* frame  = (XtExcFrame*) f;
+    XtExcFrame *frame  = (XtExcFrame *) f;
     /* Print out memory around the instruction word */
     uint32_t epc = frame->pc;
     epc = (epc & ~0x3) - 4;
@@ -76,7 +77,7 @@ static void print_illegal_instruction_details(const void* f)
     if (epc < SOC_IROM_MASK_LOW || epc >= SOC_IROM_HIGH) {
         return;
     }
-    volatile uint32_t* pepc = (uint32_t*)epc;
+    volatile uint32_t *pepc = (uint32_t *)epc;
 
     panic_print_str("Memory dump at 0x");
     panic_print_hex(epc);
@@ -89,7 +90,7 @@ static void print_illegal_instruction_details(const void* f)
     panic_print_hex(*(pepc + 2));
 }
 
-static void print_debug_exception_details(const void* f)
+static void print_debug_exception_details(const void *f)
 {
     int debug_rsn;
     asm("rsr.debugcause %0":"=r"(debug_rsn));
@@ -144,9 +145,9 @@ static void print_backtrace_entry(uint32_t pc, uint32_t sp)
     panic_print_hex(sp);
 }
 
-static void print_backtrace(const void* f, int core)
+static void print_backtrace(const void *f, int core)
 {
-    XtExcFrame *frame = (XtExcFrame*) f;
+    XtExcFrame *frame = (XtExcFrame *) f;
     int depth = 100;
     //Initialize stk_frame with first frame of stack
     esp_backtrace_frame_t stk_frame = {.pc = frame->pc, .sp = frame->a1, .next_pc = frame->a0};
@@ -155,7 +156,7 @@ static void print_backtrace(const void* f, int core)
 
     //Check if first frame is valid
     bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) &&
-                     esp_ptr_executable((void*)esp_cpu_process_stack_pc(stk_frame.pc)));
+                       esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)));
 
     uint32_t i = ((depth <= 0) ? INT32_MAX : depth) - 1;    //Account for stack frame that's already printed
     while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) {
@@ -176,7 +177,7 @@ static void print_backtrace(const void* f, int core)
 
 static void print_registers(const void *f, int core)
 {
-    XtExcFrame* frame = (XtExcFrame*) f;
+    XtExcFrame *frame = (XtExcFrame *) f;
     int *regs = (int *)frame;
     int x, y;
     const char *sdesc[] = {
@@ -207,10 +208,10 @@ static void print_registers(const void *f, int core)
     // If the core which triggers the interrupt watchpoint was in ISR context, dump the epc registers.
     if (xPortInterruptedFromISRContext()
 #if !CONFIG_FREERTOS_UNICORE
-        && ((core == 0 && frame->exccause == PANIC_RSN_INTWDT_CPU0) ||
-           (core == 1 && frame->exccause == PANIC_RSN_INTWDT_CPU1))
+            && ((core == 0 && frame->exccause == PANIC_RSN_INTWDT_CPU0) ||
+                (core == 1 && frame->exccause == PANIC_RSN_INTWDT_CPU1))
 #endif //!CONFIG_FREERTOS_UNICORE
-        ) {
+       ) {
 
         panic_print_str("\r\n");
 
@@ -246,7 +247,7 @@ static void print_state_for_core(const void *f, int core)
     print_backtrace(f, core);
 }
 
-static void print_state(const void* f)
+static void print_state(const void *f)
 {
 #if !CONFIG_FREERTOS_UNICORE
     int err_core = f == xt_exc_frames[0] ? 0 : 1;
@@ -271,7 +272,7 @@ static void print_state(const void* f)
 }
 
 #if CONFIG_IDF_TARGET_ESP32S2
-static inline void print_cache_err_details(const void* f)
+static inline void print_cache_err_details(const void *f)
 {
     uint32_t vaddr = 0, size = 0;
     uint32_t status[2];
@@ -357,9 +358,27 @@ static inline void print_cache_err_details(const void* f)
         }
     }
 }
+
+static inline void print_memprot_err_details(const void *f)
+{
+    uint32_t *fault_addr;
+    uint32_t op_type, op_subtype;
+    mem_type_prot_t mem_type = esp_memprot_get_intr_memtype();
+    esp_memprot_get_fault_status( mem_type, &fault_addr, &op_type, &op_subtype );
+
+    char *operation_type = "Write";
+    if ( op_type == 0 ) {
+        operation_type = (mem_type == MEMPROT_IRAM0 && op_subtype == 0) ? "Instruction fetch" : "Read";
+    }
+
+    panic_print_str( operation_type );
+    panic_print_str( " operation at address 0x" );
+    panic_print_hex( (uint32_t)fault_addr );
+    panic_print_str(" not permitted.\r\n");
+}
 #endif
 
-static void frame_to_panic_info(XtExcFrame *frame, panic_info_t* info, bool pseudo_excause)
+static void frame_to_panic_info(XtExcFrame *frame, panic_info_t *info, bool pseudo_excause)
 {
     info->core = cpu_hal_get_core_id();
     info->exception = PANIC_EXCEPTION_FAULT;
@@ -405,8 +424,13 @@ static void frame_to_panic_info(XtExcFrame *frame, panic_info_t* info, bool pseu
         }
 
 #if CONFIG_IDF_TARGET_ESP32S2
-        if(frame->exccause == PANIC_RSN_CACHEERR) {
-            info->details = print_cache_err_details;
+        if (frame->exccause == PANIC_RSN_CACHEERR) {
+            if ( esp_memprot_is_assoc_intr_any() ) {
+                info->details = print_memprot_err_details;
+                info->reason = "Memory protection fault";
+            } else {
+                info->details = print_cache_err_details;
+            }
         }
 #endif
     } else {
@@ -437,7 +461,7 @@ static void frame_to_panic_info(XtExcFrame *frame, panic_info_t* info, bool pseu
     }
 
     info->state = print_state;
-    info->addr = ((void*) ((XtExcFrame*) frame)->pc);
+    info->addr = ((void *) ((XtExcFrame *) frame)->pc);
     info->frame = frame;
 }
 
@@ -456,7 +480,7 @@ static void panic_handler(XtExcFrame *frame, bool pseudo_excause)
     // These are cases where both CPUs both go into panic handler. The following code ensures
     // only one core proceeds to the system panic handler.
     if (pseudo_excause) {
-        #define BUSY_WAIT_IF_TRUE(b)                { if (b) while(1); }
+#define BUSY_WAIT_IF_TRUE(b)                { if (b) while(1); }
         // For WDT expiry, pause the non-offending core - offending core handles panic
         BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_INTWDT_CPU0 && core_id == 1);
         BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_INTWDT_CPU1 && core_id == 0);
@@ -483,7 +507,7 @@ static void panic_handler(XtExcFrame *frame, bool pseudo_excause)
 
     if (esp_cpu_in_ocd_debug_mode()) {
         if (frame->exccause == PANIC_RSN_INTWDT_CPU0 ||
-            frame->exccause == PANIC_RSN_INTWDT_CPU1) {
+                frame->exccause == PANIC_RSN_INTWDT_CPU1) {
             wdt_hal_write_protect_disable(&wdt0_context);
             wdt_hal_handle_intr(&wdt0_context);
             wdt_hal_write_protect_enable(&wdt0_context);
@@ -536,9 +560,18 @@ void __attribute__((noreturn)) panic_restart(void)
     // If resetting because of a cache error, reset the digital part
     // Make sure that the reset reason is not a generic panic reason as well on ESP32S2,
     // as esp_cache_err_get_cpuid always returns PRO_CPU_NUM
-    if (esp_cache_err_get_cpuid() != -1 && esp_reset_reason_get_hint() != ESP_RST_PANIC) {
+
+    bool digital_reset_needed = false;
+    if ( esp_cache_err_get_cpuid() != -1 && esp_reset_reason_get_hint() != ESP_RST_PANIC ) {
+        digital_reset_needed = true;
+    }
+#if CONFIG_IDF_TARGET_ESP32S2
+    if ( esp_memprot_is_intr_ena_any() || esp_memprot_is_locked_any() ) {
+        digital_reset_needed = true;
+    }
+#endif
+    if ( digital_reset_needed ) {
         esp_digital_reset();
-    } else {
-        esp_restart_noos();
     }
-}
+    esp_restart_noos();
+}

+ 31 - 2
components/esp_system/system_api.c

@@ -4,6 +4,13 @@
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 
+#if CONFIG_IDF_TARGET_ESP32S2
+#include "soc/rtc.h"
+#include "soc/rtc_cntl_reg.h"
+#include "esp32s2/rom/uart.h"
+#include "esp32s2/memprot.h"
+#endif
+
 #include "esp_system.h"
 #include "panic_internal.h"
 
@@ -34,6 +41,23 @@ esp_err_t esp_unregister_shutdown_handler(shutdown_handler_t handler)
     return ESP_ERR_INVALID_STATE;
 }
 
+#if CONFIG_IDF_TARGET_ESP32S2
+static __attribute__((noreturn)) void esp_digital_reset(void)
+{
+    // make sure all the panic handler output is sent from UART FIFO
+    uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM);
+    // switch to XTAL (otherwise we will keep running from the PLL)
+
+    rtc_clk_cpu_freq_set_xtal();
+
+    // reset the digital part
+    SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
+    while (true) {
+        ;
+    }
+}
+#endif
+
 void IRAM_ATTR esp_restart(void)
 {
     for (int i = SHUTDOWN_HANDLERS_NO - 1; i >= 0; i--) {
@@ -45,6 +69,11 @@ void IRAM_ATTR esp_restart(void)
     // Disable scheduler on this core.
     vTaskSuspendAll();
 
+#if CONFIG_IDF_TARGET_ESP32S2
+    if ( esp_memprot_is_intr_ena_any() || esp_memprot_is_locked_any()) {
+        esp_digital_reset();
+    }
+#endif
     esp_restart_noos();
 }
 
@@ -58,12 +87,12 @@ uint32_t esp_get_minimum_free_heap_size( void )
     return heap_caps_get_minimum_free_size( MALLOC_CAP_DEFAULT );
 }
 
-const char* esp_get_idf_version(void)
+const char *esp_get_idf_version(void)
 {
     return IDF_VER;
 }
 
-void __attribute__((noreturn)) esp_system_abort(const char* details)
+void __attribute__((noreturn)) esp_system_abort(const char *details)
 {
     panic_abort(details);
 }

+ 2 - 0
components/heap/test/test_malloc_caps.c

@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <sys/param.h>
 
+#ifndef CONFIG_ESP32S2_MEMPROT_FEATURE
 TEST_CASE("Capabilities allocator test", "[heap]")
 {
     char *m1, *m2[10];
@@ -100,6 +101,7 @@ TEST_CASE("Capabilities allocator test", "[heap]")
     free(m1);
     printf("Done.\n");
 }
+#endif
 
 #ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
 TEST_CASE("IRAM_8BIT capability test", "[heap]")

+ 4 - 2
components/heap/test/test_realloc.c

@@ -14,7 +14,7 @@
 /* (can't realloc in place if comprehensive is enabled) */
 
 TEST_CASE("realloc shrink buffer in place", "[heap]")
-{    
+{
     void *x = malloc(64);
     TEST_ASSERT(x);
     void *y = realloc(x, 48);
@@ -23,6 +23,7 @@ TEST_CASE("realloc shrink buffer in place", "[heap]")
 
 #endif
 
+#ifndef CONFIG_ESP32S2_MEMPROT_FEATURE
 TEST_CASE("realloc shrink buffer with EXEC CAPS", "[heap]")
 {
     const size_t buffer_size = 64;
@@ -52,7 +53,7 @@ TEST_CASE("realloc move data to a new heap type", "[heap]")
     TEST_ASSERT_NOT_NULL(b);
     TEST_ASSERT_NOT_EQUAL(a, b);
     TEST_ASSERT(heap_caps_check_integrity(MALLOC_CAP_INVALID, true));
-    TEST_ASSERT_EQUAL_HEX32_ARRAY(buf, b, 64/sizeof(uint32_t));
+    TEST_ASSERT_EQUAL_HEX32_ARRAY(buf, b, 64 / sizeof(uint32_t));
 
     // Move data back to DRAM
     char *c = heap_caps_realloc(b, 48, MALLOC_CAP_8BIT);
@@ -63,3 +64,4 @@ TEST_CASE("realloc move data to a new heap type", "[heap]")
 
     free(c);
 }
+#endif

+ 5 - 1
components/heap/test/test_runtime_heap_reg.c

@@ -30,8 +30,12 @@ TEST_CASE("Allocate new heap at runtime", "[heap][ignore]")
 TEST_CASE("Allocate new heap with new capability", "[heap][ignore]")
 {
     const size_t BUF_SZ = 100;
+#ifdef CONFIG_ESP32S2_MEMPROT_FEATURE
+    const size_t ALLOC_SZ = 32;
+#else
     const size_t ALLOC_SZ = 64; // More than half of BUF_SZ
-    const uint32_t MALLOC_CAP_INVENTED = (1<<30); /* this must be unused in esp_heap_caps.h */
+#endif
+    const uint32_t MALLOC_CAP_INVENTED = (1 << 30); /* this must be unused in esp_heap_caps.h */
 
     /* no memory exists to provide this capability */
     TEST_ASSERT_NULL( heap_caps_malloc(ALLOC_SZ, MALLOC_CAP_INVENTED) );

+ 3 - 1
components/soc/soc/esp32/include/soc/soc.h

@@ -398,7 +398,9 @@
 #define ETS_TG0_T1_INUM                         10 /**< use edge interrupt*/
 #define ETS_FRC1_INUM                           22
 #define ETS_T1_WDT_INUM                         24
-#define ETS_CACHEERR_INUM                       25
+#define ETS_MEMACCESS_ERR_INUM                  25
+/* backwards compatibility only, use ETS_MEMACCESS_ERR_INUM instead*/
+#define ETS_CACHEERR_INUM                       ETS_MEMACCESS_ERR_INUM
 #define ETS_DPORT_INUM                          28
 
 //CPU0 Interrupt number used in ROM, should be cancelled in SDK

+ 1 - 1
components/soc/soc/esp32s2/include/soc/soc.h

@@ -336,7 +336,7 @@
 #define ETS_TG0_T1_INUM                         10 /**< use edge interrupt*/
 #define ETS_FRC1_INUM                           22
 #define ETS_T1_WDT_INUM                         24
-#define ETS_CACHEERR_INUM                       25
+#define ETS_MEMACCESS_ERR_INUM                  25
 #define ETS_DPORT_INUM                          28
 
 //CPU0 Interrupt number used in ROM, should be cancelled in SDK

+ 651 - 0
components/soc/src/esp32s2/include/hal/memprot_ll.h

@@ -0,0 +1,651 @@
+// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * === IRAM0 ====
+ */
+
+#define IRAM0_TOTAL_UNI_BLOCKS          4
+#define IRAM0_UNI_BLOCK_0               0
+#define IRAM0_UNI_BLOCK_1               1
+#define IRAM0_UNI_BLOCK_2               2
+#define IRAM0_UNI_BLOCK_3               3
+
+#define IRAM0_SPL_BLOCK_BASE            0x40000000
+
+//unified management (SRAM blocks 0-3)
+#define IRAM0_UNI_BLOCK_0_LOW           0x40020000
+#define IRAM0_UNI_BLOCK_0_HIGH          0x40021FFF
+#define IRAM0_UNI_BLOCK_1_LOW           0x40022000
+#define IRAM0_UNI_BLOCK_1_HIGH          0x40023FFF
+#define IRAM0_UNI_BLOCK_2_LOW           0x40024000
+#define IRAM0_UNI_BLOCK_2_HIGH          0x40025FFF
+#define IRAM0_UNI_BLOCK_3_LOW           0x40026000
+#define IRAM0_UNI_BLOCK_3_HIGH          0x40027FFF
+
+//split management (SRAM blocks 4-21)
+#define IRAM0_SPL_BLOCK_LOW             0x40028000 //block 4 low
+#define IRAM0_SPL_BLOCK_HIGH            0x4006FFFF //block 21 high
+#define IRAM0_SPLTADDR_MIN              0x40030000 //block 6 low - minimum splitting address
+
+//IRAM0 interrupt status bitmasks
+#define IRAM0_INTR_ST_FAULTADDR_M       0x003FFFFC  //(bits 21:6 in the reg, as well as in real address)
+#define IRAM0_INTR_ST_FAULTADDR_HI      0x40000000  //(high nonsignificant bits 31:22 of the faulting address - constant)
+#define IRAM0_INTR_ST_OP_TYPE_BIT       BIT(1)      //instruction: 0, data: 1
+#define IRAM0_INTR_ST_OP_RW_BIT         BIT(0)      //read: 0, write: 1
+
+
+static inline uint32_t esp_memprot_iram0_get_intr_source_num(void)
+{
+    return ETS_PMS_PRO_IRAM0_ILG_INTR_SOURCE;
+}
+
+static inline void esp_memprot_iram0_intr_ena(bool enable)
+{
+    if ( enable ) {
+        DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN );
+    } else {
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN );
+    }
+}
+
+static inline uint32_t esp_memprot_iram0_get_ena_reg(void)
+{
+    return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_4_REG);
+}
+
+static inline uint32_t esp_memprot_iram0_get_fault_reg(void)
+{
+    return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_5_REG);
+}
+
+static inline void esp_memprot_iram0_get_fault_status(uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype)
+{
+    uint32_t status_bits = esp_memprot_iram0_get_fault_reg();
+
+    uint32_t fault_addr = (status_bits & IRAM0_INTR_ST_FAULTADDR_M);
+    *faulting_address = (uint32_t *)(fault_addr | IRAM0_INTR_ST_FAULTADDR_HI);
+
+    *op_type = (uint32_t)status_bits & IRAM0_INTR_ST_OP_RW_BIT;
+    *op_subtype = (uint32_t)status_bits & IRAM0_INTR_ST_OP_TYPE_BIT;
+}
+
+static inline bool esp_memprot_iram0_is_assoc_intr(void)
+{
+    return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_INTR) > 0;
+}
+
+static inline void esp_memprot_iram0_clear_intr(void)
+{
+    DPORT_SET_PERI_REG_MASK(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_CLR);
+}
+
+static inline uint32_t esp_memprot_iram0_get_intr_ena_bit(void)
+{
+    return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_EN);
+}
+
+static inline uint32_t esp_memprot_iram0_get_intr_on_bit(void)
+{
+    return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_INTR);
+}
+
+static inline uint32_t esp_memprot_iram0_get_intr_clr_bit(void)
+{
+    return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_4_REG, DPORT_PMS_PRO_IRAM0_ILG_CLR);
+}
+
+//resets automatically on CPU restart
+static inline void esp_memprot_iram0_set_lock(void)
+{
+    DPORT_WRITE_PERI_REG( DPORT_PMS_PRO_IRAM0_0_REG, DPORT_PMS_PRO_IRAM0_LOCK);
+}
+
+static inline uint32_t esp_memprot_iram0_get_lock_reg(void)
+{
+    return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_0_REG);
+}
+
+static inline uint32_t esp_memprot_iram0_get_lock_bit(void)
+{
+    return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_IRAM0_0_REG, DPORT_PMS_PRO_IRAM0_LOCK);
+}
+
+//block 0-3
+static inline void esp_memprot_iram0_set_uni_block_perm(uint32_t block, bool write_perm, bool read_perm, bool exec_perm)
+{
+    assert(block < IRAM0_TOTAL_UNI_BLOCKS);
+
+    uint32_t write_bit, read_bit, exec_bit;
+    switch ( block ) {
+    case IRAM0_UNI_BLOCK_0:
+        write_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_W;
+        read_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_R;
+        exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_F;
+        break;
+    case IRAM0_UNI_BLOCK_1:
+        write_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_W;
+        read_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_R;
+        exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_F;
+        break;
+    case IRAM0_UNI_BLOCK_2:
+        write_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_W;
+        read_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_R;
+        exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_F;
+        break;
+    case IRAM0_UNI_BLOCK_3:
+        write_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_W;
+        read_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_R;
+        exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_F;
+        break;
+    default:
+        abort();
+    }
+
+    if ( write_perm ) {
+        DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, write_bit );
+    } else {
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, write_bit );
+    }
+
+    if ( read_perm ) {
+        DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, read_bit );
+    } else {
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, read_bit );
+    }
+
+    if ( exec_perm ) {
+        DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, exec_bit );
+    } else {
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_IRAM0_1_REG, exec_bit );
+    }
+}
+
+static inline uint32_t esp_memprot_iram0_get_uni_block_read_bit(uint32_t block)
+{
+    assert(block < IRAM0_TOTAL_UNI_BLOCKS);
+
+    switch ( block ) {
+    case IRAM0_UNI_BLOCK_0:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_R );
+    case IRAM0_UNI_BLOCK_1:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_R );
+    case IRAM0_UNI_BLOCK_2:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_R );
+    case IRAM0_UNI_BLOCK_3:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_R );
+    default:
+        abort();
+    }
+}
+
+static inline uint32_t esp_memprot_iram0_get_uni_block_write_bit(uint32_t block)
+{
+    assert(block < IRAM0_TOTAL_UNI_BLOCKS);
+
+    switch ( block ) {
+    case IRAM0_UNI_BLOCK_0:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_W );
+    case IRAM0_UNI_BLOCK_1:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_W );
+    case IRAM0_UNI_BLOCK_2:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_W );
+    case IRAM0_UNI_BLOCK_3:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_W );
+    default:
+        abort();
+    }
+}
+
+static inline uint32_t esp_memprot_iram0_get_uni_block_exec_bit(uint32_t block)
+{
+    assert(block < IRAM0_TOTAL_UNI_BLOCKS);
+
+    switch ( block ) {
+    case IRAM0_UNI_BLOCK_0:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_0_F );
+    case IRAM0_UNI_BLOCK_1:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_1_F );
+    case IRAM0_UNI_BLOCK_2:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_2_F );
+    case IRAM0_UNI_BLOCK_3:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_1_REG, DPORT_PMS_PRO_IRAM0_SRAM_3_F );
+    default:
+        abort();
+    }
+}
+
+static inline void esp_memprot_iram0_get_uni_block_sgnf_bits(uint32_t block, uint32_t *write_bit, uint32_t *read_bit, uint32_t *exec_bit)
+{
+    assert(block < IRAM0_TOTAL_UNI_BLOCKS);
+
+    switch ( block ) {
+    case IRAM0_UNI_BLOCK_0:
+        *write_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_W;
+        *read_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_R;
+        *exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_0_F;
+        break;
+    case IRAM0_UNI_BLOCK_1:
+        *write_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_W;
+        *read_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_R;
+        *exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_1_F;
+        break;
+    case IRAM0_UNI_BLOCK_2:
+        *write_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_W;
+        *read_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_R;
+        *exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_2_F;
+        break;
+    case IRAM0_UNI_BLOCK_3:
+        *write_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_W;
+        *read_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_R;
+        *exec_bit = DPORT_PMS_PRO_IRAM0_SRAM_3_F;
+        break;
+    default:
+        abort();
+    }
+}
+
+static inline uint32_t esp_memprot_iram0_get_perm_uni_reg(void)
+{
+    return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_1_REG);
+}
+
+static inline uint32_t esp_memprot_iram0_get_perm_split_reg(void)
+{
+    return DPORT_READ_PERI_REG(DPORT_PMS_PRO_IRAM0_2_REG);
+}
+
+static inline void esp_memprot_iram0_set_prot(uint32_t *split_addr, bool lw, bool lr, bool lx, bool hw, bool hr, bool hx)
+{
+    uint32_t addr = (uint32_t)split_addr;
+    assert( addr <= IRAM0_SPL_BLOCK_HIGH );
+
+    //find possible split.address in low region blocks
+    int uni_blocks_low = -1;
+    if ( addr >= IRAM0_UNI_BLOCK_0_LOW ) {
+        uni_blocks_low++;
+    }
+    if ( addr >= IRAM0_UNI_BLOCK_1_LOW ) {
+        uni_blocks_low++;
+    }
+    if ( addr >= IRAM0_UNI_BLOCK_2_LOW ) {
+        uni_blocks_low++;
+    }
+    if ( addr >= IRAM0_UNI_BLOCK_3_LOW ) {
+        uni_blocks_low++;
+    }
+
+    //unified mgmt settings per block (bits W/R/X: [11:9] bl3, [8:6] bl2, [5:3] bl1, [2:0] bl0)
+    uint32_t write_bit, read_bit, exec_bit;
+    uint32_t uni_block_perm = 0;
+
+    for ( size_t x = 0; x < IRAM0_TOTAL_UNI_BLOCKS; x++ ) {
+        esp_memprot_iram0_get_uni_block_sgnf_bits(x, &write_bit, &read_bit, &exec_bit);
+        if ( x <= uni_blocks_low ) {
+            if (lw) {
+                uni_block_perm |= write_bit;
+            }
+            if (lr) {
+                uni_block_perm |= read_bit;
+            }
+            if (lx) {
+                uni_block_perm |= exec_bit;
+            }
+        } else {
+            if (hw) {
+                uni_block_perm |= write_bit;
+            }
+            if (hr) {
+                uni_block_perm |= read_bit;
+            }
+            if (hx) {
+                uni_block_perm |= exec_bit;
+            }
+        }
+    }
+
+    //if splt.ddr not set yet, do required normalization to make the addr writeble into splt.mgmt cfg register
+    uint32_t reg_split_addr = 0;
+
+    if ( addr >= IRAM0_SPL_BLOCK_LOW ) {
+
+        //split Address must be WORD aligned
+        reg_split_addr = addr >> 2;
+        assert(addr == (reg_split_addr << 2));
+
+        //use only 17 signf.bits as the cropped parts are constant for whole section (bits [16:0])
+        reg_split_addr = (reg_split_addr << DPORT_PMS_PRO_IRAM0_SRAM_4_SPLTADDR_S) & DPORT_PMS_PRO_IRAM0_SRAM_4_SPLTADDR_M;
+    }
+
+    //prepare high & low permission mask (bits: [22:20] high range, [19:17] low range)
+    uint32_t permission_mask = 0;
+    if ( lw ) {
+        permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_L_W;
+    }
+    if ( lr ) {
+        permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_L_R;
+    }
+    if ( lx ) {
+        permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_L_F;
+    }
+    if ( hw ) {
+        permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_H_W;
+    }
+    if ( hr ) {
+        permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_H_R;
+    }
+    if ( hx ) {
+        permission_mask |= DPORT_PMS_PRO_IRAM0_SRAM_4_H_F;
+    }
+
+    //write both cfg. registers
+    DPORT_WRITE_PERI_REG( DPORT_PMS_PRO_IRAM0_1_REG, uni_block_perm );
+    DPORT_WRITE_PERI_REG( DPORT_PMS_PRO_IRAM0_2_REG, reg_split_addr | permission_mask );
+}
+
+static inline void esp_memprot_iram0_get_split_sgnf_bits(bool *lw, bool *lr, bool *lx, bool *hw, bool *hr, bool *hx)
+{
+    *lw = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_W );
+    *lr = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_R );
+    *lx = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_L_F );
+    *hw = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_W );
+    *hr = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_R );
+    *hx = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_IRAM0_2_REG, DPORT_PMS_PRO_IRAM0_SRAM_4_H_F );
+}
+
+/**
+ * === DRAM0 ====
+ */
+
+#define DRAM0_TOTAL_UNI_BLOCKS          4
+#define DRAM0_UNI_BLOCK_0               0
+#define DRAM0_UNI_BLOCK_1               1
+#define DRAM0_UNI_BLOCK_2               2
+#define DRAM0_UNI_BLOCK_3               3
+
+#define DRAM0_SPL_BLOCK_BASE            0x3FFB0000
+
+//unified management (SRAM blocks 0-3)
+#define DRAM0_UNI_BLOCK_0_LOW           0x3FFB0000
+#define DRAM0_UNI_BLOCK_0_HIGH          0x3FFB1FFF
+#define DRAM0_UNI_BLOCK_1_LOW           0x3FFB2000
+#define DRAM0_UNI_BLOCK_1_HIGH          0x3FFB3FFF
+#define DRAM0_UNI_BLOCK_2_LOW           0x3FFB4000
+#define DRAM0_UNI_BLOCK_2_HIGH          0x3FFB5FFF
+#define DRAM0_UNI_BLOCK_3_LOW           0x3FFB6000
+#define DRAM0_UNI_BLOCK_3_HIGH          0x3FFB7FFF
+
+//split management (SRAM blocks 4-21)
+#define DRAM0_SPL_BLOCK_LOW             0x3FFB8000  //block 4 low
+#define DRAM0_SPL_BLOCK_HIGH            0x3FFFFFFF  //block 21 high
+#define DRAM0_SPLTADDR_MIN              0x3FFC0000  //block 6 low - minimum splitting address
+
+//DRAM0 interrupt status bitmasks
+#define DRAM0_INTR_ST_FAULTADDR_M       0x03FFFFC0  //(bits 25:6 in the reg)
+#define DRAM0_INTR_ST_FAULTADDR_S       0x4         //(bits 21:2 of real address)
+#define DRAM0_INTR_ST_FAULTADDR_HI      0x3FF00000  //(high nonsignificant bits 31:22 of the faulting address - constant)
+#define DRAM0_INTR_ST_OP_RW_BIT         BIT(4)      //read: 0, write: 1
+#define DRAM0_INTR_ST_OP_ATOMIC_BIT     BIT(5)      //non-atomic: 0, atomic: 1
+
+
+static inline uint32_t esp_memprot_dram0_get_intr_source_num(void)
+{
+    return ETS_PMS_PRO_DRAM0_ILG_INTR_SOURCE;
+}
+
+static inline void esp_memprot_dram0_intr_ena(bool enable)
+{
+    if ( enable ) {
+        DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN );
+    } else {
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN );
+    }
+}
+
+static inline bool esp_memprot_dram0_is_assoc_intr(void)
+{
+    return DPORT_GET_PERI_REG_MASK(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_INTR) > 0;
+}
+
+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);
+}
+
+static inline uint32_t esp_memprot_dram0_get_intr_ena_bit(void)
+{
+    return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_EN);
+}
+
+static inline uint32_t esp_memprot_dram0_get_intr_on_bit(void)
+{
+    return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_INTR);
+}
+
+static inline uint32_t esp_memprot_dram0_get_intr_clr_bit(void)
+{
+    return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_3_REG, DPORT_PMS_PRO_DRAM0_ILG_CLR);
+}
+
+static inline uint32_t esp_memprot_dram0_get_lock_bit(void)
+{
+    return DPORT_REG_GET_FIELD(DPORT_PMS_PRO_DRAM0_0_REG, DPORT_PMS_PRO_DRAM0_LOCK);
+}
+
+static inline void esp_memprot_dram0_get_uni_block_sgnf_bits(uint32_t block, uint32_t *write_bit, uint32_t *read_bit)
+{
+    assert(block < DRAM0_TOTAL_UNI_BLOCKS);
+
+    switch ( block ) {
+    case DRAM0_UNI_BLOCK_0:
+        *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_0_W;
+        *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_0_R;
+        break;
+    case DRAM0_UNI_BLOCK_1:
+        *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_1_W;
+        *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_1_R;
+        break;
+    case DRAM0_UNI_BLOCK_2:
+        *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_2_W;
+        *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_2_R;
+        break;
+    case DRAM0_UNI_BLOCK_3:
+        *write_bit = DPORT_PMS_PRO_DRAM0_SRAM_3_W;
+        *read_bit = DPORT_PMS_PRO_DRAM0_SRAM_3_R;
+        break;
+    default:
+        abort();
+    }
+}
+
+static inline void esp_memprot_dram0_set_uni_block_perm(uint32_t block, bool write_perm, bool read_perm)
+{
+    assert(block < DRAM0_TOTAL_UNI_BLOCKS);
+
+    uint32_t write_bit, read_bit;
+    esp_memprot_dram0_get_uni_block_sgnf_bits(block, &write_bit, &read_bit);
+
+    if ( write_perm ) {
+        DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_1_REG, write_bit );
+    } else {
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_1_REG, write_bit );
+    }
+
+    if ( read_perm ) {
+        DPORT_SET_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_1_REG, read_bit );
+    } else {
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PMS_PRO_DRAM0_1_REG, read_bit );
+    }
+}
+
+static inline uint32_t esp_memprot_dram0_get_uni_block_read_bit(uint32_t block)
+{
+    assert(block < DRAM0_TOTAL_UNI_BLOCKS);
+
+    switch ( block ) {
+    case DRAM0_UNI_BLOCK_0:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_0_R );
+    case DRAM0_UNI_BLOCK_1:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_1_R );
+    case DRAM0_UNI_BLOCK_2:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_2_R );
+    case DRAM0_UNI_BLOCK_3:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_3_R );
+    default:
+        abort();
+    }
+}
+
+static inline uint32_t esp_memprot_dram0_get_uni_block_write_bit(uint32_t block)
+{
+    assert(block < DRAM0_TOTAL_UNI_BLOCKS);
+
+    switch ( block ) {
+    case DRAM0_UNI_BLOCK_0:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_0_W );
+    case DRAM0_UNI_BLOCK_1:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_1_W );
+    case DRAM0_UNI_BLOCK_2:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_2_W );
+    case DRAM0_UNI_BLOCK_3:
+        return DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_3_W );
+    default:
+        abort();
+    }
+}
+
+static inline uint32_t esp_memprot_dram0_get_lock_reg(void)
+{
+    return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_0_REG);
+}
+
+//lock resets automatically on CPU restart
+static inline void esp_memprot_dram0_set_lock(void)
+{
+    DPORT_WRITE_PERI_REG( DPORT_PMS_PRO_DRAM0_0_REG, DPORT_PMS_PRO_DRAM0_LOCK);
+}
+
+static inline uint32_t esp_memprot_dram0_get_perm_reg(void)
+{
+    return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_1_REG);
+}
+
+static inline uint32_t esp_memprot_dram0_get_ena_reg(void)
+{
+    return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_3_REG);
+}
+
+static inline uint32_t esp_memprot_dram0_get_fault_reg(void)
+{
+    return DPORT_READ_PERI_REG(DPORT_PMS_PRO_DRAM0_4_REG);
+}
+
+static inline void esp_memprot_dram0_get_fault_status(uint32_t **faulting_address, uint32_t *op_type, uint32_t *op_subtype)
+{
+    uint32_t status_bits = esp_memprot_dram0_get_fault_reg();
+
+    uint32_t fault_addr = (status_bits & DRAM0_INTR_ST_FAULTADDR_M) >> DRAM0_INTR_ST_FAULTADDR_S;
+    *faulting_address = (uint32_t *)(fault_addr | DRAM0_INTR_ST_FAULTADDR_HI);
+
+    *op_type = (uint32_t)status_bits & DRAM0_INTR_ST_OP_RW_BIT;
+    *op_subtype = (uint32_t)status_bits & DRAM0_INTR_ST_OP_ATOMIC_BIT;
+}
+
+static inline void esp_memprot_dram0_set_prot(uint32_t *split_addr, bool lw, bool lr, bool hw, bool hr)
+{
+    uint32_t addr = (uint32_t)split_addr;
+
+    //low boundary check provided by LD script. see comment in esp_memprot_iram0_set_prot()
+    assert( addr <= DRAM0_SPL_BLOCK_HIGH );
+
+    //set low region
+    int uni_blocks_low = -1;
+    if ( addr >= DRAM0_UNI_BLOCK_0_LOW ) {
+        uni_blocks_low++;
+    }
+    if ( addr >= DRAM0_UNI_BLOCK_1_LOW ) {
+        uni_blocks_low++;
+    }
+    if ( addr >= DRAM0_UNI_BLOCK_2_LOW ) {
+        uni_blocks_low++;
+    }
+    if ( addr >= DRAM0_UNI_BLOCK_3_LOW ) {
+        uni_blocks_low++;
+    }
+
+    //set unified mgmt region
+    uint32_t write_bit, read_bit, uni_block_perm = 0;
+    for ( size_t x = 0; x < DRAM0_TOTAL_UNI_BLOCKS; x++ ) {
+        esp_memprot_dram0_get_uni_block_sgnf_bits(x, &write_bit, &read_bit);
+        if ( x <= uni_blocks_low ) {
+            if (lw) {
+                uni_block_perm |= write_bit;
+            }
+            if (lr) {
+                uni_block_perm |= read_bit;
+            }
+        } else {
+            if (hw) {
+                uni_block_perm |= write_bit;
+            }
+            if (hr) {
+                uni_block_perm |= read_bit;
+            }
+        }
+    }
+
+    //check split address is WORD aligned
+    uint32_t reg_split_addr = addr >> 2;
+    assert(addr == (reg_split_addr << 2));
+
+    //shift aligned split address to proper bit offset
+    reg_split_addr = (reg_split_addr << DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_S) & DPORT_PMS_PRO_DRAM0_SRAM_4_SPLTADDR_M;
+
+    //prepare high & low permission mask
+    uint32_t permission_mask = 0;
+    if (lw) {
+        permission_mask |= DPORT_PMS_PRO_DRAM0_SRAM_4_L_W;
+    }
+    if (lr) {
+        permission_mask |= DPORT_PMS_PRO_DRAM0_SRAM_4_L_R;
+    }
+    if (hw) {
+        permission_mask |= DPORT_PMS_PRO_DRAM0_SRAM_4_H_W;
+    }
+    if (hr) {
+        permission_mask |= DPORT_PMS_PRO_DRAM0_SRAM_4_H_R;
+    }
+
+    //write configuration to DPORT_PMS_PRO_DRAM0_1_REG
+    DPORT_WRITE_PERI_REG(DPORT_PMS_PRO_DRAM0_1_REG, reg_split_addr | permission_mask | uni_block_perm);
+}
+
+static inline void esp_memprot_dram0_get_split_sgnf_bits(bool *lw, bool *lr, bool *hw, bool *hr)
+{
+    *lw = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_W );
+    *lr = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_L_R );
+    *hw = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_W );
+    *hr = DPORT_REG_GET_FIELD( DPORT_PMS_PRO_DRAM0_1_REG, DPORT_PMS_PRO_DRAM0_SRAM_4_H_R );
+}
+
+
+#ifdef __cplusplus
+}
+#endif

+ 33 - 27
components/soc/src/esp32s2/soc_memory_layout.c

@@ -53,6 +53,12 @@ const soc_memory_type_desc_t soc_memory_types[] = {
     { "SPIRAM", { MALLOC_CAP_SPIRAM|MALLOC_CAP_DEFAULT, 0, MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, false, false},
 };
 
+#ifdef CONFIG_ESP32S2_MEMPROT_FEATURE
+#define SOC_MEMORY_TYPE_DEFAULT 0
+#else
+#define SOC_MEMORY_TYPE_DEFAULT 2
+#endif
+
 const size_t soc_memory_type_count = sizeof(soc_memory_types)/sizeof(soc_memory_type_desc_t);
 
 /*
@@ -67,41 +73,41 @@ const soc_memory_region_t soc_memory_regions[] = {
 #endif
 #if CONFIG_ESP32S2_INSTRUCTION_CACHE_8KB
 #if CONFIG_ESP32S2_DATA_CACHE_0KB
-    { 0x3FFB2000, 0x2000, 2, 0x40022000}, //Block 1, can be use as I/D cache memory
-    { 0x3FFB4000, 0x2000, 2, 0x40024000}, //Block 2, can be use as D cache memory
-    { 0x3FFB6000, 0x2000, 2, 0x40026000}, //Block 3, can be use as D cache memory
+    { 0x3FFB2000, 0x2000, SOC_MEMORY_TYPE_DEFAULT, 0x40022000}, //Block 1, can be use as I/D cache memory
+    { 0x3FFB4000, 0x2000, SOC_MEMORY_TYPE_DEFAULT, 0x40024000}, //Block 2, can be use as D cache memory
+    { 0x3FFB6000, 0x2000, SOC_MEMORY_TYPE_DEFAULT, 0x40026000}, //Block 3, can be use as D cache memory
 #elif CONFIG_ESP32S2_DATA_CACHE_8KB
-    { 0x3FFB4000, 0x2000, 2, 0x40024000}, //Block 2, can be use as D cache memory
-    { 0x3FFB6000, 0x2000, 2, 0x40026000}, //Block 3, can be use as D cache memory
+    { 0x3FFB4000, 0x2000, SOC_MEMORY_TYPE_DEFAULT, 0x40024000}, //Block 2, can be use as D cache memory
+    { 0x3FFB6000, 0x2000, SOC_MEMORY_TYPE_DEFAULT, 0x40026000}, //Block 3, can be use as D cache memory
 #else
-    { 0x3FFB6000, 0x2000, 2, 0x40026000}, //Block 3, can be use as D cache memory
+    { 0x3FFB6000, 0x2000, SOC_MEMORY_TYPE_DEFAULT, 0x40026000}, //Block 3, can be use as D cache memory
 #endif
 #else
 #if CONFIG_ESP32S2_DATA_CACHE_0KB
-    { 0x3FFB4000, 0x2000, 2, 0x40024000}, //Block 2, can be use as D cache memory
-    { 0x3FFB6000, 0x2000, 2, 0x40026000}, //Block 3, can be use as D cache memory
+    { 0x3FFB4000, 0x2000, SOC_MEMORY_TYPE_DEFAULT, 0x40024000}, //Block SOC_MEMORY_TYPE_DEFAULT, can be use as D cache memory
+    { 0x3FFB6000, 0x2000, SOC_MEMORY_TYPE_DEFAULT, 0x40026000}, //Block 3, can be use as D cache memory
 #elif CONFIG_ESP32S2_DATA_CACHE_8KB
-    { 0x3FFB6000, 0x2000, 2, 0x40026000}, //Block 3, can be use as D cache memory
+    { 0x3FFB6000, 0x2000, SOC_MEMORY_TYPE_DEFAULT, 0x40026000}, //Block 3, can be use as D cache memory
 #endif
 #endif
-    { 0x3FFB8000, 0x4000, 2, 0x40028000}, //Block 4,  can be remapped to ROM, can be used as trace memory
-    { 0x3FFBC000, 0x4000, 2, 0x4002C000}, //Block 5,  can be remapped to ROM, can be used as trace memory
-    { 0x3FFC0000, 0x4000, 2, 0x40030000}, //Block 6,  can be used as trace memory
-    { 0x3FFC4000, 0x4000, 2, 0x40034000}, //Block 7,  can be used as trace memory
-    { 0x3FFC8000, 0x4000, 2, 0x40038000}, //Block 8,  can be used as trace memory
-    { 0x3FFCC000, 0x4000, 2, 0x4003C000}, //Block 9,  can be used as trace memory
-
-    { 0x3FFD0000, 0x4000, 2, 0x40040000}, //Block 10,  can be used as trace memory
-    { 0x3FFD4000, 0x4000, 2, 0x40044000}, //Block 11,  can be used as trace memory
-    { 0x3FFD8000, 0x4000, 2, 0x40048000}, //Block 12,  can be used as trace memory
-    { 0x3FFDC000, 0x4000, 2, 0x4004C000}, //Block 13,  can be used as trace memory
-    { 0x3FFE0000, 0x4000, 2, 0x40050000}, //Block 14,  can be used as trace memory
-    { 0x3FFE4000, 0x4000, 2, 0x40054000}, //Block 15,  can be used as trace memory
-    { 0x3FFE8000, 0x4000, 2, 0x40058000}, //Block 16,  can be used as trace memory
-    { 0x3FFEC000, 0x4000, 2, 0x4005C000}, //Block 17,  can be used as trace memory
-    { 0x3FFF0000, 0x4000, 2, 0x40060000}, //Block 18,  can be used for MAC dump, can be used as trace memory
-    { 0x3FFF4000, 0x4000, 2, 0x40064000}, //Block 19,  can be used for MAC dump, can be used as trace memory
-    { 0x3FFF8000, 0x4000, 2, 0x40068000}, //Block 20,  can be used for MAC dump, can be used as trace memory
+    { 0x3FFB8000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40028000}, //Block 4,  can be remapped to ROM, can be used as trace memory
+    { 0x3FFBC000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x4002C000}, //Block 5,  can be remapped to ROM, can be used as trace memory
+    { 0x3FFC0000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40030000}, //Block 6,  can be used as trace memory
+    { 0x3FFC4000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40034000}, //Block 7,  can be used as trace memory
+    { 0x3FFC8000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40038000}, //Block 8,  can be used as trace memory
+    { 0x3FFCC000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x4003C000}, //Block 9,  can be used as trace memory
+
+    { 0x3FFD0000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40040000}, //Block 10,  can be used as trace memory
+    { 0x3FFD4000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40044000}, //Block 11,  can be used as trace memory
+    { 0x3FFD8000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40048000}, //Block 12,  can be used as trace memory
+    { 0x3FFDC000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x4004C000}, //Block 13,  can be used as trace memory
+    { 0x3FFE0000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40050000}, //Block 14,  can be used as trace memory
+    { 0x3FFE4000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40054000}, //Block 15,  can be used as trace memory
+    { 0x3FFE8000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40058000}, //Block 16,  can be used as trace memory
+    { 0x3FFEC000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x4005C000}, //Block 17,  can be used as trace memory
+    { 0x3FFF0000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40060000}, //Block 18,  can be used for MAC dump, can be used as trace memory
+    { 0x3FFF4000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40064000}, //Block 19,  can be used for MAC dump, can be used as trace memory
+    { 0x3FFF8000, 0x4000, SOC_MEMORY_TYPE_DEFAULT, 0x40068000}, //Block 20,  can be used for MAC dump, can be used as trace memory
     { 0x3FFFC000, 0x4000, 1, 0x4006C000}, //Block 21,  can be used for MAC dump, can be used as trace memory, used for startup stack
 };
 

+ 19 - 20
components/soc/src/memory_layout_utils.c

@@ -29,7 +29,7 @@ extern soc_reserved_region_t soc_reserved_memory_region_end;
 static size_t s_get_num_reserved_regions(void)
 {
     return ( &soc_reserved_memory_region_end
-               - &soc_reserved_memory_region_start );
+             - &soc_reserved_memory_region_start );
 }
 
 size_t soc_get_available_memory_region_max_count(void)
@@ -63,20 +63,19 @@ static void s_prepare_reserved_regions(soc_reserved_region_t *reserved, size_t c
                    &soc_reserved_memory_region_start,
                    &soc_reserved_memory_region_end);
     ESP_EARLY_LOGD(TAG, "Checking %d reserved memory ranges:", count);
-    for (size_t i = 0; i < count; i++)
-    {
+    for (size_t i = 0; i < count; i++) {
         ESP_EARLY_LOGD(TAG, "Reserved memory range 0x%08x - 0x%08x",
                        reserved[i].start, reserved[i].end);
         reserved[i].start = reserved[i].start & ~3; /* expand all reserved areas to word boundaries */
         reserved[i].end = (reserved[i].end + 3) & ~3;
         assert(reserved[i].start < reserved[i].end);
         if (i < count - 1) {
-            assert(reserved[i+1].start > reserved[i].start);
-            if (reserved[i].end > reserved[i+1].start) {
+            assert(reserved[i + 1].start > reserved[i].start);
+            if (reserved[i].end > reserved[i + 1].start) {
                 ESP_EARLY_LOGE(TAG, "SOC_RESERVE_MEMORY_REGION region range " \
                                "0x%08x - 0x%08x overlaps with 0x%08x - 0x%08x",
-                               reserved[i].start, reserved[i].end, reserved[i+1].start,
-                               reserved[i+1].end);
+                               reserved[i].start, reserved[i].end, reserved[i + 1].start,
+                               reserved[i + 1].end);
                 abort();
             }
         }
@@ -101,7 +100,7 @@ size_t soc_get_available_memory_regions(soc_memory_region_t *regions)
        region, and then copy them to an out_region once trimmed
     */
     ESP_EARLY_LOGD(TAG, "Building list of available memory regions:");
-    while(in_region != in_regions + soc_memory_region_count) {
+    while (in_region != in_regions + soc_memory_region_count) {
         soc_memory_region_t in = *in_region;
         ESP_EARLY_LOGV(TAG, "Examining memory region 0x%08x - 0x%08x", in.start, in.start + in.size);
         intptr_t in_start = in.start;
@@ -113,21 +112,18 @@ size_t soc_get_available_memory_regions(soc_memory_region_t *regions)
             if (reserved[i].end <= in_start) {
                 /* reserved region ends before 'in' starts */
                 continue;
-            }
-            else if (reserved[i].start >= in_end) {
+            } else if (reserved[i].start >= in_end) {
                 /* reserved region starts after 'in' ends */
                 break;
-            }
-            else if (reserved[i].start <= in_start &&
-                     reserved[i].end >= in_end) { /* reserved covers all of 'in' */
+            } else if (reserved[i].start <= in_start &&
+                       reserved[i].end >= in_end) { /* reserved covers all of 'in' */
                 ESP_EARLY_LOGV(TAG, "Region 0x%08x - 0x%08x inside of reserved 0x%08x - 0x%08x",
                                in_start, in_end, reserved[i].start, reserved[i].end);
                 /* skip 'in' entirely */
                 copy_in_to_out = false;
                 break;
-            }
-            else if (in_start < reserved[i].start &&
-                     in_end > reserved[i].end) { /* reserved contained inside 'in', need to "hole punch" */
+            } else if (in_start < reserved[i].start &&
+                       in_end > reserved[i].end) { /* reserved contained inside 'in', need to "hole punch" */
                 ESP_EARLY_LOGV(TAG, "Region 0x%08x - 0x%08x contains reserved 0x%08x - 0x%08x",
                                in_start, in_end, reserved[i].start, reserved[i].end);
                 assert(in_start < reserved[i].start);
@@ -145,15 +141,13 @@ size_t soc_get_available_memory_regions(soc_memory_region_t *regions)
                 /* add first region, then re-run while loop with the updated in_region */
                 move_to_next = false;
                 break;
-            }
-            else if (reserved[i].start <= in_start) { /* reserved overlaps start of 'in' */
+            } else if (reserved[i].start <= in_start) { /* reserved overlaps start of 'in' */
                 ESP_EARLY_LOGV(TAG, "Start of region 0x%08x - 0x%08x overlaps reserved 0x%08x - 0x%08x",
                                in_start, in_end, reserved[i].start, reserved[i].end);
                 in.start = reserved[i].end;
                 in_start = in.start;
                 in.size = in_end - in_start;
-            }
-            else { /* reserved overlaps end of 'in' */
+            } else { /* reserved overlaps end of 'in' */
                 ESP_EARLY_LOGV(TAG, "End of region 0x%08x - 0x%08x overlaps reserved 0x%08x - 0x%08x",
                                in_start, in_end, reserved[i].start, reserved[i].end);
                 in_end = reserved[i].start;
@@ -161,6 +155,11 @@ size_t soc_get_available_memory_regions(soc_memory_region_t *regions)
             }
         }
 
+        /* ignore regions smaller than 16B */
+        if (in.size <= 16) {
+            copy_in_to_out = false;
+        }
+
         if (copy_in_to_out) {
             ESP_EARLY_LOGD(TAG, "Available memory region 0x%08x - 0x%08x", in.start, in.start + in.size);
             *out_region++ = in;