Преглед изворни кода

Merge branch 'esp32c2/IDRAM_PMP_split' into 'master'

esp32c2: Enable IRAM/DRAM split using PMP

Closes IDF-3837

See merge request espressif/esp-idf!18156
Mahavir Jain пре 3 година
родитељ
комит
c6e2ae76a9

+ 64 - 17
components/esp_hw_support/port/esp32c2/cpu_util_esp32c2.c

@@ -5,6 +5,29 @@
  */
 #include <assert.h>
 #include "esp_cpu.h"
+#include "sdkconfig.h"
+
+#if CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT && !BOOTLOADER_BUILD
+extern int _iram_end;
+extern int _data_start;
+#define IRAM_END        (int)&_iram_end
+#define DRAM_START      (int)&_data_start
+#else
+#define IRAM_END        SOC_DIRAM_IRAM_HIGH
+#define DRAM_START      SOC_DIRAM_DRAM_LOW
+#endif
+
+#ifdef BOOTLOADER_BUILD
+// Without L bit set
+#define CONDITIONAL_NONE        0x0
+#define CONDITIONAL_RX          PMP_R | PMP_X
+#define CONDITIONAL_RW          PMP_R | PMP_W
+#else
+// With L bit set
+#define CONDITIONAL_NONE        NONE
+#define CONDITIONAL_RX          RX
+#define CONDITIONAL_RW          RW
+#endif
 
 void esp_cpu_configure_region_protection(void)
 {
@@ -19,47 +42,71 @@ void esp_cpu_configure_region_protection(void)
      * 3) 3-15 PMPADDR entries be hardcoded to fixed value, 0-2 PMPADDR be programmed to split ID SRAM
      * as IRAM/DRAM. All PMPCFG entryies be available.
      *
+     * 4) Ideally, PMPADDR 0-2 entries should be configured twice, once during bootloader startup and another during app startup.
+     *    However, the CPU currently always executes in machine mode and to enforce these permissions in machine mode, we need
+     *    to set the Lock (L) bit but if set once, it cannot be reconfigured. So, we only configure 0-2 PMPADDR during app startup.
      */
-    const unsigned NONE = PMP_L ;
+    const unsigned NONE    = PMP_L ;
     const unsigned R       = PMP_L | PMP_R;
     const unsigned X       = PMP_L | PMP_X;
     const unsigned RW      = PMP_L | PMP_R | PMP_W;
     const unsigned RX      = PMP_L | PMP_R | PMP_X;
     const unsigned RWX     = PMP_L | PMP_R | PMP_W | PMP_X;
 
+    /* There are 3 configuration scenarios for PMPADDR 0-2
+     *
+     * 1. Bootloader build:
+     *    - We cannot set the lock bit as we need to reconfigure it again for the application.
+     *      We configure PMPADDR 0-1 to cover entire valid IRAM range and PMPADDR 2-3 to cover entire valid DRAM range.
+     *
+     * 2. Application build with CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT enabled
+     *    - We split the SRAM into IRAM and DRAM such that IRAM region cannot be accessed via DBUS
+     *      and DRAM region cannot be accessed via IBUS. We use _iram_end and _data_start markers to set the boundaries.
+     *      We also lock these entries so the R/W/X permissions are enforced even for machine mode
+     *
+     * 3. Application build with CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT disabled
+     *    - The IRAM-DRAM split is not enabled so we just need to ensure that access to only valid address ranges are successful
+     *      so for that we set PMPADDR 0-1 to cover entire valid IRAM range and PMPADDR 2-3 to cover entire DRAM region.
+     *      We also lock these entries so the R/W/X permissions are enforced even for machine mode
+     *
+     *  PMPADDR 3-15 are hard-coded and are appicable to both, bootloader and application. So we configure and lock
+     *  these during BOOTLOADER build itself. During application build, reconfiguration of these PMPADDR entries
+     *  are silently ignored by the CPU
+     */
+
     // 1. IRAM
-    PMP_ENTRY_SET(0,SOC_DIRAM_IRAM_LOW, NONE);
-    PMP_ENTRY_SET(1,SOC_DIRAM_IRAM_HIGH, PMP_TOR|RWX); //TODO IRAM/DRAM spilt address
+    PMP_ENTRY_SET(0, SOC_DIRAM_IRAM_LOW, CONDITIONAL_NONE);
+    PMP_ENTRY_SET(1, IRAM_END, PMP_TOR | CONDITIONAL_RX);
 
     // 2. DRAM
-    PMP_ENTRY_SET(2,SOC_DIRAM_DRAM_LOW, NONE); //TODO IRAM/DRAM spilt address
-    PMP_ENTRY_CFG_SET(3,PMP_TOR|RW);
+    PMP_ENTRY_SET(2, DRAM_START, CONDITIONAL_NONE);
+    PMP_ENTRY_CFG_SET(3, PMP_TOR | CONDITIONAL_RW);
 
     // 3. Debug region
-    PMP_ENTRY_CFG_SET(4,PMP_NAPOT|RWX);
+    PMP_ENTRY_CFG_SET(4, PMP_NAPOT | RWX);
 
     // 4. DROM (flash dcache)
-    PMP_ENTRY_CFG_SET(5,PMP_NAPOT|R);
+    PMP_ENTRY_CFG_SET(5, PMP_NAPOT | R);
 
     // 5. DROM_MASK
-    PMP_ENTRY_CFG_SET(6,NONE);
-    PMP_ENTRY_CFG_SET(7,PMP_TOR|R);
+    PMP_ENTRY_CFG_SET(6, NONE);
+    PMP_ENTRY_CFG_SET(7, PMP_TOR | R);
 
     // 6. IROM_MASK
-    PMP_ENTRY_CFG_SET(8,NONE);
-    PMP_ENTRY_CFG_SET(9,PMP_TOR|RX);
+    PMP_ENTRY_CFG_SET(8, NONE);
+    PMP_ENTRY_CFG_SET(9, PMP_TOR | RX);
 
     // 7. IROM (flash icache)
-    PMP_ENTRY_CFG_SET(10,PMP_NAPOT|RX);
+    PMP_ENTRY_CFG_SET(10, PMP_NAPOT | RX);
 
     // 8. Peripheral addresses
-    PMP_ENTRY_CFG_SET(11,PMP_NAPOT|RW);
+    PMP_ENTRY_CFG_SET(11, PMP_NAPOT | RW);
 
     // 9. SRAM (used as ICache)
-    PMP_ENTRY_CFG_SET(12,PMP_NAPOT|X);
+    PMP_ENTRY_CFG_SET(12, PMP_NAPOT | X);
 
     // 10. no access to any address below(0x0-0xFFFF_FFFF)
-    PMP_ENTRY_CFG_SET(13,PMP_NA4|NONE);// last 4 bytes(0xFFFFFFFC)
-    PMP_ENTRY_CFG_SET(14,NONE);
-    PMP_ENTRY_CFG_SET(15,PMP_TOR|NONE);
+    PMP_ENTRY_CFG_SET(13, PMP_NA4 | NONE);// last 4 bytes(0xFFFFFFFC)
+    PMP_ENTRY_CFG_SET(14, NONE);
+    PMP_ENTRY_CFG_SET(15, PMP_TOR | NONE);
 }

+ 12 - 0
components/esp_system/Kconfig

@@ -117,6 +117,18 @@ menu "ESP System Settings"
 
     menu "Memory protection"
 
+        config ESP_SYSTEM_PMP_IDRAM_SPLIT
+            bool "Enable IRAM/DRAM split protection"
+            depends on SOC_CPU_IDRAM_SPLIT_USING_PMP
+            default "y"
+            help
+                If enabled, the CPU watches all the memory access and raises an exception in case
+                of any memory violation. This feature automatically splits
+                the SRAM memory, using PMP, into data and instruction segments and sets Read/Execute permissions
+                for the instruction part (below given splitting address) and Read/Write permissions
+                for the data part (above the splitting address). The memory protection is effective
+                on all access through the IRAM0 and DRAM0 buses.
+
         config ESP_SYSTEM_MEMPROT_DEPCHECK
             bool
             default y if IDF_TARGET_ESP32S2

+ 4 - 0
components/soc/esp32c2/include/soc/Kconfig.soc_caps.in

@@ -151,6 +151,10 @@ config SOC_CPU_WATCHPOINT_SIZE
     hex
     default 0x80000000
 
+config SOC_CPU_IDRAM_SPLIT_USING_PMP
+    bool
+    default y
+
 config SOC_GDMA_GROUPS
     int
     default 1

+ 2 - 0
components/soc/esp32c2/include/soc/soc_caps.h

@@ -80,6 +80,8 @@
 
 #define SOC_CPU_WATCHPOINT_SIZE         0x80000000 // bytes
 
+#define SOC_CPU_IDRAM_SPLIT_USING_PMP   1
+
 /*-------------------------- GDMA CAPS -------------------------------------*/
 #define SOC_GDMA_GROUPS                 (1U) // Number of GDMA groups
 #define SOC_GDMA_PAIRS_PER_GROUP        (1U) // Number of GDMA pairs in each group