diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index 5cf8eba363b..189677dfe03 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -91,6 +91,7 @@ /components/esp_hw_support/ @esp-idf-codeowners/system @esp-idf-codeowners/peripherals /components/esp_lcd/ @esp-idf-codeowners/peripherals /components/esp_local_ctrl/ @esp-idf-codeowners/app-utilities +/components/esp_mm/ @esp-idf-codeowners/peripherals /components/esp_netif/ @esp-idf-codeowners/network /components/esp_netif_stack/ @esp-idf-codeowners/network /components/esp_partition/ @esp-idf-codeowners/storage diff --git a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c index da0b959e967..914c0536fc5 100644 --- a/components/bootloader_support/bootloader_flash/src/bootloader_flash.c +++ b/components/bootloader_support/bootloader_flash/src/bootloader_flash.c @@ -139,12 +139,8 @@ static const char *TAG = "bootloader_flash"; 63th block for bootloader_flash_read */ #define MMU_BLOCK0_VADDR SOC_DROM_LOW -#ifdef SOC_MMU_PAGE_SIZE_CONFIGURABLE -#define MMAP_MMU_SIZE (DRAM0_CACHE_ADDRESS_HIGH(SPI_FLASH_MMU_PAGE_SIZE) - DRAM0_CACHE_ADDRESS_LOW - SPI_FLASH_MMU_PAGE_SIZE) // This mmu size means that the mmu size to be mapped -#else -#define MMAP_MMU_SIZE (DRAM0_CACHE_ADDRESS_HIGH - DRAM0_CACHE_ADDRESS_LOW - SPI_FLASH_MMU_PAGE_SIZE) // This mmu size means that the mmu size to be mapped -#endif -#define MMU_BLOCK63_VADDR (MMU_BLOCK0_VADDR + MMAP_MMU_SIZE) +#define MMAP_MMU_SIZE (DRAM0_CACHE_ADDRESS_HIGH - DRAM0_CACHE_ADDRESS_LOW) // This mmu size means that the mmu size to be mapped +#define MMU_BLOCK63_VADDR (MMU_BLOCK0_VADDR + MMAP_MMU_SIZE - SPI_FLASH_MMU_PAGE_SIZE) #define FLASH_READ_VADDR MMU_BLOCK63_VADDR #endif diff --git a/components/driver/test_apps/rmt/main/test_rmt_tx.c b/components/driver/test_apps/rmt/main/test_rmt_tx.c index c498bc0508d..5ef13e83491 100644 --- a/components/driver/test_apps/rmt/main/test_rmt_tx.c +++ b/components/driver/test_apps/rmt/main/test_rmt_tx.c @@ -466,11 +466,11 @@ static void test_rmt_multi_channels_trans(size_t channel0_mem_block_symbols, siz #define TEST_RMT_CHANS 2 #define TEST_LED_NUM 24 #define TEST_STOP_TIME_NO_SYNCHRO_DELTA 150 -#if CONFIG_IDF_TARGET_ESP32C6 +#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 #define TEST_STOP_TIME_SYNCHRO_DELTA 400 #else #define TEST_STOP_TIME_SYNCHRO_DELTA 10 -#endif // CONFIG_IDF_TARGET_ESP32C6 +#endif // #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 rmt_tx_channel_config_t tx_channel_cfg = { .clk_src = RMT_CLK_SRC_DEFAULT, .resolution_hz = 10000000, // 10MHz, 1 tick = 0.1us (led strip needs a high resolution) diff --git a/components/driver/test_apps/spi/master/main/test_app_main.c b/components/driver/test_apps/spi/master/main/test_app_main.c index f80c5a1e1fb..f202bf7b7b9 100644 --- a/components/driver/test_apps/spi/master/main/test_app_main.c +++ b/components/driver/test_apps/spi/master/main/test_app_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" // iterator to load partition tables in `test spi bus lock, with flash` will lead memory not free -#define TEST_MEMORY_LEAK_THRESHOLD (250) +#define TEST_MEMORY_LEAK_THRESHOLD (350) static size_t before_free_8bit; static size_t before_free_32bit; diff --git a/components/esp_mm/CMakeLists.txt b/components/esp_mm/CMakeLists.txt new file mode 100644 index 00000000000..9c7bf0419e5 --- /dev/null +++ b/components/esp_mm/CMakeLists.txt @@ -0,0 +1,24 @@ +idf_build_get_property(target IDF_TARGET) + +set(includes "include") + +# Note: requires spi_flash for cache_utils, will be refactored +set(priv_requires heap spi_flash) + +set(srcs) + +if(NOT CONFIG_APP_BUILD_TYPE_PURE_RAM_APP) + set(srcs "esp_mmu_map.c" + "port/${target}/ext_mem_layout.c") +endif() + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS ${includes} + PRIV_REQUIRES ${priv_requires}) + +if(NOT BOOTLOADER_BUILD) + if(CONFIG_SPIRAM) + # Use esp_psram for `esp_psram_extram_writeback_cache()` on ESP32 + idf_component_optional_requires(PRIVATE esp_psram) + endif() +endif() diff --git a/components/esp_mm/Kconfig b/components/esp_mm/Kconfig new file mode 100644 index 00000000000..a44a9159131 --- /dev/null +++ b/components/esp_mm/Kconfig @@ -0,0 +1,8 @@ +menu "ESP Memory Management" + + # Add MMU setting menu here + # Add Cache setting menu here + + orsource "./Kconfig.mmap" + +endmenu # ESP Memory Management diff --git a/components/esp_mm/Kconfig.mmap b/components/esp_mm/Kconfig.mmap new file mode 100644 index 00000000000..fb0e3d22e9f --- /dev/null +++ b/components/esp_mm/Kconfig.mmap @@ -0,0 +1,3 @@ +menu "MMAP Configuration" + +endmenu diff --git a/components/esp_mm/esp_mmu_map.c b/components/esp_mm/esp_mmu_map.c new file mode 100644 index 00000000000..8c445bd2d7b --- /dev/null +++ b/components/esp_mm/esp_mmu_map.c @@ -0,0 +1,724 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" + +#include "soc/soc_caps.h" +#include "hal/cache_types.h" +#include "hal/cache_hal.h" +#include "hal/cache_ll.h" +#include "hal/mmu_types.h" +#include "hal/mmu_hal.h" +#include "hal/mmu_ll.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/cache.h" +#endif +#include "esp_private/cache_utils.h" +#if CONFIG_SPIRAM +#include "esp_private/esp_psram_extram.h" +#endif + +#include "esp_private/esp_mmu_map_private.h" +#include "ext_mem_layout.h" +#include "esp_mmu_map.h" + + +//This is for size align +#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +//This is for vaddr align +#define ALIGN_DOWN_BY(num, align) ((num) & (~((align) - 1))) + +//This flag indicates the memory region is merged, we don't care about it anymore +#define MEM_REGION_MERGED -1 + +/** + * We have some hw related tests for vaddr region capabilites + * Use this macro to disable paddr check as we need to reuse certain paddr blocks + */ +#define ENABLE_PADDR_CHECK !ESP_MMAP_TEST_ALLOW_MAP_TO_MAPPED_PADDR + +static DRAM_ATTR const char *TAG = "mmap"; + +/** + * @brief MMU Memory Mapping Driver + * + * Driver Backgrounds: + * + * -------------------------------------------------------------------------------------------------------- + * Memory Pool | + * -------------------------------------------------------------------------------------------------------- + * | Memory Region 0 | Memory Region 1 | ... | + * -------------------------------------------------------------------------------------------------------- + * | Block 0 | Slot 0 | Block 1 | Block 2 | ... | Slot 1 (final slot) | ... | + * -------------------------------------------------------------------------------------------------------- + * + * - A block is a piece of vaddr range that is dynamically mapped. Blocks are doubly linked: + * Block 0 <-> Block 1 <-> Block 2 + * - A Slot is the vaddr range between 2 blocks. + */ + +/** + * Struct for a block + */ +typedef struct mem_block_ { + uint32_t laddr_start; //linear address start of this block + uint32_t laddr_end; //linear address end of this block + intptr_t vaddr_start; //virtual address start of this block + intptr_t vaddr_end; //virtual address end of this block + size_t size; //size of this block, should be aligned to MMU page size + int caps; //caps of this block, `mmu_mem_caps_t` + uint32_t paddr_start; //physical address start of this block + uint32_t paddr_end; //physical address end of this block + mmu_target_t target; //physical target that this block is mapped to + TAILQ_ENTRY(mem_block_) entries; //link entry +} mem_block_t; + +/** + * Struct for a memory region + */ +typedef struct mem_region_ { + cache_bus_mask_t bus_id; //cache bus mask of this region + uint32_t start; //linear address start of this region + uint32_t end; //linear address end of this region + size_t region_size; //region size, in bytes + uint32_t free_head; //linear address free head of this region + size_t max_slot_size; //max slot size within this region + int caps; //caps of this region, `mmu_mem_caps_t` + mmu_target_t targets; //physical targets that this region is supported + TAILQ_HEAD(mem_block_head_, mem_block_) mem_block_head; //link head of allocated blocks within this region +} mem_region_t; + +typedef struct { + /** + * number of memory regions that are available, after coalescing, this number should be smaller than or equal to `SOC_MMU_LINEAR_ADDRESS_REGION_NUM` + */ + uint32_t num_regions; + /** + * This saves the available MMU linear address regions, + * after reserving flash .rodata and .text, and after coalescing. + * Only the first `num_regions` items are valid + */ + mem_region_t mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM]; +} mmu_ctx_t; + +static mmu_ctx_t s_mmu_ctx; + + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS +static void s_reserve_irom_region(mem_region_t *hw_mem_regions, int region_nums) +{ + /** + * We follow the way how 1st bootloader load flash .text: + * + * - Now IBUS addresses (between `_instruction_reserved_start` and `_instruction_reserved_end`) are consecutive on all chips, + * we strongly rely on this to calculate the .text length + */ + extern int _instruction_reserved_start; + extern int _instruction_reserved_end; + size_t irom_len_to_reserve = (uint32_t)&_instruction_reserved_end - (uint32_t)&_instruction_reserved_start; + assert((mmu_ll_vaddr_to_laddr((uint32_t)&_instruction_reserved_end) - mmu_ll_vaddr_to_laddr((uint32_t)&_instruction_reserved_start)) == irom_len_to_reserve); + + irom_len_to_reserve += (uint32_t)&_instruction_reserved_start - ALIGN_DOWN_BY((uint32_t)&_instruction_reserved_start, CONFIG_MMU_PAGE_SIZE); + irom_len_to_reserve = ALIGN_UP_BY(irom_len_to_reserve, CONFIG_MMU_PAGE_SIZE); + cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, (uint32_t)&_instruction_reserved_start, irom_len_to_reserve); + + for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { + if (bus_mask & hw_mem_regions[i].bus_id) { + if (hw_mem_regions[i].region_size <= irom_len_to_reserve) { + hw_mem_regions[i].free_head = hw_mem_regions[i].end; + hw_mem_regions[i].max_slot_size = 0; + irom_len_to_reserve -= hw_mem_regions[i].region_size; + } else { + hw_mem_regions[i].free_head = hw_mem_regions[i].free_head + irom_len_to_reserve; + hw_mem_regions[i].max_slot_size -= irom_len_to_reserve; + } + } + } +} + +static void s_reserve_drom_region(mem_region_t *hw_mem_regions, int region_nums) +{ + /** + * Similarly, we follow the way how 1st bootloader load flash .rodata: + */ + extern int _rodata_reserved_start; + extern int _rodata_reserved_end; + size_t drom_len_to_reserve = (uint32_t)&_rodata_reserved_end - (uint32_t)&_rodata_reserved_start; + assert((mmu_ll_vaddr_to_laddr((uint32_t)&_rodata_reserved_end) - mmu_ll_vaddr_to_laddr((uint32_t)&_rodata_reserved_start)) == drom_len_to_reserve); + + drom_len_to_reserve += (uint32_t)&_rodata_reserved_start - ALIGN_DOWN_BY((uint32_t)&_rodata_reserved_start, CONFIG_MMU_PAGE_SIZE); + drom_len_to_reserve = ALIGN_UP_BY(drom_len_to_reserve, CONFIG_MMU_PAGE_SIZE); + cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, (uint32_t)&_rodata_reserved_start, drom_len_to_reserve); + + for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { + if (bus_mask & hw_mem_regions[i].bus_id) { + if (hw_mem_regions[i].region_size <= drom_len_to_reserve) { + hw_mem_regions[i].free_head = hw_mem_regions[i].end; + hw_mem_regions[i].max_slot_size = 0; + drom_len_to_reserve -= hw_mem_regions[i].region_size; + } else { + hw_mem_regions[i].free_head = hw_mem_regions[i].free_head + drom_len_to_reserve; + hw_mem_regions[i].max_slot_size -= drom_len_to_reserve; + } + } + } +} +#endif //#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + +void esp_mmu_map_init(void) +{ + mem_region_t hw_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = {}; + + for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { + hw_mem_regions[i].start = g_mmu_mem_regions[i].start; + hw_mem_regions[i].end = g_mmu_mem_regions[i].end; + hw_mem_regions[i].region_size = g_mmu_mem_regions[i].size; + hw_mem_regions[i].max_slot_size = g_mmu_mem_regions[i].size; + hw_mem_regions[i].free_head = g_mmu_mem_regions[i].start; + hw_mem_regions[i].bus_id = g_mmu_mem_regions[i].bus_id; + hw_mem_regions[i].caps = g_mmu_mem_regions[i].caps; + hw_mem_regions[i].targets = g_mmu_mem_regions[i].targets; +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 + assert(__builtin_popcount(hw_mem_regions[i].bus_id) == 1); +#endif + assert(hw_mem_regions[i].region_size % CONFIG_MMU_PAGE_SIZE == 0); + } + +#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + //First reserve memory regions used for irom and drom, as we must follow the way how 1st bootloader load them + s_reserve_irom_region(hw_mem_regions, SOC_MMU_LINEAR_ADDRESS_REGION_NUM); + s_reserve_drom_region(hw_mem_regions, SOC_MMU_LINEAR_ADDRESS_REGION_NUM); +#endif //#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS + + if (SOC_MMU_LINEAR_ADDRESS_REGION_NUM > 1) { + //Now we can coalesce adjacent regions + for (int i = 1; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { + mem_region_t *a = &hw_mem_regions[i - 1]; + mem_region_t *b = &hw_mem_regions[i]; + if ((b->free_head == a->end) && (b->caps == a->caps) && (b->targets == a->targets)) { + a->caps = MEM_REGION_MERGED; + b->bus_id |= a->bus_id; + b->start = a->start; + b->region_size += a->region_size; + b->free_head = a->free_head; + b->max_slot_size += a->max_slot_size; + } + } + } + + //Count the mem regions left after coalescing + uint32_t region_num = 0; + for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { + if(hw_mem_regions[i].caps != MEM_REGION_MERGED) { + region_num++; + } + } + ESP_EARLY_LOGV(TAG, "after coalescing, %d regions are left", region_num); + + //Initialise `s_mmu_ctx.mem_regions[]`, as we've done all static allocation, to prepare available virtual memory regions + uint32_t available_region_idx = 0; + s_mmu_ctx.num_regions = region_num; + for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { + if (hw_mem_regions[i].caps == MEM_REGION_MERGED) { + continue; + } + + memcpy(&s_mmu_ctx.mem_regions[available_region_idx], &hw_mem_regions[i], sizeof(mem_region_t)); + available_region_idx++; + } + + for (int i = 0; i < available_region_idx; i++) { + TAILQ_INIT(&s_mmu_ctx.mem_regions[i].mem_block_head); + } + + assert(available_region_idx == region_num); +} + + +static esp_err_t s_mem_caps_check(mmu_mem_caps_t caps) +{ + if (caps & MMU_MEM_CAP_EXEC) { + if ((caps & MMU_MEM_CAP_8BIT) || (caps & MMU_MEM_CAP_WRITE)) { + //None of the executable memory are expected to be 8-bit accessible or writable. + return ESP_ERR_INVALID_ARG; + } + caps |= MMU_MEM_CAP_32BIT; + } + return ESP_OK; +} + +esp_err_t esp_mmu_map_get_max_consecutive_free_block_size(mmu_mem_caps_t caps, mmu_target_t target, size_t *out_len) +{ + ESP_RETURN_ON_FALSE(out_len, ESP_ERR_INVALID_ARG, TAG, "null pointer"); + ESP_RETURN_ON_ERROR(s_mem_caps_check(caps), TAG, "invalid caps"); + *out_len = 0; + + size_t max = 0; + + for (int i = 0; i < s_mmu_ctx.num_regions; i++) { + if (((s_mmu_ctx.mem_regions[i].caps & caps) == caps) && ((s_mmu_ctx.mem_regions[i].targets & target) == target)) { + if (s_mmu_ctx.mem_regions[i].max_slot_size > max) { + max = s_mmu_ctx.mem_regions[i].max_slot_size; + } + } + } + + *out_len = max; + + return ESP_OK; +} + + +static int32_t s_find_available_region(mem_region_t *mem_regions, uint32_t region_nums, size_t size, mmu_mem_caps_t caps, mmu_target_t target) +{ + int32_t found_region_id = -1; + for (int i = 0; i < region_nums; i++) { + if (((mem_regions[i].caps & caps) == caps) && ((mem_regions[i].targets & target) == target)) { + if (mem_regions[i].max_slot_size >= size) { + found_region_id = i; + break; + } + } + } + return found_region_id; +} + +esp_err_t esp_mmu_map_reserve_block_with_caps(size_t size, mmu_mem_caps_t caps, mmu_target_t target, const void **out_ptr) +{ + ESP_RETURN_ON_FALSE(out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); + ESP_RETURN_ON_ERROR(s_mem_caps_check(caps), TAG, "invalid caps"); + + size_t aligned_size = ALIGN_UP_BY(size, CONFIG_MMU_PAGE_SIZE); + uint32_t laddr = 0; + + int32_t found_region_id = s_find_available_region(s_mmu_ctx.mem_regions, s_mmu_ctx.num_regions, aligned_size, caps, target); + if (found_region_id == -1) { + ESP_EARLY_LOGE(TAG, "no such vaddr range"); + return ESP_ERR_NOT_FOUND; + } + + laddr = (uint32_t)s_mmu_ctx.mem_regions[found_region_id].free_head; + s_mmu_ctx.mem_regions[found_region_id].free_head += aligned_size; + s_mmu_ctx.mem_regions[found_region_id].max_slot_size -= aligned_size; + ESP_EARLY_LOGV(TAG, "found laddr is 0x%x", laddr); + + uint32_t vaddr = 0; + if (caps & MMU_MEM_CAP_EXEC) { + vaddr = mmu_ll_laddr_to_vaddr(laddr, MMU_VADDR_INSTRUCTION); + } else { + vaddr = mmu_ll_laddr_to_vaddr(laddr, MMU_VADDR_DATA); + } + *out_ptr = (void *)vaddr; + + return ESP_OK; +} + + +#if CONFIG_IDF_TARGET_ESP32 +/** + * On ESP32, due to hardware limitation, we don't have an + * easy way to sync between cache and external memory wrt + * certain range. So we do a full sync here + */ +static void IRAM_ATTR NOINLINE_ATTR s_cache_sync(void) +{ +#if CONFIG_SPIRAM + esp_psram_extram_writeback_cache(); +#endif //#if CONFIG_SPIRAM + Cache_Flush(0); +#if !CONFIG_FREERTOS_UNICORE + Cache_Flush(1); +#endif // !CONFIG_FREERTOS_UNICORE +} +#endif //#if CONFIG_IDF_TARGET_ESP32 + + +static void IRAM_ATTR NOINLINE_ATTR s_do_cache_invalidate(uint32_t vaddr_start, uint32_t size) +{ +#if CONFIG_IDF_TARGET_ESP32 + s_cache_sync(); +#else //Other chips + cache_hal_invalidate_addr(vaddr_start, size); +#endif // CONFIG_IDF_TARGET_ESP32 +} + +static void IRAM_ATTR NOINLINE_ATTR s_do_mapping(mmu_target_t target, uint32_t vaddr_start, esp_paddr_t paddr_start, uint32_t size) +{ + /** + * Disable Cache, after this function, involved code and data should be placed in internal RAM. + * + * @note we call this for now, but this will be refactored to move out of `spi_flash` + */ + spi_flash_disable_interrupts_caches_and_other_cpu(); + + uint32_t actual_mapped_len = 0; + mmu_hal_map_region(0, target, vaddr_start, paddr_start, size, &actual_mapped_len); +#if (SOC_MMU_PERIPH_NUM == 2) +#if !CONFIG_FREERTOS_UNICORE + mmu_hal_map_region(1, target, vaddr_start, paddr_start, size, &actual_mapped_len); +#endif // #if !CONFIG_FREERTOS_UNICORE +#endif // #if (SOC_MMU_PERIPH_NUM == 2) + + cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, vaddr_start, size); + cache_ll_l1_enable_bus(0, bus_mask); +#if !CONFIG_FREERTOS_UNICORE + bus_mask = cache_ll_l1_get_bus(0, vaddr_start, size); + cache_ll_l1_enable_bus(1, bus_mask); +#endif + + s_do_cache_invalidate(vaddr_start, size); + + //enable Cache, after this function, internal RAM access is no longer mandatory + spi_flash_enable_interrupts_caches_and_other_cpu(); + + ESP_EARLY_LOGV(TAG, "actual_mapped_len is 0x%"PRIx32, actual_mapped_len); +} + +esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_mem_caps_t caps, mmu_target_t target, void **out_ptr) +{ + esp_err_t ret = ESP_FAIL; + ESP_RETURN_ON_FALSE(out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); +#if !SOC_SPIRAM_SUPPORTED || CONFIG_IDF_TARGET_ESP32 + ESP_RETURN_ON_FALSE(!(target & MMU_TARGET_PSRAM0), ESP_ERR_NOT_SUPPORTED, TAG, "PSRAM is not supported"); +#endif + ESP_RETURN_ON_FALSE((paddr_start % CONFIG_MMU_PAGE_SIZE == 0), ESP_ERR_INVALID_ARG, TAG, "paddr must be rounded up to the nearest multiple of CONFIG_MMU_PAGE_SIZE"); + ESP_RETURN_ON_ERROR(s_mem_caps_check(caps), TAG, "invalid caps"); + + size_t aligned_size = ALIGN_UP_BY(size, CONFIG_MMU_PAGE_SIZE); + int32_t found_region_id = s_find_available_region(s_mmu_ctx.mem_regions, s_mmu_ctx.num_regions, aligned_size, caps, target); + if (found_region_id == -1) { + ESP_EARLY_LOGE(TAG, "no such vaddr range"); + return ESP_ERR_NOT_FOUND; + } + + //Now we're sure we can find an available block inside a certain region + mem_region_t *found_region = &s_mmu_ctx.mem_regions[found_region_id]; + mem_block_t *dummy_head = NULL; + mem_block_t *dummy_tail = NULL; + mem_block_t *new_block = NULL; + + if (TAILQ_EMPTY(&found_region->mem_block_head)) { + dummy_head = (mem_block_t *)heap_caps_calloc(1, sizeof(mem_block_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_GOTO_ON_FALSE(dummy_head, ESP_ERR_NO_MEM, err, TAG, "no mem"); + + dummy_head->laddr_start = found_region->free_head; + dummy_head->laddr_end = found_region->free_head; + //We don't care vaddr or paddr address for dummy head + dummy_head->size = 0; + dummy_head->caps = caps; + TAILQ_INSERT_HEAD(&found_region->mem_block_head, dummy_head, entries); + + dummy_tail = (mem_block_t *)heap_caps_calloc(1, sizeof(mem_block_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_GOTO_ON_FALSE(dummy_tail, ESP_ERR_NO_MEM, err, TAG, "no mem"); + + dummy_tail->laddr_start = found_region->end; + dummy_tail->laddr_end = found_region->end; + //We don't care vaddr or paddr address for dummy tail + dummy_tail->size = 0; + dummy_tail->caps = caps; + TAILQ_INSERT_TAIL(&found_region->mem_block_head, dummy_tail, entries); + } + + //Check if paddr is overlapped + mem_block_t *mem_block = NULL; + +#if ENABLE_PADDR_CHECK + bool is_mapped = false; + TAILQ_FOREACH(mem_block, &found_region->mem_block_head, entries) { + if (target == mem_block->target) { + if ((paddr_start >= mem_block->paddr_start) && ((paddr_start + aligned_size) <= mem_block->paddr_end)) { + //the to-be-mapped paddr region is mapped already + is_mapped = true; + break; + } + } + } + + if (is_mapped) { + ESP_LOGW(TAG, "paddr region is mapped already, vaddr_start: %p, size: 0x%x", (void *)mem_block->vaddr_start, mem_block->size); + *out_ptr = (void *)mem_block->vaddr_start; + return ESP_ERR_INVALID_STATE; + } +#endif //#if ENABLE_PADDR_CHECK + + new_block = (mem_block_t *)heap_caps_calloc(1, sizeof(mem_block_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + ESP_GOTO_ON_FALSE(new_block, ESP_ERR_NO_MEM, err, TAG, "no mem"); + + //Reserve this block as it'll be mapped + bool found = false; + // Get the end address of the dummy_head block, which is always first block on the list + uint32_t last_end = TAILQ_FIRST(&found_region->mem_block_head)->laddr_end; + size_t slot_len = 0; + size_t max_slot_len = 0; + mem_block_t *found_block = NULL; //This stands for the block we found, whose slot between its prior block is where we will insert the new block to + + TAILQ_FOREACH(mem_block, &found_region->mem_block_head, entries) { + slot_len = mem_block->laddr_start - last_end; + + if (!found) { + if (slot_len >= aligned_size) { + //Found it + found = true; + found_block = mem_block; + slot_len -= aligned_size; + new_block->laddr_start = last_end; + } + } + + max_slot_len = (slot_len > max_slot_len) ? slot_len : max_slot_len; + last_end = mem_block->laddr_end; + } + + assert(found); + //insert the to-be-mapped new block to the list + TAILQ_INSERT_BEFORE(found_block, new_block, entries); + + //Finally, we update the max_slot_size + found_region->max_slot_size = max_slot_len; + + //Now we fill others according to the found `new_block->laddr_start` + new_block->laddr_end = new_block->laddr_start + aligned_size; + new_block->size = aligned_size; + new_block->caps = caps; + if (caps & MMU_MEM_CAP_EXEC) { + new_block->vaddr_start = mmu_ll_laddr_to_vaddr(new_block->laddr_start, MMU_VADDR_INSTRUCTION); + new_block->vaddr_end = mmu_ll_laddr_to_vaddr(new_block->laddr_end, MMU_VADDR_INSTRUCTION); + } else { + new_block->vaddr_start = mmu_ll_laddr_to_vaddr(new_block->laddr_start, MMU_VADDR_DATA); + new_block->vaddr_end = mmu_ll_laddr_to_vaddr(new_block->laddr_end, MMU_VADDR_DATA); + } + new_block->paddr_start = paddr_start; + new_block->paddr_end = paddr_start + aligned_size; + new_block->target = target; + + //do mapping + s_do_mapping(target, new_block->vaddr_start, paddr_start, aligned_size); + *out_ptr = (void *)new_block->vaddr_start; + + return ESP_OK; + +err: + if (new_block) { + free(new_block); + } + if (dummy_tail) { + free(dummy_tail); + } + if (dummy_head) { + free(dummy_head); + } + + return ret; +} + + +static void IRAM_ATTR NOINLINE_ATTR s_do_unmapping(uint32_t vaddr_start, uint32_t size) +{ + /** + * Disable Cache, after this function, involved code and data should be placed in internal RAM. + * + * @note we call this for now, but this will be refactored to move out of `spi_flash` + */ + spi_flash_disable_interrupts_caches_and_other_cpu(); + + mmu_hal_unmap_region(0, vaddr_start, size); +#if (SOC_MMU_PERIPH_NUM == 2) +#if !CONFIG_FREERTOS_UNICORE + mmu_hal_unmap_region(1, vaddr_start, size); +#endif // #if !CONFIG_FREERTOS_UNICORE +#endif // #if (SOC_MMU_PERIPH_NUM == 2) + + //enable Cache, after this function, internal RAM access is no longer mandatory + spi_flash_enable_interrupts_caches_and_other_cpu(); +} + +esp_err_t esp_mmu_unmap(void *ptr) +{ + ESP_RETURN_ON_FALSE(ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); + + mem_region_t *region = NULL; + mem_block_t *mem_block = NULL; + uint32_t ptr_laddr = mmu_ll_vaddr_to_laddr((uint32_t)ptr); + size_t slot_len = 0; + + for (int i = 0; i < s_mmu_ctx.num_regions; i++) { + if (ptr_laddr >= s_mmu_ctx.mem_regions[i].free_head && ptr_laddr < s_mmu_ctx.mem_regions[i].end) { + region = &s_mmu_ctx.mem_regions[i]; + } + } + ESP_RETURN_ON_FALSE(region, ESP_ERR_NOT_FOUND, TAG, "munmap target pointer is outside external memory regions"); + + bool found = false; + mem_block_t *found_block = NULL; + TAILQ_FOREACH(mem_block, ®ion->mem_block_head, entries) { + if (mem_block == TAILQ_FIRST(®ion->mem_block_head) || mem_block == TAILQ_LAST(®ion->mem_block_head, mem_block_head_)) { + //we don't care the dummy_head and the dummy_tail + continue; + } + + //now we are only traversing the actual dynamically allocated blocks, dummy_head and dummy_tail are excluded already + if (mem_block->laddr_start == ptr_laddr) { + slot_len = TAILQ_NEXT(mem_block, entries)->laddr_start - TAILQ_PREV(mem_block, mem_block_head_, entries)->laddr_end; + region->max_slot_size = (slot_len > region->max_slot_size) ? slot_len : region->max_slot_size; + + found = true; + found_block = mem_block; + break; + } + } + + ESP_RETURN_ON_FALSE(found, ESP_ERR_NOT_FOUND, TAG, "munmap target pointer isn't mapped yet"); + + //do unmap + s_do_unmapping(mem_block->vaddr_start, mem_block->size); + //remove the already unmapped block from the list + TAILQ_REMOVE(®ion->mem_block_head, found_block, entries); + free(found_block); + + return ESP_OK; +} + + +esp_err_t esp_mmu_map_dump_mapped_blocks(FILE* stream) +{ + char line[100]; + for (int i = 0; i < s_mmu_ctx.num_regions; i++) { + fprintf(stream, "region %d:\n", i); + fprintf(stream, "%-15s %-14s %-14s %-12s %-12s %-12s\n", "Bus ID", "Start", "Free Head", "End", "Caps", "Max Slot Size"); + + char *buf = line; + size_t len = sizeof(line); + memset(line, 0x0, len); + snprintf(buf, len, "0x%-13x 0x%-12"PRIx32" 0x%-11"PRIx32" 0x%-10"PRIx32" 0x%-10x 0x%-8x\n", + s_mmu_ctx.mem_regions[i].bus_id, + s_mmu_ctx.mem_regions[i].start, + s_mmu_ctx.mem_regions[i].free_head, + s_mmu_ctx.mem_regions[i].end, + s_mmu_ctx.mem_regions[i].caps, + s_mmu_ctx.mem_regions[i].max_slot_size); + fputs(line, stream); + + fprintf(stream, "mapped blocks:\n"); + fprintf(stream, "%-4s %-13s %-12s %-12s %-6s %-13s %-11s\n", "ID", "Vaddr Start", "Vaddr End", "Block Size", "Caps", "Paddr Start", "Paddr End"); + mem_region_t *region = &s_mmu_ctx.mem_regions[i]; + mem_block_t *mem_block = NULL; + int id = 0; + TAILQ_FOREACH(mem_block, ®ion->mem_block_head, entries) { + if (mem_block != TAILQ_FIRST(®ion->mem_block_head) && mem_block != TAILQ_LAST(®ion->mem_block_head, mem_block_head_)) { + snprintf(buf, len, "%-4d 0x%-11x 0x%-10x 0x%-10x 0x%-4x 0x%-11"PRIx32" 0x%-8"PRIx32"\n", + id, + mem_block->vaddr_start, + mem_block->vaddr_end, + mem_block->size, + mem_block->caps, + mem_block->paddr_start, + mem_block->paddr_end); + fputs(line, stream); + id++; + } + } + fprintf(stream, "\n"); + } + + return ESP_OK; +} + + +/*--------------------------------------------------------------- + Private dump functions, IRAM Safe +---------------------------------------------------------------*/ +esp_err_t IRAM_ATTR esp_mmu_map_dump_mapped_blocks_private(void) +{ + for (int i = 0; i < s_mmu_ctx.num_regions; i++) { + mem_region_t *region = &s_mmu_ctx.mem_regions[i]; + mem_block_t *mem_block = NULL; + TAILQ_FOREACH(mem_block, ®ion->mem_block_head, entries) { + if (mem_block != TAILQ_FIRST(®ion->mem_block_head) && mem_block != TAILQ_LAST(®ion->mem_block_head, mem_block_head_)) { + ESP_DRAM_LOGI(TAG, "block vaddr_start: 0x%x", mem_block->vaddr_start); + ESP_DRAM_LOGI(TAG, "block vaddr_end: 0x%x", mem_block->vaddr_end); + ESP_DRAM_LOGI(TAG, "block size: 0x%x", mem_block->size); + ESP_DRAM_LOGI(TAG, "block caps: 0x%x\n", mem_block->caps); + ESP_DRAM_LOGI(TAG, "block paddr_start: 0x%x\n", mem_block->paddr_start); + ESP_DRAM_LOGI(TAG, "block paddr_end: 0x%x\n", mem_block->paddr_end); + } + } + ESP_DRAM_LOGI(TAG, "region bus_id: 0x%x", s_mmu_ctx.mem_regions[i].bus_id); + ESP_DRAM_LOGI(TAG, "region start: 0x%x", s_mmu_ctx.mem_regions[i].start); + ESP_DRAM_LOGI(TAG, "region end: 0x%x", s_mmu_ctx.mem_regions[i].end); + ESP_DRAM_LOGI(TAG, "region caps: 0x%x\n", s_mmu_ctx.mem_regions[i].caps); + } + + return ESP_OK; +} + + +/*--------------------------------------------------------------- + Helper APIs for conversion between vaddr and paddr +---------------------------------------------------------------*/ +static bool NOINLINE_ATTR IRAM_ATTR s_vaddr_to_paddr(uint32_t vaddr, esp_paddr_t *out_paddr, mmu_target_t *out_target) +{ + //we call this for now, but this will be refactored to move out of `spi_flash` + spi_flash_disable_interrupts_caches_and_other_cpu(); + //On ESP32, core 1 settings should be the same as the core 0 + bool is_mapped = mmu_hal_vaddr_to_paddr(0, vaddr, out_paddr, out_target); + spi_flash_enable_interrupts_caches_and_other_cpu(); + + return is_mapped; +} + +esp_err_t esp_mmu_vaddr_to_paddr(void *vaddr, esp_paddr_t *out_paddr, mmu_target_t *out_target) +{ + ESP_RETURN_ON_FALSE(vaddr && out_paddr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); + ESP_RETURN_ON_FALSE(mmu_ll_check_valid_ext_vaddr_region(0, (uint32_t)vaddr, 1), ESP_ERR_INVALID_ARG, TAG, "not a valid external virtual address"); + + esp_paddr_t paddr = 0; + mmu_target_t target = 0; + + bool is_mapped = s_vaddr_to_paddr((uint32_t)vaddr, &paddr, &target); + ESP_RETURN_ON_FALSE(is_mapped, ESP_ERR_NOT_FOUND, TAG, "vaddr isn't mapped"); + + *out_paddr = paddr; + *out_target = target; + + return ESP_OK; +} + + +static bool NOINLINE_ATTR IRAM_ATTR s_paddr_to_vaddr(esp_paddr_t paddr, mmu_target_t target, mmu_vaddr_t type, uint32_t *out_vaddr) +{ + //we call this for now, but this will be refactored to move out of `spi_flash` + spi_flash_disable_interrupts_caches_and_other_cpu(); + //On ESP32, core 1 settings should be the same as the core 0 + bool found = mmu_hal_paddr_to_vaddr(0, paddr, target, type, out_vaddr); + spi_flash_enable_interrupts_caches_and_other_cpu(); + + return found; +} + +esp_err_t esp_mmu_paddr_to_vaddr(esp_paddr_t paddr, mmu_target_t target, mmu_vaddr_t type, void **out_vaddr) +{ + ESP_RETURN_ON_FALSE(out_vaddr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); + + uint32_t vaddr = 0; + bool found = false; + + found = s_paddr_to_vaddr(paddr, target, type, &vaddr); + ESP_RETURN_ON_FALSE(found, ESP_ERR_NOT_FOUND, TAG, "paddr isn't mapped"); + + *out_vaddr = (void *)vaddr; + + return ESP_OK; +} diff --git a/components/esp_psram/ext_mem_layout.h b/components/esp_mm/ext_mem_layout.h similarity index 59% rename from components/esp_psram/ext_mem_layout.h rename to components/esp_mm/ext_mem_layout.h index 539b3cc5204..9f72753306c 100644 --- a/components/esp_psram/ext_mem_layout.h +++ b/components/esp_mm/ext_mem_layout.h @@ -10,6 +10,7 @@ #include "sdkconfig.h" #include "soc/soc_caps.h" #include "hal/cache_types.h" +#include "hal/mmu_types.h" #ifdef __cplusplus extern "C" { @@ -17,11 +18,12 @@ extern "C" { typedef struct { - intptr_t start; - intptr_t end; - size_t size; - cache_bus_mask_t bus_id; - uint32_t caps; + uint32_t start; //laddr start + uint32_t end; //laddr end + size_t size; //region size + cache_bus_mask_t bus_id; //bus_id mask, for accessible cache buses + mmu_target_t targets; //region supported physical targets + uint32_t caps; //vaddr capabilities } mmu_mem_region_t; //These regions is referring to linear address diff --git a/components/esp_mm/include/esp_mmu_map.h b/components/esp_mm/include/esp_mmu_map.h new file mode 100644 index 00000000000..87a27f09ce6 --- /dev/null +++ b/components/esp_mm/include/esp_mmu_map.h @@ -0,0 +1,142 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "esp_err.h" +#include "hal/mmu_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * MMU Memory Mapping Driver APIs for MMU supported memory + * + * + * Driver Backgrounds: + * + * -------------------------------------------------------------------------------------------------------- + * Memory Pool | + * -------------------------------------------------------------------------------------------------------- + * | Memory Region 0 | Memory Region 1 | ... | + * -------------------------------------------------------------------------------------------------------- + * | Block 0 | Slot 0 | Block 1 | Block 2 | ... | Slot 1 (final slot) | ... | + * -------------------------------------------------------------------------------------------------------- + * + * - A memory pool stands for the whole virtual address range that can be mapped to physical memory + * - A memory region is a range of virtual address with same attributes + * - A block is a piece of vaddr range that is dynamically mapped. + * - A Slot is the vaddr range between 2 blocks. + */ + +/** + * @brief Physical memory type + */ +typedef uint32_t esp_paddr_t; + +/** + * @brief Map a physical memory block to external virtual address block, with given capabilities. + * + * @note This API does not guarantee thread safety + * + * @param[in] paddr_start Start address of the physical memory block + * @param[in] size Size to be mapped. Size will be rounded up by to the nearest multiple of MMU page size + * @param[in] caps Memory capabilities, see `mmu_mem_caps_t` + * @param[in] target Physical memory target you're going to map to, see `mmu_target_t` + * @param[out] out_ptr Start address of the mapped virtual memory + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid argument, see printed logs + * - ESP_ERR_NOT_SUPPORTED: Only on ESP32, PSRAM is not a supported physical memory target + * - ESP_ERR_NOT_FOUND: No enough size free block to use + * - ESP_ERR_NO_MEM: Out of memory, this API will allocate some heap memory for internal usage + * - ESP_ERR_INVALID_STATE: Paddr is mapped already, this API will return corresponding vaddr_start of the previously mapped block. + * Only to-be-mapped paddr block is totally enclosed by a previously mapped block will lead to this error: + * new_block_start new_block_end + * |-------- New Block --------| + * |--------------- Block ---------------| + * block_start block_end + * + */ +esp_err_t esp_mmu_map(esp_paddr_t paddr_start, size_t size, mmu_mem_caps_t caps, mmu_target_t target, void **out_ptr); + +/** + * @brief Unmap a previously mapped virtual memory block + * + * @note This API does not guarantee thread safety + * + * @param[in] ptr Start address of the virtual memory + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Null pointer + * - ESP_ERR_NOT_FOUND: Vaddr is not in external memory, or it's not mapped yet + */ +esp_err_t esp_mmu_unmap(void *ptr); + +/** + * @brief Get largest consecutive free external virtual memory block size, with given capabilities and given physical target + * + * @param[in] caps Bitwise OR of MMU_MEM_CAP_* flags indicating the memory block + * @param[in] target Physical memory target you're going to map to, see `mmu_target_t`. + * @param[out] out_len Largest free block length, in bytes. + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Invalid arguments, could be null pointer + */ +esp_err_t esp_mmu_map_get_max_consecutive_free_block_size(mmu_mem_caps_t caps, mmu_target_t target, size_t *out_len); + +/** + * Dump all the previously mapped blocks + * + * @note This API shall not be called from an ISR. + * @note This API does not guarantee thread safety + * + * @param stream stream to print information to; use stdout or stderr to print + * to the console; use fmemopen/open_memstream to print to a + * string buffer. + * @return + * - ESP_OK + */ +esp_err_t esp_mmu_map_dump_mapped_blocks(FILE* stream); + +/** + * @brief Convert virtual address to physical address + * + * @param[in] vaddr Virtual address + * @param[out] out_paddr Physical address + * @param[out] out_target Physical memory target, see `mmu_target_t` + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Null pointer, or vaddr is not within external memory + * - ESP_ERR_NOT_FOUND: Vaddr is not mapped yet + */ +esp_err_t esp_mmu_vaddr_to_paddr(void *vaddr, esp_paddr_t *out_paddr, mmu_target_t *out_target); + +/** + * @brief Convert physical address to virtual address + * + * @param[in] paddr Physical address + * @param[in] target Physical memory target, see `mmu_target_t` + * @param[in] type Virtual address type, could be either instruction or data + * @param[out] out_vaddr Virtual address + * + * @return + * - ESP_OK + * - ESP_ERR_INVALID_ARG: Null pointer + * - ESP_ERR_NOT_FOUND: Paddr is not mapped yet + */ +esp_err_t esp_mmu_paddr_to_vaddr(esp_paddr_t paddr, mmu_target_t target, mmu_vaddr_t type, void **out_vaddr); + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_mm/include/esp_private/esp_mmu_map_private.h b/components/esp_mm/include/esp_private/esp_mmu_map_private.h new file mode 100644 index 00000000000..d51817542b6 --- /dev/null +++ b/components/esp_mm/include/esp_private/esp_mmu_map_private.h @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "esp_err.h" +#include "hal/mmu_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Memory Mapping Private APIs for MMU supported memory + */ + +/** + * @brief Initialise the MMU MMAP driver + * + * This is called once in the IDF startup code. Don't call it in applications + */ +void esp_mmu_map_init(void); + +/** + * @brief Reserve a consecutive external virtual memory block, with given capabilities and size + * + * @note This private API shall be only called internally during startup stage. DO NOT call + * this API in your applications + * + * @param[in] size Size, in bytes, the amount of memory to find + * @param[in] caps Bitwise OR of `mmu_mem_caps_t` flags indicating the memory block capability + * @param[in] target Target memory type. See `mmu_target_t` + * @param[out] out_ptr Pointer to start address of the memory block that is reserved + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_ARG: Invalid arguments, could be wrong caps makeup, or null pointer + * - ESP_ERR_NOT_FOUND: Didn't find enough memory with give caps + */ +esp_err_t esp_mmu_map_reserve_block_with_caps(size_t size, mmu_mem_caps_t caps, mmu_target_t target, const void **out_ptr); + +/* + * @brief Dump all mapped blocks + * + * @return + * - ESP_OK + */ +esp_err_t esp_mmu_map_dump_mapped_blocks_private(void); + + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_mm/port/esp32/ext_mem_layout.c b/components/esp_mm/port/esp32/ext_mem_layout.c new file mode 100644 index 00000000000..312e902c245 --- /dev/null +++ b/components/esp_mm/port/esp32/ext_mem_layout.c @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "soc/ext_mem_defs.h" +#include "../ext_mem_layout.h" + +/** + * These regions is referring to linear address + * The start addresses in this list should always be sorted from low to high, as MMU driver will need to + * coalesce adjacent regions + */ +const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { + [0] = { + .start = SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_IRAM0_LINEAR), + .bus_id = CACHE_BUS_IBUS0, + .targets = MMU_TARGET_FLASH0, + .caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_32BIT, + }, + [1] = { + .start = SOC_MMU_DROM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_DROM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_DROM0_LINEAR), + .bus_id = CACHE_BUS_DBUS0, + .targets = MMU_TARGET_FLASH0, + .caps = MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, + [2] = { + .start = SOC_MMU_DRAM1_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_DRAM1_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_DRAM1_LINEAR), + .bus_id = CACHE_BUS_DBUS1, + .targets = MMU_TARGET_PSRAM0, + .caps = MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, + +}; diff --git a/components/esp_mm/port/esp32c2/ext_mem_layout.c b/components/esp_mm/port/esp32c2/ext_mem_layout.c new file mode 100644 index 00000000000..d81ec0cc82d --- /dev/null +++ b/components/esp_mm/port/esp32c2/ext_mem_layout.c @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "soc/ext_mem_defs.h" +#include "../ext_mem_layout.h" + +/** + * The start addresses in this list should always be sorted from low to high, as MMU driver will need to + * coalesce adjacent regions + */ +const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { + [0] = { + .start = SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_IRAM0_LINEAR), + .bus_id = CACHE_BUS_IBUS0 | CACHE_BUS_DBUS0, + .targets = MMU_TARGET_FLASH0, + .caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, +}; diff --git a/components/esp_mm/port/esp32c3/ext_mem_layout.c b/components/esp_mm/port/esp32c3/ext_mem_layout.c new file mode 100644 index 00000000000..d81ec0cc82d --- /dev/null +++ b/components/esp_mm/port/esp32c3/ext_mem_layout.c @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "soc/ext_mem_defs.h" +#include "../ext_mem_layout.h" + +/** + * The start addresses in this list should always be sorted from low to high, as MMU driver will need to + * coalesce adjacent regions + */ +const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { + [0] = { + .start = SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_IRAM0_LINEAR), + .bus_id = CACHE_BUS_IBUS0 | CACHE_BUS_DBUS0, + .targets = MMU_TARGET_FLASH0, + .caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, +}; diff --git a/components/esp_mm/port/esp32c6/ext_mem_layout.c b/components/esp_mm/port/esp32c6/ext_mem_layout.c new file mode 100644 index 00000000000..7158be4c992 --- /dev/null +++ b/components/esp_mm/port/esp32c6/ext_mem_layout.c @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "soc/ext_mem_defs.h" +#include "../ext_mem_layout.h" +#include "hal/mmu_types.h" + +/** + * The start addresses in this list should always be sorted from low to high, as MMU driver will need to + * coalesce adjacent regions + */ +const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { + [0] = { + .start = SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_IRAM0_LINEAR), + .bus_id = CACHE_BUS_IBUS0 | CACHE_BUS_DBUS0, + .targets = MMU_TARGET_FLASH0, + .caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, +}; diff --git a/components/esp_mm/port/esp32h2/ext_mem_layout.c b/components/esp_mm/port/esp32h2/ext_mem_layout.c new file mode 100644 index 00000000000..7158be4c992 --- /dev/null +++ b/components/esp_mm/port/esp32h2/ext_mem_layout.c @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "soc/ext_mem_defs.h" +#include "../ext_mem_layout.h" +#include "hal/mmu_types.h" + +/** + * The start addresses in this list should always be sorted from low to high, as MMU driver will need to + * coalesce adjacent regions + */ +const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { + [0] = { + .start = SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_IRAM0_LINEAR), + .bus_id = CACHE_BUS_IBUS0 | CACHE_BUS_DBUS0, + .targets = MMU_TARGET_FLASH0, + .caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, +}; diff --git a/components/esp_mm/port/esp32h4/ext_mem_layout.c b/components/esp_mm/port/esp32h4/ext_mem_layout.c new file mode 100644 index 00000000000..d81ec0cc82d --- /dev/null +++ b/components/esp_mm/port/esp32h4/ext_mem_layout.c @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "soc/ext_mem_defs.h" +#include "../ext_mem_layout.h" + +/** + * The start addresses in this list should always be sorted from low to high, as MMU driver will need to + * coalesce adjacent regions + */ +const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { + [0] = { + .start = SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_IRAM0_LINEAR), + .bus_id = CACHE_BUS_IBUS0 | CACHE_BUS_DBUS0, + .targets = MMU_TARGET_FLASH0, + .caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, +}; diff --git a/components/esp_mm/port/esp32s2/ext_mem_layout.c b/components/esp_mm/port/esp32s2/ext_mem_layout.c new file mode 100644 index 00000000000..4932ad87506 --- /dev/null +++ b/components/esp_mm/port/esp32s2/ext_mem_layout.c @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "soc/ext_mem_defs.h" +#include "../ext_mem_layout.h" + +/** + * These regions is referring to linear address + * The start addresses in this list should always be sorted from low to high, as MMU driver will need to + * coalesce adjacent regions + */ +const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { + [0] = { + .start = SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_IRAM0_LINEAR), + .bus_id = CACHE_BUS_IBUS0, + .targets = MMU_TARGET_FLASH0 | MMU_TARGET_PSRAM0, + .caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_32BIT, + }, + [1] = { + .start = SOC_MMU_DROM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_DROM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_DROM0_LINEAR), + .bus_id = CACHE_BUS_IBUS2, + .targets = MMU_TARGET_FLASH0 | MMU_TARGET_PSRAM0, + .caps = MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, + [2] = { + .start = SOC_MMU_DPORT_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_DPORT_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_DPORT_LINEAR), + .bus_id = CACHE_BUS_DBUS2, + .targets = MMU_TARGET_FLASH0 | MMU_TARGET_PSRAM0, + .caps = MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT, + }, + [3] = { + .start = SOC_MMU_DRAM1_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_DRAM1_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_DRAM1_LINEAR), + .bus_id = CACHE_BUS_DBUS1, + .targets = MMU_TARGET_FLASH0 | MMU_TARGET_PSRAM0, + .caps = MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, + [4] = { + .start = SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_DRAM0_LINEAR), + .bus_id = CACHE_BUS_DBUS0, + .targets = MMU_TARGET_FLASH0 | MMU_TARGET_PSRAM0, + .caps = MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, +}; diff --git a/components/esp_mm/port/esp32s3/ext_mem_layout.c b/components/esp_mm/port/esp32s3/ext_mem_layout.c new file mode 100644 index 00000000000..acd98cd2b1e --- /dev/null +++ b/components/esp_mm/port/esp32s3/ext_mem_layout.c @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "soc/ext_mem_defs.h" +#include "../ext_mem_layout.h" + +/** + * The start addresses in this list should always be sorted from low to high, as MMU driver will need to + * coalesce adjacent regions + */ +const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { + [0] = { + .start = SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, + .end = SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, + .size = BUS_SIZE(SOC_MMU_IRAM0_LINEAR), + .bus_id = CACHE_BUS_IBUS0 | CACHE_BUS_DBUS0, + .targets = MMU_TARGET_FLASH0 | MMU_TARGET_PSRAM0, + .caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT, + }, +}; diff --git a/components/esp_mm/test_apps/mmap/CMakeLists.txt b/components/esp_mm/test_apps/mmap/CMakeLists.txt new file mode 100644 index 00000000000..04ae1b20f5c --- /dev/null +++ b/components/esp_mm/test_apps/mmap/CMakeLists.txt @@ -0,0 +1,20 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(mmap_test) + +if(CONFIG_COMPILER_DUMP_RTL_FILES) + add_custom_target(check_test_app_sections ALL + COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py + --rtl-dir ${CMAKE_BINARY_DIR}/esp-idf/esp_mm/ + --elf-file ${CMAKE_BINARY_DIR}/mmap_test.elf + find-refs + --from-sections=.iram0.text + --to-sections=.flash.text,.flash.rodata + --exit-code + DEPENDS ${elf} + ) +endif() diff --git a/components/esp_mm/test_apps/mmap/README.md b/components/esp_mm/test_apps/mmap/README.md new file mode 100644 index 00000000000..a8b7833fa30 --- /dev/null +++ b/components/esp_mm/test_apps/mmap/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/components/esp_mm/test_apps/mmap/main/CMakeLists.txt b/components/esp_mm/test_apps/mmap/main/CMakeLists.txt new file mode 100644 index 00000000000..a99935cb691 --- /dev/null +++ b/components/esp_mm/test_apps/mmap/main/CMakeLists.txt @@ -0,0 +1,15 @@ +set(srcs "test_app_main.c") + +list(APPEND srcs "test_mmap.c" + "test_mmap_hw.c") + + +# In order for the cases defined by `TEST_CASE` to be linked into the final elf, +# the component can be registered as WHOLE_ARCHIVE +idf_component_register(SRCS ${srcs} + PRIV_REQUIRES test_utils spi_flash esp_mm + WHOLE_ARCHIVE) + +idf_component_get_property(lib_name esp_mm COMPONENT_LIB) +# Add this to skip checking mapping to a paddr range that is enclosed by a previous mapped paddr range +target_compile_definitions(${lib_name} PRIVATE ESP_MMAP_TEST_ALLOW_MAP_TO_MAPPED_PADDR) diff --git a/components/esp_mm/test_apps/mmap/main/test_app_main.c b/components/esp_mm/test_apps/mmap/main/test_app_main.c new file mode 100644 index 00000000000..95fc6dcab24 --- /dev/null +++ b/components/esp_mm/test_apps/mmap/main/test_app_main.c @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "unity.h" +#include "unity_test_utils.h" +#include "esp_heap_caps.h" + +/** + * Hardware related tests, e.g. + * - traversing all vaddr range to check their attributes + * + * These tests need certain number of internal resources (heap memory), as they uses up the vaddr ranges + * On ESP32, it should be around 450 + * On ESP32S2, it should be around 600 + * On other chips, it should be around 400 + */ +#define TEST_MEMORY_LEAK_THRESHOLD (-650) + +static size_t before_free_8bit; +static size_t before_free_32bit; + +static void check_leak(size_t before_free, size_t after_free, const char *type) +{ + ssize_t delta = after_free - before_free; + printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta); + TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak"); +} + +void setUp(void) +{ + before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); +} + +void tearDown(void) +{ + size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT); + size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT); + check_leak(before_free_8bit, after_free_8bit, "8BIT"); + check_leak(before_free_32bit, after_free_32bit, "32BIT"); +} + +void app_main(void) +{ + /* + _____ ___________ ___ ______ ___ ___ ______ _____ _____ _____ _____ + | ___/ ___| ___ \ | \/ || \/ | / _ \ | ___ \ |_ _| ___/ ___|_ _| + | |__ \ `--.| |_/ / | . . || . . |/ /_\ \| |_/ / | | | |__ \ `--. | | + | __| `--. \ __/ | |\/| || |\/| || _ || __/ | | | __| `--. \ | | + | |___/\__/ / | | | | || | | || | | || | | | | |___/\__/ / | | + \____/\____/\_| \_| |_/\_| |_/\_| |_/\_| \_/ \____/\____/ \_/ + */ + printf(" _____ ___________ ___ ______ ___ ___ ______ _____ _____ _____ _____\r\n"); + printf("| ___/ ___| ___ \\ | \\/ || \\/ | / _ \\ | ___ \\ |_ _| ___/ ___|_ _|\r\n"); + printf("| |__ \\ `--.| |_/ / | . . || . . |/ /_\\ \\| |_/ / | | | |__ \\ `--. | |\r\n"); + printf("| __| `--. \\ __/ | |\\/| || |\\/| || _ || __/ | | | __| `--. \\ | |\r\n"); + printf("| |___/\\__/ / | | | | || | | || | | || | | | | |___/\\__/ / | |\r\n"); + printf("\\____/\\____/\\_| \\_| |_/\\_| |_/\\_| |_/\\_| \\_/ \\____/\\____/ \\_/\r\n"); + + unity_run_menu(); +} diff --git a/components/esp_mm/test_apps/mmap/main/test_mmap.c b/components/esp_mm/test_apps/mmap/main/test_mmap.c new file mode 100644 index 00000000000..e12903aaf8f --- /dev/null +++ b/components/esp_mm/test_apps/mmap/main/test_mmap.c @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include +#include +#include "inttypes.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "unity.h" +#include "esp_heap_caps.h" +#include "esp_partition.h" + +#include "esp_mmu_map.h" +#include "esp_rom_sys.h" + +#define TEST_BLOCK_SIZE CONFIG_MMU_PAGE_SIZE + +const static char *TAG = "MMU_TEST"; + +static const esp_partition_t *s_get_partition(void) +{ + //Find the "storage1" partition defined in `partitions.csv` + const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1"); + if (!result) { + ESP_LOGE(TAG, "Can't find the partition, please define it correctly in `partitions.csv`"); + abort(); + } + return result; +} + +TEST_CASE("Can dump mapped block stats", "[mmu]") +{ + const esp_partition_t *part = s_get_partition(); + ESP_LOGI(TAG, "found partition '%s' at offset 0x%"PRIx32" with size 0x%"PRIx32, part->label, part->address, part->size); + + void *ptr0 = NULL; + TEST_ESP_OK(esp_mmu_map(part->address, TEST_BLOCK_SIZE, MMU_MEM_CAP_READ, MMU_TARGET_FLASH0, &ptr0)); + void *ptr1 = NULL; + TEST_ESP_OK(esp_mmu_map(part->address, TEST_BLOCK_SIZE, MMU_MEM_CAP_EXEC, MMU_TARGET_FLASH0, &ptr1)); + void *ptr2 = NULL; + TEST_ESP_OK(esp_mmu_map(part->address, TEST_BLOCK_SIZE, MMU_MEM_CAP_READ, MMU_TARGET_FLASH0, &ptr2)); + + esp_mmu_map_dump_mapped_blocks(stdout); + + TEST_ESP_OK(esp_mmu_unmap(ptr0)); + TEST_ESP_OK(esp_mmu_unmap(ptr1)); + TEST_ESP_OK(esp_mmu_unmap(ptr2)); +} diff --git a/components/esp_mm/test_apps/mmap/main/test_mmap_hw.c b/components/esp_mm/test_apps/mmap/main/test_mmap_hw.c new file mode 100644 index 00000000000..d48cf53992f --- /dev/null +++ b/components/esp_mm/test_apps/mmap/main/test_mmap_hw.c @@ -0,0 +1,193 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include +#include +#include +#include "inttypes.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "unity.h" +#include "esp_heap_caps.h" +#include "esp_partition.h" +#include "esp_flash.h" + +#include "esp_mmu_map.h" +#include "esp_rom_sys.h" + +/** + * This file contains simple hw tests for vaddr memory regions + * + * Traversing all vaddr memory regions to see if they have correct capabilities + */ + +const static char *TAG = "MMU_TEST"; + +static const esp_partition_t *s_get_partition(void) +{ + //Find the "storage1" partition defined in `partitions.csv` + const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1"); + if (!result) { + ESP_LOGE(TAG, "Can't find the partition, please define it correctly in `partitions.csv`"); + abort(); + } + return result; +} + +/** + * Do following two tests: + * - test all readable vaddr can map to flash + * - test all executable vaddr can map to flash + * + * manually. Do a reset before a test start, as each of the tests + * will map as much as possible, and don't do unmap. + */ + +#define TEST_BLOCK_SIZE CONFIG_MMU_PAGE_SIZE + +typedef struct test_block_info_ { + uint32_t vaddr; + LIST_ENTRY(test_block_info_) entries; +} test_block_info_t; + +static LIST_HEAD(test_block_list_head_, test_block_info_) test_block_head; +static DRAM_ATTR uint8_t sector_buf[TEST_BLOCK_SIZE]; + + +static void s_fill_random_data(uint8_t *buffer, size_t size, int random_seed) +{ + srand(random_seed); + for (int i = 0 ; i < size; i++) { + buffer[i] = rand() % 0xff; + } +} + +static bool s_test_mmap_data_by_random(uint8_t *mblock_ptr, size_t size, int random_seed) +{ + srand(random_seed); + uint8_t *test_ptr = mblock_ptr; + + for (int i = 0; i < size; i++) { + uint8_t test_data = rand() % 0xff; + if(test_data != test_ptr[i]) { + printf("i: %d\n", i); + printf("test_data: %d\n", test_data); + printf("test_ptr[%d]: %d\n", i, test_ptr[i]); + printf("sector_buf[%d]: %d\n", i, sector_buf[i]); + ESP_EARLY_LOGE(TAG, "FAIL!!!!!!"); + return false; + } + } + return true; +} + +TEST_CASE("test all readable vaddr can map to flash", "[mmu]") +{ + //Get the partition used for SPI1 erase operation + const esp_partition_t *part = s_get_partition(); + ESP_LOGI(TAG, "found partition '%s' at offset 0x%"PRIx32" with size 0x%"PRIx32, part->label, part->address, part->size); + //Erase whole region + TEST_ESP_OK(esp_flash_erase_region(part->flash_chip, part->address, part->size)); + + ESP_LOGI(TAG, "TEST_BLOCK_SIZE: 0x%x", TEST_BLOCK_SIZE); + + int test_seed = 299; + s_fill_random_data(sector_buf, sizeof(sector_buf), test_seed); + ESP_LOGV(TAG, "rand seed: %d, write flash addr: %p...", test_seed, (void *)part->address); + TEST_ESP_OK(esp_flash_write(part->flash_chip, sector_buf, part->address, sizeof(sector_buf))); + + + esp_err_t ret = ESP_FAIL; + int count = 0; + LIST_INIT(&test_block_head); + while (1) { + test_block_info_t *block_info = heap_caps_calloc(1, sizeof(test_block_info_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + TEST_ASSERT(block_info && "no mem"); + + void *ptr = NULL; + ret = esp_mmu_map(part->address, TEST_BLOCK_SIZE, MMU_MEM_CAP_READ, MMU_TARGET_FLASH0, &ptr); + if (ret == ESP_OK) { + ESP_LOGI(TAG, "ptr is %p", ptr); + bool success = s_test_mmap_data_by_random((uint8_t *)ptr, sizeof(sector_buf), test_seed); + TEST_ASSERT(success); + } else if (ret == ESP_ERR_NOT_FOUND) { + free(block_info); + break; + } else { + ESP_LOGI(TAG, "ret: 0x%x", ret); + TEST_ASSERT(false); + } + + block_info->vaddr = (uint32_t)ptr; + LIST_INSERT_HEAD(&test_block_head, block_info, entries); + count++; + } + + ESP_LOGI(TAG, "no more free block, finish test, test block size: 0x%x, count: 0d%d", TEST_BLOCK_SIZE, count); + + test_block_info_t *block_to_free = LIST_FIRST(&test_block_head); + test_block_info_t *temp = NULL; + while (block_to_free) { + temp = block_to_free; + TEST_ESP_OK(esp_mmu_unmap((void *)block_to_free->vaddr)); + block_to_free = LIST_NEXT(block_to_free, entries); + free(temp); + } +} + + +TEST_CASE("test all executable vaddr can map to flash", "[mmu]") +{ + //Get the partition used for SPI1 erase operation + const esp_partition_t *part = s_get_partition(); + ESP_LOGI(TAG, "found partition '%s' at offset 0x%"PRIx32" with size 0x%"PRIx32, part->label, part->address, part->size); + //Erase whole region + TEST_ESP_OK(esp_flash_erase_region(part->flash_chip, part->address, part->size)); + + esp_err_t ret = ESP_FAIL; + int count = 0; + LIST_INIT(&test_block_head); + while (1) { + test_block_info_t *block_info = heap_caps_calloc(1, sizeof(test_block_info_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + TEST_ASSERT(block_info && "no mem"); + + void *ptr = NULL; + ret = esp_mmu_map(part->address, TEST_BLOCK_SIZE, MMU_MEM_CAP_EXEC, MMU_TARGET_FLASH0, &ptr); + if (ret == ESP_OK) { + ESP_LOGI(TAG, "ptr is %p", ptr); + for (int i = 0; i < TEST_BLOCK_SIZE; i += 0x100) { + uint32_t vaddr = (uint32_t)ptr + i; + uint32_t paddr = 0; + mmu_target_t mem_target = 0; + TEST_ESP_OK(esp_mmu_vaddr_to_paddr((void *)vaddr, &paddr, &mem_target)); + TEST_ASSERT(paddr == part->address + i); + ESP_LOGV(TAG, "paddr: %p, on %s", (void *)paddr, (mem_target) == MMU_TARGET_FLASH0 ? "Flash" : "PSRAM"); + } + } + else if (ret == ESP_ERR_NOT_FOUND) { + free(block_info); + break; + } else { + TEST_ASSERT(false); + } + + block_info->vaddr = (uint32_t)ptr; + LIST_INSERT_HEAD(&test_block_head, block_info, entries); + count++; + } + + ESP_LOGI(TAG, "no more free block, finish test, test block size: 0x%x, count: 0d%d", TEST_BLOCK_SIZE, count); + + test_block_info_t *block_to_free = LIST_FIRST(&test_block_head); + test_block_info_t *temp = NULL; + while (block_to_free) { + temp = block_to_free; + TEST_ESP_OK(esp_mmu_unmap((void *)block_to_free->vaddr)); + block_to_free = LIST_NEXT(block_to_free, entries); + free(temp); + } +} diff --git a/components/esp_mm/test_apps/mmap/partitions.csv b/components/esp_mm/test_apps/mmap/partitions.csv new file mode 100644 index 00000000000..6b057cd3544 --- /dev/null +++ b/components/esp_mm/test_apps/mmap/partitions.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, 0x9000, 0x6000, +phy_init, data, phy, 0xf000, 0x1000, +factory, app, factory, 0x10000, 1M, +storage1, data, fat, , 512K, diff --git a/components/esp_mm/test_apps/mmap/pytest_mmap.py b/components/esp_mm/test_apps/mmap/pytest_mmap.py new file mode 100644 index 00000000000..945b0b92b92 --- /dev/null +++ b/components/esp_mm/test_apps/mmap/pytest_mmap.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.supported_targets +@pytest.mark.generic +@pytest.mark.parametrize( + 'config', + [ + 'release', + ], + indirect=True, +) +def test_mmap(dut: Dut) -> None: + dut.run_all_single_board_cases(group='mmu', timeout=600) diff --git a/components/esp_mm/test_apps/mmap/sdkconfig.ci.release b/components/esp_mm/test_apps/mmap/sdkconfig.ci.release new file mode 100644 index 00000000000..22bd3f16c0d --- /dev/null +++ b/components/esp_mm/test_apps/mmap/sdkconfig.ci.release @@ -0,0 +1,6 @@ +# set compilier optimization level +CONFIG_COMPILER_OPTIMIZATION_SIZE=y +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y + +# we can silent the assertion to save the binary footprint +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y diff --git a/components/esp_mm/test_apps/mmap/sdkconfig.defaults b/components/esp_mm/test_apps/mmap/sdkconfig.defaults new file mode 100644 index 00000000000..ee544f97f7e --- /dev/null +++ b/components/esp_mm/test_apps/mmap/sdkconfig.defaults @@ -0,0 +1,7 @@ +CONFIG_ESP_TASK_WDT=n + +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" + +CONFIG_COMPILER_DUMP_RTL_FILES=y diff --git a/components/esp_partition/partition_target.c b/components/esp_partition/partition_target.c index e9a89edaa2b..25456e919c5 100644 --- a/components/esp_partition/partition_target.c +++ b/components/esp_partition/partition_target.c @@ -45,7 +45,7 @@ esp_err_t esp_partition_read(const esp_partition_t *partition, /* Encrypted partitions need to be read via a cache mapping */ const void *buf; - spi_flash_mmap_handle_t handle; + esp_partition_mmap_handle_t handle; esp_err_t err = esp_partition_mmap(partition, src_offset, size, SPI_FLASH_MMAP_DATA, &buf, &handle); diff --git a/components/esp_psram/CMakeLists.txt b/components/esp_psram/CMakeLists.txt index 8fafa87a04b..48333512b29 100644 --- a/components/esp_psram/CMakeLists.txt +++ b/components/esp_psram/CMakeLists.txt @@ -2,7 +2,7 @@ idf_build_get_property(target IDF_TARGET) set(includes "include") -set(priv_requires heap spi_flash) +set(priv_requires heap spi_flash esp_mm) if(${target} STREQUAL "esp32") list(APPEND priv_requires bootloader_support) # [refactor-todo]: requires "driver" for `spicommon_periph_claim` @@ -13,9 +13,7 @@ set(srcs) if(CONFIG_SPIRAM) list(APPEND srcs "esp_psram.c" - "mmu.c" - "mmu_psram_flash.c" - "ext_mem_layout.c") + "mmu_psram_flash.c") if(${target} STREQUAL "esp32") list(APPEND srcs "esp32/esp_psram_extram_cache.c" diff --git a/components/esp_psram/esp_psram.c b/components/esp_psram/esp_psram.c index ce23e4f9337..008d9a4533c 100644 --- a/components/esp_psram/esp_psram.c +++ b/components/esp_psram/esp_psram.c @@ -26,7 +26,8 @@ #include "esp_private/mmu_psram_flash.h" #include "esp_psram_impl.h" #include "esp_psram.h" -#include "mmu.h" +#include "esp_private/esp_mmu_map_private.h" +#include "esp_mmu_map.h" #if CONFIG_IDF_TARGET_ESP32 #include "esp32/himem.h" @@ -184,15 +185,6 @@ esp_err_t esp_psram_init(void) ESP_EARLY_LOGV(TAG, "after copy .rodata, used page is %d, start_page is %d, psram_available_size is %d B", used_page, start_page, psram_available_size); #endif //#if CONFIG_SPIRAM_RODATA - /** - * For now, - * - we only need to use MMU driver when PSRAM is enabled - * - MMU driver isn't public - * - * So we call `esp_mmu_init()` here, instead of calling it in startup code. - */ - esp_mmu_init(); - //----------------------------------Map the PSRAM physical range to MMU-----------------------------// /** * @note 2 @@ -203,12 +195,12 @@ esp_err_t esp_psram_init(void) size_t total_mapped_size = 0; size_t size_to_map = 0; size_t byte_aligned_size = 0; - ret = esp_mmu_get_largest_free_block(MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_8BIT | MMU_MEM_CAP_32BIT, &byte_aligned_size); + ret = esp_mmu_map_get_max_consecutive_free_block_size(MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_8BIT | MMU_MEM_CAP_32BIT, MMU_TARGET_PSRAM0, &byte_aligned_size); assert(ret == ESP_OK); size_to_map = MIN(byte_aligned_size, psram_available_size); const void *v_start_8bit_aligned = NULL; - ret = esp_mmu_find_vaddr_range(size_to_map, MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_8BIT | MMU_MEM_CAP_32BIT, &v_start_8bit_aligned); + ret = esp_mmu_map_reserve_block_with_caps(size_to_map, MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_8BIT | MMU_MEM_CAP_32BIT, MMU_TARGET_PSRAM0, &v_start_8bit_aligned); assert(ret == ESP_OK); #if CONFIG_IDF_TARGET_ESP32 @@ -248,12 +240,12 @@ esp_err_t esp_psram_init(void) size_to_map = psram_available_size - total_mapped_size; size_t word_aligned_size = 0; - ret = esp_mmu_get_largest_free_block(MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT, &word_aligned_size); + ret = esp_mmu_map_get_max_consecutive_free_block_size(MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT, MMU_TARGET_PSRAM0, &word_aligned_size); assert(ret == ESP_OK); size_to_map = MIN(word_aligned_size, size_to_map); const void *v_start_32bit_aligned = NULL; - ret = esp_mmu_find_vaddr_range(size_to_map, MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT, &v_start_32bit_aligned); + ret = esp_mmu_map_reserve_block_with_caps(size_to_map, MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT, MMU_TARGET_PSRAM0, &v_start_32bit_aligned); assert(ret == ESP_OK); mmu_hal_map_region(0, MMU_TARGET_PSRAM0, (intptr_t)v_start_32bit_aligned, MMU_PAGE_TO_BYTES(start_page), size_to_map, &actual_mapped_len); diff --git a/components/esp_psram/ext_mem_layout.c b/components/esp_psram/ext_mem_layout.c deleted file mode 100644 index 1a5a61dc89b..00000000000 --- a/components/esp_psram/ext_mem_layout.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include "sdkconfig.h" -#include "soc/ext_mem_defs.h" -#include "ext_mem_layout.h" -#include "mmu.h" - - -#if CONFIG_IDF_TARGET_ESP32 -/** - * These regions is referring to linear address - * The start addresses in this list should always be sorted from low to high, as MMU driver will need to - * coalesce adjacent regions - */ -const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { - - /*linear start linear end bus size bus ID, bus capabilities */ - - //Can be used for text - {SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_IRAM0_LINEAR), CACHE_BUS_IBUS0, MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT}, - //Can be used for text - {SOC_MMU_IRAM1_LINEAR_ADDRESS_LOW, SOC_MMU_IRAM1_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_IRAM1_LINEAR), CACHE_BUS_IBUS1, MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT}, - //Can be used for text - {SOC_MMU_IROM0_LINEAR_ADDRESS_LOW, SOC_MMU_IROM0_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_IROM0_LINEAR), CACHE_BUS_IBUS2, MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT}, - //Can be used for rodata - {SOC_MMU_DROM0_LINEAR_ADDRESS_LOW, SOC_MMU_DROM0_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_DROM0_LINEAR), CACHE_BUS_DBUS0, MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT}, - //Can be used for PSRAM - {SOC_MMU_DRAM1_LINEAR_ADDRESS_LOW, SOC_MMU_DRAM1_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_DRAM1_LINEAR), CACHE_BUS_DBUS1, MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT}, -}; - - -#elif CONFIG_IDF_TARGET_ESP32S2 -/** - * These regions is referring to linear address - * The start addresses in this list should always be sorted from low to high, as MMU driver will need to - * coalesce adjacent regions - */ -const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { - - /*linear start linear end bus size bus ID, bus capabilities */ - - //Can be used for text - {SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_IRAM0_LINEAR), CACHE_BUS_IBUS0, MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT}, - //Can be used for text - {SOC_MMU_IRAM1_LINEAR_ADDRESS_LOW, SOC_MMU_IRAM1_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_IRAM1_LINEAR), CACHE_BUS_IBUS1, MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT}, - //Can be used for Flash rodata, connected by IBUS - {SOC_MMU_DROM0_LINEAR_ADDRESS_LOW, SOC_MMU_DROM0_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_DROM0_LINEAR), CACHE_BUS_IBUS2, MMU_MEM_CAP_READ | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT}, - //Can be used for PSRAM - {SOC_MMU_DPORT_LINEAR_ADDRESS_LOW, SOC_MMU_DPORT_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_DPORT_LINEAR), CACHE_BUS_DBUS2, MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT}, - //Can be used for PSRAM - {SOC_MMU_DRAM1_LINEAR_ADDRESS_LOW, SOC_MMU_DRAM1_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_DRAM1_LINEAR), CACHE_BUS_DBUS1, MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT}, - //Can be used for PSRAM - {SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW, SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_DRAM0_LINEAR), CACHE_BUS_DBUS0, MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT}, -}; - - -#elif CONFIG_IDF_TARGET_ESP32S3 -/** - * The start addresses in this list should always be sorted from low to high, as MMU driver will need to - * coalesce adjacent regions - */ -const mmu_mem_region_t g_mmu_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = { - - /*linear start linear end bus size bus ID, bus capabilities */ - - /** - * Can be used for Flash text, rodata, and PSRAM - * IRAM0 linear address should be always the same as DRAM0 linear address - */ - {SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW, SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH, BUS_SIZE(SOC_MMU_IRAM0_LINEAR), CACHE_BUS_IBUS0 | CACHE_BUS_DBUS0, MMU_MEM_CAP_EXEC | MMU_MEM_CAP_READ | MMU_MEM_CAP_WRITE | MMU_MEM_CAP_32BIT | MMU_MEM_CAP_8BIT}, -}; -#endif diff --git a/components/esp_psram/linker.lf b/components/esp_psram/linker.lf index f290b41bea7..aa6cb564e3d 100644 --- a/components/esp_psram/linker.lf +++ b/components/esp_psram/linker.lf @@ -3,8 +3,6 @@ archive: libesp_psram.a entries: if SPIRAM = y: - mmu (noflash) - if SPIRAM_MODE_QUAD = y: if IDF_TARGET_ESP32S3 = y: esp_psram_impl_quad (noflash) diff --git a/components/esp_psram/mmu.c b/components/esp_psram/mmu.c deleted file mode 100644 index 74d9a488fce..00000000000 --- a/components/esp_psram/mmu.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * This file will be redesigned into MMU driver, to maintain all the external - * memory contexts including: - * - Flash - * - PSRAM - * - DDR - * - * Now only MMU-PSRAM related private APIs - */ - -#include -#include -#include -#include "sdkconfig.h" -#include "esp_attr.h" -#include "esp_log.h" -#include "esp_check.h" -#include "soc/soc_caps.h" -#include "ext_mem_layout.h" -#include "freertos/FreeRTOS.h" -#include "hal/cache_types.h" -#include "hal/cache_ll.h" -#include "hal/mmu_types.h" -#include "hal/mmu_ll.h" -#include "mmu.h" - - -#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) -#define MMU_PAGE_SIZE CONFIG_MMU_PAGE_SIZE - -//This flag indicates the memory region is merged, we don't care about it anymore -#define MEM_REGION_MERGED -1 - -static const char *TAG = "mmu"; -extern int _instruction_reserved_start; -extern int _instruction_reserved_end; -extern int _rodata_reserved_start; -extern int _rodata_reserved_end; - -typedef struct mmu_linear_mem_ { - cache_bus_mask_t bus_id; - intptr_t start; - intptr_t end; - size_t pool_size; - intptr_t free_head; - size_t free_size; - int caps; -} mmu_linear_mem_t; - -typedef struct { - /** - * number of memory regions that are available, after coalescing, this number should be smaller than or equal to `SOC_MMU_LINEAR_ADDRESS_REGION_NUM` - */ - uint32_t num_regions; - /** - * This saves the available MMU linear address regions, - * after reserving flash .rodata and .text, and after coalescing. - * Only the first `num_regions` items are valid - */ - mmu_linear_mem_t mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM]; -} mmu_ctx_t; - -static mmu_ctx_t s_mmu_ctx; - - -static void s_reserve_irom_region(mmu_linear_mem_t *hw_mem_regions, int region_nums) -{ - /** - * We follow the way how 1st bootloader load flash .text: - * - * - Now IBUS addresses (between `_instruction_reserved_start` and `_instruction_reserved_end`) are consecutive on all chips, - * we strongly rely on this to calculate the .text length - */ - size_t irom_len_to_reserve = (uint32_t)&_instruction_reserved_end - (uint32_t)&_instruction_reserved_start; - assert((mmu_ll_vaddr_to_laddr((uint32_t)&_instruction_reserved_end) - mmu_ll_vaddr_to_laddr((uint32_t)&_instruction_reserved_start)) == irom_len_to_reserve); - - irom_len_to_reserve = ALIGN_UP_BY(irom_len_to_reserve, MMU_PAGE_SIZE); - cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, (uint32_t)&_instruction_reserved_start, irom_len_to_reserve); - - for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { - if (bus_mask & hw_mem_regions[i].bus_id) { - if (hw_mem_regions[i].pool_size <= irom_len_to_reserve) { - hw_mem_regions[i].free_head = hw_mem_regions[i].end; - hw_mem_regions[i].free_size = 0; - irom_len_to_reserve -= hw_mem_regions[i].pool_size; - } else { - hw_mem_regions[i].free_head = hw_mem_regions[i].free_head + irom_len_to_reserve; - hw_mem_regions[i].free_size -= irom_len_to_reserve; - } - } - } -} - -static void s_reserve_drom_region(mmu_linear_mem_t *hw_mem_regions, int region_nums) -{ - /** - * Similarly, we follow the way how 1st bootloader load flash .rodata: - */ - size_t drom_len_to_reserve = (uint32_t)&_rodata_reserved_end - (uint32_t)&_rodata_reserved_start; - assert((mmu_ll_vaddr_to_laddr((uint32_t)&_rodata_reserved_end) - mmu_ll_vaddr_to_laddr((uint32_t)&_rodata_reserved_start)) == drom_len_to_reserve); - - drom_len_to_reserve = ALIGN_UP_BY(drom_len_to_reserve, MMU_PAGE_SIZE); - cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, (uint32_t)&_rodata_reserved_start, drom_len_to_reserve); - - for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { - if (bus_mask & hw_mem_regions[i].bus_id) { - if (hw_mem_regions[i].pool_size <= drom_len_to_reserve) { - hw_mem_regions[i].free_head = hw_mem_regions[i].end; - hw_mem_regions[i].free_size = 0; - drom_len_to_reserve -= hw_mem_regions[i].pool_size; - } else { - hw_mem_regions[i].free_head = hw_mem_regions[i].free_head + drom_len_to_reserve; - hw_mem_regions[i].free_size -= drom_len_to_reserve; - } - } - } -} - -void esp_mmu_init(void) -{ - mmu_linear_mem_t hw_mem_regions[SOC_MMU_LINEAR_ADDRESS_REGION_NUM] = {}; - - for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { - hw_mem_regions[i].start = g_mmu_mem_regions[i].start; - hw_mem_regions[i].end = g_mmu_mem_regions[i].end; - hw_mem_regions[i].pool_size = g_mmu_mem_regions[i].size; - hw_mem_regions[i].free_size = g_mmu_mem_regions[i].size; - hw_mem_regions[i].free_head = g_mmu_mem_regions[i].start; - hw_mem_regions[i].bus_id = g_mmu_mem_regions[i].bus_id; - hw_mem_regions[i].caps = g_mmu_mem_regions[i].caps; -#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 - assert(__builtin_popcount(hw_mem_regions[i].bus_id) == 1); -#endif - assert(hw_mem_regions[i].pool_size % MMU_PAGE_SIZE == 0); - } - - //First reserve memory regions used for irom and drom, as we must follow the way how 1st bootloader load them - s_reserve_irom_region(hw_mem_regions, SOC_MMU_LINEAR_ADDRESS_REGION_NUM); - s_reserve_drom_region(hw_mem_regions, SOC_MMU_LINEAR_ADDRESS_REGION_NUM); - - if (SOC_MMU_LINEAR_ADDRESS_REGION_NUM > 1) { - //Now we can coalesce adjacent regions - for (int i = 1; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { - mmu_linear_mem_t *a = &hw_mem_regions[i - 1]; - mmu_linear_mem_t *b = &hw_mem_regions[i]; - if ((b->free_head == a->end) && (b->caps == a->caps)) { - a->caps = MEM_REGION_MERGED; - b->bus_id |= a->bus_id; - b->start = a->start; - b->pool_size += a->pool_size; - b->free_head = a->free_head; - b->free_size += a->free_size; - } - } - } - - //Count the mem regions left after coalescing - uint32_t region_num = 0; - for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { - if(hw_mem_regions[i].caps != MEM_REGION_MERGED) { - region_num++; - } - } - ESP_EARLY_LOGV(TAG, "after coalescing, %d regions are left", region_num); - - //Initialise `s_mmu_ctx.mem_regions[]`, as we've done all static allocation, to prepare available virtual memory regions - uint32_t available_region_idx = 0; - s_mmu_ctx.num_regions = region_num; - for (int i = 0; i < SOC_MMU_LINEAR_ADDRESS_REGION_NUM; i++) { - if (hw_mem_regions[i].caps == MEM_REGION_MERGED) { - continue; - } - - memcpy(&s_mmu_ctx.mem_regions[available_region_idx], &hw_mem_regions[i], sizeof(mmu_linear_mem_t)); - available_region_idx++; - } - - assert(available_region_idx == region_num); -} - -esp_err_t esp_mmu_get_largest_free_block(int caps, size_t *out_len) -{ - ESP_RETURN_ON_FALSE(out_len, ESP_ERR_INVALID_ARG, TAG, "null pointer"); - if (caps & MMU_MEM_CAP_EXEC) { - if ((caps & MMU_MEM_CAP_8BIT) || (caps & MMU_MEM_CAP_WRITE)) { - //None of the executable memory are expected to be 8-bit accessible or writable. - return ESP_ERR_INVALID_ARG; - } - } - *out_len = 0; - - size_t max = 0; - - for (int i = 0; i < s_mmu_ctx.num_regions; i++) { - if ((s_mmu_ctx.mem_regions[i].caps & caps) == caps) { - if (s_mmu_ctx.mem_regions[i].free_size > max) { - max = s_mmu_ctx.mem_regions[i].free_size; - } - } - } - - *out_len = max; - - return ESP_OK; -} - -esp_err_t esp_mmu_find_vaddr_range(size_t size, uint32_t caps, const void **out_ptr) -{ - ESP_RETURN_ON_FALSE(out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); - if (caps & MMU_MEM_CAP_EXEC) { - if ((caps & MMU_MEM_CAP_8BIT) || (caps & MMU_MEM_CAP_WRITE)) { - //None of the executable memory are expected to be 8-bit accessible or writable. - return ESP_ERR_INVALID_ARG; - } - caps |= MMU_MEM_CAP_32BIT; - } - - size_t aligned_size = ALIGN_UP_BY(size, MMU_PAGE_SIZE); - bool is_match = false; - uint32_t laddr = 0; - - for (int i = 0; i < s_mmu_ctx.num_regions; i++) { - if ((s_mmu_ctx.mem_regions[i].caps & caps) == caps) { - if (s_mmu_ctx.mem_regions[i].free_size < aligned_size) { - continue; - } else { - laddr = (uint32_t)s_mmu_ctx.mem_regions[i].free_head; - s_mmu_ctx.mem_regions[i].free_head += aligned_size; - s_mmu_ctx.mem_regions[i].free_size -= aligned_size; - is_match = true; - break; - } - } - } - ESP_RETURN_ON_FALSE(is_match, ESP_ERR_NOT_FOUND, TAG, "no such vaddr range"); - ESP_EARLY_LOGV(TAG, "found laddr is 0x%x", laddr); - - if (caps & MMU_MEM_CAP_EXEC) { - laddr = mmu_ll_laddr_to_vaddr(laddr, MMU_VADDR_INSTRUCTION); - } else { - laddr = mmu_ll_laddr_to_vaddr(laddr, MMU_VADDR_DATA); - } - *out_ptr = (void *)laddr; - - return ESP_OK; -} - -esp_err_t esp_mmu_dump_region_usage(void) -{ - for (int i = 0; i < s_mmu_ctx.num_regions; i++) { - ESP_EARLY_LOGI(TAG, "bus_id: 0x%x", s_mmu_ctx.mem_regions[i].bus_id); - ESP_EARLY_LOGI(TAG, "start: 0x%x", s_mmu_ctx.mem_regions[i].start); - ESP_EARLY_LOGI(TAG, "end: 0x%x", s_mmu_ctx.mem_regions[i].end); - ESP_EARLY_LOGI(TAG, "pool_size: 0x%x", s_mmu_ctx.mem_regions[i].pool_size); - ESP_EARLY_LOGI(TAG, "free_head: 0x%x", s_mmu_ctx.mem_regions[i].free_head); - ESP_EARLY_LOGI(TAG, "free_size: 0x%x", s_mmu_ctx.mem_regions[i].free_size); - ESP_EARLY_LOGI(TAG, "caps: 0x%x\n", s_mmu_ctx.mem_regions[i].caps); - } - - return ESP_OK; -} diff --git a/components/esp_psram/mmu.h b/components/esp_psram/mmu.h deleted file mode 100644 index 98dab602302..00000000000 --- a/components/esp_psram/mmu.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include -#include -#include "esp_err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * This file will be moved out of `esp_psram` component. And will be - * future MMU driver, to maintain all the external memory contexts including: - * - Flash - * - PSRAM - * - DDR - * - * Now only support ESP32, ESP32S2, ESP32S3 virtual address maintenance, and is internal - */ - - -#define MMU_MEM_CAP_EXEC (1<<0) -#define MMU_MEM_CAP_READ (1<<1) -#define MMU_MEM_CAP_WRITE (1<<2) -#define MMU_MEM_CAP_32BIT (1<<3) -#define MMU_MEM_CAP_8BIT (1<<4) - -/** - * @brief Initialise the MMU driver - * - * This is called once in the IDF startup code. Don't call it in applications - */ -void esp_mmu_init(void); - -/** - * @brief Get largest consecutive free external virtual memory block, with given capabilities - * - * @param[in] caps Bitwise OR of MMU_MEM_CAP_* flags indicating the memory block - * @param[out] out_len Largest free block length, in bytes. - * - * @return - * - ESP_OK: On success - * - ESP_ERR_INVALID_ARG: Invalid arguments, could be null pointer - */ -esp_err_t esp_mmu_get_largest_free_block(int caps, size_t *out_len); - -/** - * @brief Find a consecutive external virtual memory range, with given capabilities and size - * - * @param[in] size Size, in bytes, the amount of memory to find - * @param[in] caps Bitwise OR of MMU_MEM_CAP_* flags indicating the memory block - * @param[out] out_ptr Pointer to the memory range found - * - * @return - * - ESP_OK: On success - * - ESP_ERR_INVALID_ARG: Invalid arguments, could be wrong caps makeup, or null pointer - * - ESP_ERR_NOT_FOUND: Didn't find enough memory with give caps - */ -esp_err_t esp_mmu_find_vaddr_range(size_t size, uint32_t caps, const void **out_ptr); - -/** - * @brief Dump internal memory region usage - * - * @return - * - ESP_OK: On success - */ -esp_err_t esp_mmu_dump_region_usage(void); - -#ifdef __cplusplus -} -#endif diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index d3621876832..14a2349548c 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -55,7 +55,7 @@ else() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS include - PRIV_REQUIRES spi_flash esp_timer + PRIV_REQUIRES spi_flash esp_timer esp_mm # [refactor-todo] requirements due to init code, # should be removable once using component init functions # link-time registration is used. diff --git a/components/esp_system/ld/esp32/sections.ld.in b/components/esp_system/ld/esp32/sections.ld.in index 089bc26f7e0..fc64206ad9b 100644 --- a/components/esp_system/ld/esp32/sections.ld.in +++ b/components/esp_system/ld/esp32/sections.ld.in @@ -319,14 +319,22 @@ SECTIONS *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); - _rodata_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address */ . = ALIGN(4); } >default_rodata_seg _flash_rodata_align = ALIGNOF(.flash.rodata); + /* + This section is a place where we dump all the rodata which aren't used at runtime, + so as to avoid binary size increase + */ .flash.rodata_noload (NOLOAD) : { + /* + This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address + We don't need to include the noload rodata in this section + */ + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN (4); mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32c2/sections.ld.in b/components/esp_system/ld/esp32c2/sections.ld.in index 66431103deb..a6a92900627 100644 --- a/components/esp_system/ld/esp32c2/sections.ld.in +++ b/components/esp_system/ld/esp32c2/sections.ld.in @@ -97,7 +97,7 @@ SECTIONS .flash.text : { _stext = .; - _instruction_reserved_start = ABSOLUTE(.); + _instruction_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.text start, this can be used for mmu driver to maintain virtual address */ _text_start = ABSOLUTE(.); mapping[flash_text] @@ -116,7 +116,7 @@ SECTIONS . += _esp_flash_mmap_prefetch_pad_size; _text_end = ABSOLUTE(.); - _instruction_reserved_end = ABSOLUTE(.); + _instruction_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.text end, this can be used for mmu driver to maintain virtual address */ _etext = .; /** @@ -141,11 +141,11 @@ SECTIONS /* Prepare the alignment of the section above. Few bytes (0x20) must be * added for the mapping header. */ . = ALIGN(_esp_mmu_block_size) + 0x20; - _rodata_reserved_start = .; } > default_rodata_seg .flash.appdesc : ALIGN(0x10) { + _rodata_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.rodata start, this can be used for mmu driver to maintain virtual address */ _rodata_start = ABSOLUTE(.); *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ @@ -222,7 +222,6 @@ SECTIONS *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); - _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg @@ -246,8 +245,17 @@ SECTIONS __eh_frame_hdr_end = ABSOLUTE(.); } > default_rodata_seg + /* + This section is a place where we dump all the rodata which aren't used at runtime, + so as to avoid binary size increase + */ .flash.rodata_noload (NOLOAD) : { + /* + This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address + We don't need to include the noload rodata in this section + */ + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN (4); mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32c3/sections.ld.in b/components/esp_system/ld/esp32c3/sections.ld.in index bb2ed2f14c1..13cbf840254 100644 --- a/components/esp_system/ld/esp32c3/sections.ld.in +++ b/components/esp_system/ld/esp32c3/sections.ld.in @@ -207,7 +207,7 @@ SECTIONS .flash.text : { _stext = .; - _instruction_reserved_start = ABSOLUTE(.); + _instruction_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.text start, this can be used for mmu driver to maintain virtual address */ _text_start = ABSOLUTE(.); mapping[flash_text] @@ -226,7 +226,7 @@ SECTIONS . += _esp_flash_mmap_prefetch_pad_size; _text_end = ABSOLUTE(.); - _instruction_reserved_end = ABSOLUTE(.); + _instruction_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.text end, this can be used for mmu driver to maintain virtual address */ _etext = .; /** @@ -251,11 +251,11 @@ SECTIONS /* Prepare the alignment of the section above. Few bytes (0x20) must be * added for the mapping header. */ . = ALIGN(_esp_mmu_block_size) + 0x20; - _rodata_reserved_start = .; } > default_rodata_seg .flash.appdesc : ALIGN(0x10) { + _rodata_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.rodata start, this can be used for mmu driver to maintain virtual address */ _rodata_start = ABSOLUTE(.); *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ @@ -332,7 +332,6 @@ SECTIONS *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); - _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg @@ -356,8 +355,17 @@ SECTIONS __eh_frame_hdr_end = ABSOLUTE(.); } > default_rodata_seg + /* + This section is a place where we dump all the rodata which aren't used at runtime, + so as to avoid binary size increase + */ .flash.rodata_noload (NOLOAD) : { + /* + This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address + We don't need to include the noload rodata in this section + */ + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN (4); mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32c6/sections.ld.in b/components/esp_system/ld/esp32c6/sections.ld.in index d8e72f755ad..34c9bd38d30 100644 --- a/components/esp_system/ld/esp32c6/sections.ld.in +++ b/components/esp_system/ld/esp32c6/sections.ld.in @@ -240,7 +240,7 @@ SECTIONS .flash.text : { _stext = .; - _instruction_reserved_start = ABSOLUTE(.); + _instruction_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.text start, this can be used for mmu driver to maintain virtual address */ _text_start = ABSOLUTE(.); mapping[flash_text] @@ -259,7 +259,7 @@ SECTIONS . += _esp_flash_mmap_prefetch_pad_size; _text_end = ABSOLUTE(.); - _instruction_reserved_end = ABSOLUTE(.); + _instruction_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.text end, this can be used for mmu driver to maintain virtual address */ _etext = .; /** @@ -284,11 +284,11 @@ SECTIONS /* Prepare the alignment of the section above. Few bytes (0x20) must be * added for the mapping header. */ . = ALIGN(_esp_mmu_block_size) + 0x20; - _rodata_reserved_start = .; } > default_rodata_seg .flash.appdesc : ALIGN(0x10) { + _rodata_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.rodata start, this can be used for mmu driver to maintain virtual address */ _rodata_start = ABSOLUTE(.); *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ @@ -365,7 +365,6 @@ SECTIONS *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); - _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg @@ -389,8 +388,17 @@ SECTIONS __eh_frame_hdr_end = ABSOLUTE(.); } > default_rodata_seg + /* + This section is a place where we dump all the rodata which aren't used at runtime, + so as to avoid binary size increase + */ .flash.rodata_noload (NOLOAD) : { + /* + This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address + We don't need to include the noload rodata in this section + */ + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN (4); mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32h2/memory.ld.in b/components/esp_system/ld/esp32h2/memory.ld.in index 308dd314bf2..36887dcfbc9 100644 --- a/components/esp_system/ld/esp32h2/memory.ld.in +++ b/components/esp_system/ld/esp32h2/memory.ld.in @@ -64,7 +64,7 @@ MEMORY #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* Flash mapped instruction data */ - iram0_2_seg (RX) : org = 0x42000020, len = (IDRAM0_2_SEG_SIZE >> 1) -0x20 + irom_seg (RX) : org = 0x42000020, len = IDRAM0_2_SEG_SIZE - 0x20 /** * (0x20 offset above is a convenience for the app binary image generation. @@ -83,9 +83,9 @@ MEMORY #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS /* Flash mapped constant data */ - drom0_0_seg (R) : org = 0x42000020 + (IDRAM0_2_SEG_SIZE >> 1), len = (IDRAM0_2_SEG_SIZE >> 1)-0x20 + drom_seg (R) : org = 0x42000020, len = IDRAM0_2_SEG_SIZE - 0x20 - /* (See iram0_2_seg for meaning of 0x20 offset in the above.) */ + /* (See irom_seg for meaning of 0x20 offset in the above.) */ #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS /** @@ -122,19 +122,19 @@ REGION_ALIAS("rtc_slow_seg", rtc_iram_seg ); REGION_ALIAS("rtc_data_location", rtc_iram_seg ); #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS - REGION_ALIAS("default_code_seg", iram0_2_seg); + REGION_ALIAS("default_code_seg", irom_seg); #else REGION_ALIAS("default_code_seg", iram0_0_seg); #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS - REGION_ALIAS("default_rodata_seg", drom0_0_seg); + REGION_ALIAS("default_rodata_seg", drom_seg); #else REGION_ALIAS("default_rodata_seg", dram0_0_seg); #endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS /** - * If rodata default segment is placed in `drom0_0_seg`, then flash's first rodata section must + * If rodata default segment is placed in `drom_seg`, then flash's first rodata section must * also be first in the segment. */ #if CONFIG_APP_BUILD_USE_FLASH_SECTIONS diff --git a/components/esp_system/ld/esp32h4/sections.ld.in b/components/esp_system/ld/esp32h4/sections.ld.in index 84726e74147..43fbf0cb1f2 100644 --- a/components/esp_system/ld/esp32h4/sections.ld.in +++ b/components/esp_system/ld/esp32h4/sections.ld.in @@ -210,7 +210,7 @@ SECTIONS .flash.text : { _stext = .; - _instruction_reserved_start = ABSOLUTE(.); + _instruction_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.text start, this can be used for mmu driver to maintain virtual address */ _text_start = ABSOLUTE(.); mapping[flash_text] @@ -229,7 +229,7 @@ SECTIONS . += 16; _text_end = ABSOLUTE(.); - _instruction_reserved_end = ABSOLUTE(.); + _instruction_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.text end, this can be used for mmu driver to maintain virtual address */ _etext = .; /** @@ -254,11 +254,11 @@ SECTIONS /* Prepare the alignment of the section above. Few bytes (0x20) must be * added for the mapping header. */ . = ALIGN(_esp_mmu_block_size) + 0x20; - _rodata_reserved_start = .; } > default_rodata_seg .flash.appdesc : ALIGN(0x10) { + _rodata_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.rodata start, this can be used for mmu driver to maintain virtual address */ _rodata_start = ABSOLUTE(.); *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ @@ -335,7 +335,6 @@ SECTIONS *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); - _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(ALIGNOF(.eh_frame)); } > default_rodata_seg @@ -359,6 +358,20 @@ SECTIONS __eh_frame_hdr_end = ABSOLUTE(.); } > default_rodata_seg + /* + This section is a place where we dump all the rodata which aren't used at runtime, + so as to avoid binary size increase + */ + .flash.rodata_noload (NOLOAD) : + { + /* + This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address + We don't need to include the noload rodata in this section + */ + _rodata_reserved_end = ABSOLUTE(.); + . = ALIGN (4); + } > default_rodata_seg + /* Marks the end of IRAM code segment */ .iram0.text_end (NOLOAD) : { diff --git a/components/esp_system/ld/esp32s2/sections.ld.in b/components/esp_system/ld/esp32s2/sections.ld.in index 575e1e289ee..b8e461df427 100644 --- a/components/esp_system/ld/esp32s2/sections.ld.in +++ b/components/esp_system/ld/esp32s2/sections.ld.in @@ -335,14 +335,22 @@ SECTIONS *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); - _rodata_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address */ . = ALIGN(4); } >default_rodata_seg _flash_rodata_align = ALIGNOF(.flash.rodata); + /* + This section is a place where we dump all the rodata which aren't used at runtime, + so as to avoid binary size increase + */ .flash.rodata_noload (NOLOAD) : { + /* + This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address + We don't need to include the noload rodata in this section + */ + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN (4); mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/ld/esp32s3/sections.ld.in b/components/esp_system/ld/esp32s3/sections.ld.in index afd83defa16..d14f1da4021 100644 --- a/components/esp_system/ld/esp32s3/sections.ld.in +++ b/components/esp_system/ld/esp32s3/sections.ld.in @@ -288,11 +288,11 @@ SECTIONS /* Prepare the alignment of the section above. Few bytes (0x20) must be * added for the mapping header. */ . = ALIGN(_esp_mmu_block_size) + 0x20; - _rodata_reserved_start = .; /* This is a symbol marking the flash.rodata start, this can be used for mmu driver to maintain virtual address */ } > default_rodata_seg .flash.appdesc : ALIGN(0x10) { + _rodata_reserved_start = ABSOLUTE(.); /* This is a symbol marking the flash.rodata start, this can be used for mmu driver to maintain virtual address */ _rodata_start = ABSOLUTE(.); *(.rodata_desc .rodata_desc.*) /* Should be the first. App version info. DO NOT PUT ANYTHING BEFORE IT! */ @@ -361,14 +361,22 @@ SECTIONS *(.tbss) *(.tbss.*) _thread_local_end = ABSOLUTE(.); - _rodata_reserved_end = ABSOLUTE(.); /* This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address */ . = ALIGN(4); } > default_rodata_seg _flash_rodata_align = ALIGNOF(.flash.rodata); + /* + This section is a place where we dump all the rodata which aren't used at runtime, + so as to avoid binary size increase + */ .flash.rodata_noload (NOLOAD) : { + /* + This is a symbol marking the flash.rodata end, this can be used for mmu driver to maintain virtual address + We don't need to include the noload rodata in this section + */ + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN (4); mapping[rodata_noload] } > default_rodata_seg diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 6c1ef92d1c7..225dd2ff5bd 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -68,6 +68,7 @@ #include "esp32c2/memprot.h" #endif +#include "esp_private/esp_mmu_map_private.h" #if CONFIG_SPIRAM #include "esp_psram.h" #include "esp_private/esp_psram_extram.h" @@ -339,12 +340,10 @@ void IRAM_ATTR call_start_cpu0(void) /* If we need use SPIRAM, we should use data cache, or if we want to access rodata, we also should use data cache. Configure the mode of data : cache size, cache associated ways, cache line size. Enable data cache, so if we don't use SPIRAM, it just works. */ -#if CONFIG_SPIRAM_BOOT_INIT extern void esp_config_data_cache_mode(void); esp_config_data_cache_mode(); Cache_Enable_DCache(0); #endif -#endif #if CONFIG_IDF_TARGET_ESP32S3 /* Configure the mode of instruction cache : cache size, cache line size. */ @@ -401,6 +400,8 @@ void IRAM_ATTR call_start_cpu0(void) mspi_timing_flash_tuning(); #endif + esp_mmu_map_init(); + #if CONFIG_SPIRAM_BOOT_INIT if (esp_psram_init() != ESP_OK) { #if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY diff --git a/components/esp_system/port/soc/esp32s2/Kconfig.cache b/components/esp_system/port/soc/esp32s2/Kconfig.cache index bef23e3be67..fcb244ed313 100644 --- a/components/esp_system/port/soc/esp32s2/Kconfig.cache +++ b/components/esp_system/port/soc/esp32s2/Kconfig.cache @@ -28,8 +28,7 @@ menu "Cache config" choice ESP32S2_DATA_CACHE_SIZE prompt "Data cache size" - default ESP32S2_DATA_CACHE_0KB if !SPIRAM - default ESP32S2_DATA_CACHE_8KB if SPIRAM + default ESP32S2_DATA_CACHE_8KB help Data cache size to be set on application startup. If you use 0KB data cache, the other 16KB will be added to the heap diff --git a/components/hal/cache_hal.c b/components/hal/cache_hal.c index 608fff08ef0..db7db4b5737 100644 --- a/components/hal/cache_hal.c +++ b/components/hal/cache_hal.c @@ -12,6 +12,7 @@ #include "hal/cache_hal.h" #include "hal/cache_types.h" #include "hal/cache_ll.h" +#include "hal/mmu_ll.h" #include "soc/soc_caps.h" #if CONFIG_IDF_TARGET_ESP32S2 @@ -112,3 +113,10 @@ void cache_hal_enable(cache_type_t type) } #endif } + +void cache_hal_invalidate_addr(uint32_t vaddr, uint32_t size) +{ + //Now only esp32 has 2 MMUs, this file doesn't build on esp32 + HAL_ASSERT(mmu_ll_check_valid_ext_vaddr_region(0, vaddr, size)); + Cache_Invalidate_Addr(vaddr, size); +} diff --git a/components/hal/esp32/include/hal/cache_ll.h b/components/hal/esp32/include/hal/cache_ll.h index b3443a1c88d..263a168bf0f 100644 --- a/components/hal/esp32/include/hal/cache_ll.h +++ b/components/hal/esp32/include/hal/cache_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/components/hal/esp32/include/hal/mmu_ll.h b/components/hal/esp32/include/hal/mmu_ll.h index d7d0a8aa232..8d0dfd10d20 100644 --- a/components/hal/esp32/include/hal/mmu_ll.h +++ b/components/hal/esp32/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,8 @@ extern "C" { #endif +#define MMU_LL_PSRAM_ENTRY_START_ID 1152 + /** * Convert MMU virtual address to linear address * @@ -75,7 +77,7 @@ static inline mmu_page_size_t mmu_ll_get_page_size(uint32_t mmu_id) __attribute__((always_inline)) static inline void mmu_ll_set_page_size(uint32_t mmu_id, uint32_t size) { - HAL_ASSERT(size == MMU_PAGE_64KB); + //ONly supports `MMU_PAGE_64KB` } /** @@ -101,6 +103,96 @@ static inline bool mmu_ll_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t (ADDRESS_IN_DROM0_CACHE(vaddr_start) && ADDRESS_IN_DROM0_CACHE(vaddr_end)); } +/** + * Check if the paddr region is valid + * + * @param mmu_id MMU ID + * @param paddr_start start of the physical address + * @param len length, in bytes + * + * @return + * True for valid + */ +static inline bool mmu_ll_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len) +{ + (void)mmu_id; + return (paddr_start < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + (len < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + ((paddr_start + len - 1) < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)); +} + +/** + * To get the MMU table entry id to be mapped + * + * @param mmu_id MMU ID + * @param vaddr virtual address to be mapped + * + * @return + * MMU table entry id + */ +__attribute__((always_inline)) +static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) +{ + (void)mmu_id; + uint32_t offset = 0; + uint32_t shift_code = 0; + uint32_t vaddr_mask = 0; + + //On ESP32, we only use PID0 and PID1 + if (ADDRESS_IN_DROM0_CACHE(vaddr)) { + offset = 0; + shift_code = 16; + vaddr_mask = MMU_VADDR_MASK; + } else if (ADDRESS_IN_IRAM0_CACHE(vaddr)) { + offset = 64; + shift_code = 16; + vaddr_mask = MMU_VADDR_MASK; + } else if (ADDRESS_IN_IRAM1_CACHE(vaddr)) { + offset = 128; + shift_code = 16; + vaddr_mask = MMU_VADDR_MASK; + } else if (ADDRESS_IN_IROM0_CACHE(vaddr)) { + offset = 192; + shift_code = 16; + vaddr_mask = MMU_VADDR_MASK; + } else if (ADDRESS_IN_DRAM1_CACHE(vaddr)) { + //PSRAM page size 32KB + offset = MMU_LL_PSRAM_ENTRY_START_ID; + shift_code = 15; + vaddr_mask = MMU_VADDR_MASK >> 1; + } else { + HAL_ASSERT(false); + } + + return offset + ((vaddr & vaddr_mask) >> shift_code); +} + +/** + * Format the paddr to be mappable + * + * @param mmu_id MMU ID + * @param paddr physical address to be mapped + * @param target paddr memory target, not used + * + * @return + * mmu_val - paddr in MMU table supported format + */ +__attribute__((always_inline)) +static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target) +{ + (void)mmu_id; + uint32_t shift_code = 0; + + if (target == MMU_TARGET_FLASH0) { + shift_code = 16; + } else { + //PSRAM page size 32KB + shift_code = 15; + } + + return paddr >> shift_code; +} + /** * Write to the MMU table to map the virtual memory and the physical memory * @@ -113,7 +205,6 @@ __attribute__((always_inline)) static inline void mmu_ll_write_entry(uint32_t mmu_id, uint32_t entry_id, uint32_t mmu_val, mmu_target_t target) { (void)target; - HAL_ASSERT(entry_id < MMU_ENTRY_NUM); DPORT_INTERRUPT_DISABLE(); switch (mmu_id) { @@ -140,7 +231,6 @@ __attribute__((always_inline)) static inline uint32_t mmu_ll_read_entry(uint32_t mmu_id, uint32_t entry_id) { uint32_t mmu_value; - HAL_ASSERT(entry_id < MMU_ENTRY_NUM); DPORT_INTERRUPT_DISABLE(); switch (mmu_id) { @@ -167,7 +257,6 @@ __attribute__((always_inline)) static inline void mmu_ll_set_entry_invalid(uint32_t mmu_id, uint32_t entry_id) { HAL_ASSERT(entry_id < MMU_ENTRY_NUM); - DPORT_INTERRUPT_DISABLE(); switch (mmu_id) { case MMU_TABLE_CORE0: @@ -196,22 +285,164 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) } /** - * Get MMU table entry is invalid + * Check MMU table entry value is valid * * @param mmu_id MMU ID * @param entry_id MMU entry ID - * return ture for MMU entry is invalid, false for valid + * + * @return Ture for MMU entry is valid; False for invalid */ -__attribute__((always_inline)) -static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + DPORT_INTERRUPT_DISABLE(); + uint32_t mmu_value = DPORT_SEQUENCE_REG_READ((uint32_t)&DPORT_PRO_FLASH_MMU_TABLE[entry_id]); + DPORT_INTERRUPT_RESTORE(); + + return (mmu_value & MMU_INVALID) ? false : true; +} + +/** + * Get the MMU table entry target + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return Target, see `mmu_target_t` + */ +static inline mmu_target_t mmu_ll_get_entry_target(uint32_t mmu_id, uint32_t entry_id) +{ + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + HAL_ASSERT(mmu_ll_check_entry_valid(mmu_id, entry_id)); + + return (entry_id >= MMU_LL_PSRAM_ENTRY_START_ID) ? MMU_TARGET_PSRAM0 : MMU_TARGET_FLASH0; +} + +/** + * Convert MMU entry ID to paddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return paddr base + */ +static inline uint32_t mmu_ll_entry_id_to_paddr_base(uint32_t mmu_id, uint32_t entry_id) { (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); DPORT_INTERRUPT_DISABLE(); uint32_t mmu_value = DPORT_SEQUENCE_REG_READ((uint32_t)&DPORT_PRO_FLASH_MMU_TABLE[entry_id]); DPORT_INTERRUPT_RESTORE(); - return (mmu_value & MMU_INVALID) ? true : false; + return (entry_id >= MMU_LL_PSRAM_ENTRY_START_ID) ? (mmu_value << 15) : (mmu_value << 16); +} + +/** + * Find the MMU table entry ID based on table map value + * @note This function can only find the first match entry ID. However it is possible that a physical address + * is mapped to multiple virtual addresses + * + * @param mmu_id MMU ID + * @param mmu_val map value to be read from MMU table standing for paddr + * @param target physical memory target, see `mmu_target_t` + * + * @return MMU entry ID, -1 for invalid + */ +static inline int mmu_ll_find_entry_id_based_on_map_value(uint32_t mmu_id, uint32_t mmu_val, mmu_target_t target) +{ + (void)mmu_id; + (void)target; + + DPORT_INTERRUPT_DISABLE(); + if (target == MMU_TARGET_FLASH0) { + for (int i = 0; i < MMU_ENTRY_NUM; i++) { + uint32_t mmu_value = DPORT_SEQUENCE_REG_READ((uint32_t)&DPORT_PRO_FLASH_MMU_TABLE[i]); + if (!(mmu_value & MMU_INVALID)) { + if (mmu_value == mmu_val) { + DPORT_INTERRUPT_RESTORE(); + return i; + } + } + } + } else { + //For PSRAM, we only use PID 0/1. Its start entry ID is MMU_LL_PSRAM_ENTRY_START_ID (1152), and 128 entries are used for PSRAM + for (int i = MMU_LL_PSRAM_ENTRY_START_ID; i < 1280; i++) { + uint32_t mmu_value = DPORT_SEQUENCE_REG_READ((uint32_t)&DPORT_PRO_FLASH_MMU_TABLE[i]); + if (!(mmu_value & MMU_INVALID)) { + if (mmu_value == mmu_val) { + DPORT_INTERRUPT_RESTORE(); + return i; + } + } + } + } + DPORT_INTERRUPT_RESTORE(); + + return -1; +} + +/** + * Convert MMU entry ID to vaddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + */ +static inline uint32_t mmu_ll_entry_id_to_vaddr_base(uint32_t mmu_id, uint32_t entry_id, mmu_vaddr_t type) +{ + (void)mmu_id; + (void)type; + uint32_t vaddr_base = 0; + uint32_t shift_code = 0; + + if (entry_id < 64) { + //first 64 entries are for DROM0 + if (type != MMU_VADDR_DATA) { + return 0; + } + entry_id -= 0; + shift_code = 16; + vaddr_base = 0x3f400000; + } else if (entry_id >= 64 && entry_id < 128) { + //second 64 entries are for IRAM0 + if (type != MMU_VADDR_INSTRUCTION) { + return 0; + } + entry_id -= 64; + shift_code = 16; + vaddr_base = 0x40000000; + } else if (entry_id >= 128 && entry_id < 192) { + //third 64 entries are for IRAM1 + if (type != MMU_VADDR_INSTRUCTION) { + return 0; + } + entry_id -= 128; + shift_code = 16; + vaddr_base = 0x40000000; + } else if (entry_id >= 192 && entry_id < 256) { + //fourth 64 entries are for IROM0 + if (type != MMU_VADDR_INSTRUCTION) { + return 0; + } + entry_id -= 192; + shift_code = 16; + vaddr_base = 0x40000000; + } else if (entry_id >= MMU_LL_PSRAM_ENTRY_START_ID) { + //starting from 1152, 128 entries are for DRAM1 + if (type != MMU_VADDR_DATA) { + return 0; + } + entry_id -= MMU_LL_PSRAM_ENTRY_START_ID; + shift_code = 15; + vaddr_base = 0x3f800000; + } else { + HAL_ASSERT(false); + } + + return vaddr_base + (entry_id << shift_code); } #ifdef __cplusplus diff --git a/components/hal/esp32c2/include/hal/cache_ll.h b/components/hal/esp32c2/include/hal/cache_ll.h index c39aa532c85..b65b9d47d95 100644 --- a/components/hal/esp32c2/include/hal/cache_ll.h +++ b/components/hal/esp32c2/include/hal/cache_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,7 +12,6 @@ #include "soc/ext_mem_defs.h" #include "hal/cache_types.h" #include "hal/assert.h" -#include "sdkconfig.h" #ifdef __cplusplus extern "C" { @@ -54,9 +53,9 @@ static inline cache_bus_mask_t cache_ll_l1_get_bus(uint32_t cache_id, uint32_t v cache_bus_mask_t mask = 0; uint32_t vaddr_end = vaddr_start + len - 1; - if (vaddr_start >= IRAM0_CACHE_ADDRESS_LOW && vaddr_end < IRAM0_CACHE_ADDRESS_HIGH(CONFIG_MMU_PAGE_SIZE)) { + if (vaddr_start >= IRAM0_CACHE_ADDRESS_LOW && vaddr_end < IRAM0_CACHE_ADDRESS_HIGH) { mask |= CACHE_BUS_IBUS0; - } else if (vaddr_start >= DRAM0_CACHE_ADDRESS_LOW && vaddr_end < DRAM0_CACHE_ADDRESS_HIGH(CONFIG_MMU_PAGE_SIZE)) { + } else if (vaddr_start >= DRAM0_CACHE_ADDRESS_LOW && vaddr_end < DRAM0_CACHE_ADDRESS_HIGH) { mask |= CACHE_BUS_DBUS0; } else { HAL_ASSERT(0); //Out of region diff --git a/components/hal/esp32c2/include/hal/mmu_ll.h b/components/hal/esp32c2/include/hal/mmu_ll.h index 305f1fe4459..572d79aa003 100644 --- a/components/hal/esp32c2/include/hal/mmu_ll.h +++ b/components/hal/esp32c2/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,7 +13,6 @@ #include "soc/ext_mem_defs.h" #include "hal/assert.h" #include "hal/mmu_types.h" -#include "sdkconfig.h" #ifdef __cplusplus @@ -21,11 +20,36 @@ extern "C" { #endif /** - * @brief The real MMU page size get from Kconfig. + * Convert MMU virtual address to linear address * - * @note Only used in this file + * @param vaddr virtual address + * + * @return linear address */ -#define MMU_LL_PAGE_SIZE (CONFIG_MMU_PAGE_SIZE) +static inline uint32_t mmu_ll_vaddr_to_laddr(uint32_t vaddr) +{ + return vaddr & SOC_MMU_LINEAR_ADDR_MASK; +} + +/** + * Convert MMU linear address to virtual address + * + * @param laddr linear address + * @param vaddr_type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + * + * @return virtual address + */ +static inline uint32_t mmu_ll_laddr_to_vaddr(uint32_t laddr, mmu_vaddr_t vaddr_type) +{ + uint32_t vaddr_base = 0; + if (vaddr_type == MMU_VADDR_DATA) { + vaddr_base = SOC_MMU_DBUS_VADDR_BASE; + } else { + vaddr_base = SOC_MMU_IBUS_VADDR_BASE; + } + + return vaddr_base | laddr; +} /** * Get MMU page size @@ -69,7 +93,25 @@ static inline bool mmu_ll_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t { (void)mmu_id; uint32_t vaddr_end = vaddr_start + len - 1; - return (ADDRESS_IN_IRAM0_CACHE(vaddr_start, MMU_LL_PAGE_SIZE) && ADDRESS_IN_IRAM0_CACHE(vaddr_end, MMU_LL_PAGE_SIZE)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start, MMU_LL_PAGE_SIZE) && ADDRESS_IN_DRAM0_CACHE(vaddr_end, MMU_LL_PAGE_SIZE)); + return (ADDRESS_IN_IRAM0_CACHE(vaddr_start) && ADDRESS_IN_IRAM0_CACHE(vaddr_end)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start) && ADDRESS_IN_DRAM0_CACHE(vaddr_end)); +} + +/** + * Check if the paddr region is valid + * + * @param mmu_id MMU ID + * @param paddr_start start of the physical address + * @param len length, in bytes + * + * @return + * True for valid + */ +static inline bool mmu_ll_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len) +{ + (void)mmu_id; + return (paddr_start < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + (len < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + ((paddr_start + len - 1) < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)); } /** @@ -102,7 +144,7 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) HAL_ASSERT(shift_code); } - return ((vaddr & MMU_VADDR_MASK(page_size)) >> shift_code); + return ((vaddr & MMU_VADDR_MASK) >> shift_code); } /** @@ -110,14 +152,16 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) * * @param mmu_id MMU ID * @param paddr physical address to be mapped + * @param target paddr memory target, not used * * @return * mmu_val - paddr in MMU table supported format */ __attribute__((always_inline)) -static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr) +static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target) { (void)mmu_id; + (void)target; mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); uint32_t shift_code = 0; @@ -201,19 +245,122 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) } /** - * Get MMU table entry is invalid + * Check MMU table entry value is valid * * @param mmu_id MMU ID * @param entry_id MMU entry ID - * return ture for MMU entry is invalid, false for valid + * + * @return Ture for MMU entry is valid; False for invalid */ -__attribute__((always_inline)) -static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { (void)mmu_id; HAL_ASSERT(entry_id < MMU_ENTRY_NUM); - return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? true : false; + return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? false : true; +} + +/** + * Get the MMU table entry target + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return Target, see `mmu_target_t` + */ +static inline mmu_target_t mmu_ll_get_entry_target(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + return MMU_TARGET_FLASH0; +} + +/** + * Convert MMU entry ID to paddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return paddr base + */ +static inline uint32_t mmu_ll_entry_id_to_paddr_base(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); + uint32_t shift_code = 0; + switch (page_size) { + case MMU_PAGE_64KB: + shift_code = 16; + break; + case MMU_PAGE_32KB: + shift_code = 15; + break; + case MMU_PAGE_16KB: + shift_code = 14; + break; + default: + HAL_ASSERT(shift_code); + } + + return ((*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4)) & MMU_VALID_VAL_MASK) << shift_code; +} + +/** + * Find the MMU table entry ID based on table map value + * @note This function can only find the first match entry ID. However it is possible that a physical address + * is mapped to multiple virtual addresses + * + * @param mmu_id MMU ID + * @param mmu_val map value to be read from MMU table standing for paddr + * @param target physical memory target, see `mmu_target_t` + * + * @return MMU entry ID, -1 for invalid + */ +static inline int mmu_ll_find_entry_id_based_on_map_value(uint32_t mmu_id, uint32_t mmu_val, mmu_target_t target) +{ + (void)mmu_id; + for (int i = 0; i < MMU_ENTRY_NUM; i++) { + if (mmu_ll_check_entry_valid(mmu_id, i)) { + if (mmu_ll_get_entry_target(mmu_id, i) == target) { + if (((*(uint32_t *)(DR_REG_MMU_TABLE + i * 4)) & MMU_VALID_VAL_MASK) == mmu_val) { + return i; + } + } + } + } + + return -1; +} + +/** + * Convert MMU entry ID to vaddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + */ +static inline uint32_t mmu_ll_entry_id_to_vaddr_base(uint32_t mmu_id, uint32_t entry_id, mmu_vaddr_t type) +{ + (void)mmu_id; + mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); + uint32_t shift_code = 0; + + switch (page_size) { + case MMU_PAGE_64KB: + shift_code = 16; + break; + case MMU_PAGE_32KB: + shift_code = 15; + break; + case MMU_PAGE_16KB: + shift_code = 14; + break; + default: + HAL_ASSERT(shift_code); + } + uint32_t laddr = entry_id << shift_code; + return mmu_ll_laddr_to_vaddr(laddr, type); } #ifdef __cplusplus diff --git a/components/hal/esp32c3/include/hal/mmu_ll.h b/components/hal/esp32c3/include/hal/mmu_ll.h index a1e28d69376..62ed027c551 100644 --- a/components/hal/esp32c3/include/hal/mmu_ll.h +++ b/components/hal/esp32c3/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #pragma once +#include "esp_types.h" #include "soc/extmem_reg.h" #include "soc/ext_mem_defs.h" #include "hal/assert.h" @@ -18,6 +19,38 @@ extern "C" { #endif +/** + * Convert MMU virtual address to linear address + * + * @param vaddr virtual address + * + * @return linear address + */ +static inline uint32_t mmu_ll_vaddr_to_laddr(uint32_t vaddr) +{ + return vaddr & SOC_MMU_LINEAR_ADDR_MASK; +} + +/** + * Convert MMU linear address to virtual address + * + * @param laddr linear address + * @param vaddr_type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + * + * @return virtual address + */ +static inline uint32_t mmu_ll_laddr_to_vaddr(uint32_t laddr, mmu_vaddr_t vaddr_type) +{ + uint32_t vaddr_base = 0; + if (vaddr_type == MMU_VADDR_DATA) { + vaddr_base = SOC_MMU_DBUS_VADDR_BASE; + } else { + vaddr_base = SOC_MMU_IBUS_VADDR_BASE; + } + + return vaddr_base | laddr; +} + /** * Get MMU page size * @@ -64,6 +97,24 @@ static inline bool mmu_ll_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t return (ADDRESS_IN_IRAM0_CACHE(vaddr_start) && ADDRESS_IN_IRAM0_CACHE(vaddr_end)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start) && ADDRESS_IN_DRAM0_CACHE(vaddr_end)); } +/** + * Check if the paddr region is valid + * + * @param mmu_id MMU ID + * @param paddr_start start of the physical address + * @param len length, in bytes + * + * @return + * True for valid + */ +static inline bool mmu_ll_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len) +{ + (void)mmu_id; + return (paddr_start < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + (len < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + ((paddr_start + len - 1) < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)); +} + /** * To get the MMU table entry id to be mapped * @@ -85,14 +136,16 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) * * @param mmu_id MMU ID * @param paddr physical address to be mapped + * @param target paddr memory target, not used * * @return * mmu_val - paddr in MMU table supported format */ __attribute__((always_inline)) -static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr) +static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target) { (void)mmu_id; + (void)target; return paddr >> 16; } @@ -159,19 +212,93 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) } /** - * Get MMU table entry is invalid + * Check MMU table entry value is valid * * @param mmu_id MMU ID * @param entry_id MMU entry ID - * return ture for MMU entry is invalid, false for valid + * + * @return Ture for MMU entry is valid; False for invalid */ -__attribute__((always_inline)) -static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? false : true; +} + +/** + * Get the MMU table entry target + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return Target, see `mmu_target_t` + */ +static inline mmu_target_t mmu_ll_get_entry_target(uint32_t mmu_id, uint32_t entry_id) { (void)mmu_id; HAL_ASSERT(entry_id < MMU_ENTRY_NUM); - return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? true : false; + return MMU_TARGET_FLASH0; +} + +/** + * Convert MMU entry ID to paddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return paddr base + */ +static inline uint32_t mmu_ll_entry_id_to_paddr_base(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + return ((*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4)) & MMU_VALID_VAL_MASK) << 16; +} + +/** + * Find the MMU table entry ID based on table map value + * @note This function can only find the first match entry ID. However it is possible that a physical address + * is mapped to multiple virtual addresses + * + * @param mmu_id MMU ID + * @param mmu_val map value to be read from MMU table standing for paddr + * @param target physical memory target, see `mmu_target_t` + * + * @return MMU entry ID, -1 for invalid + */ +static inline int mmu_ll_find_entry_id_based_on_map_value(uint32_t mmu_id, uint32_t mmu_val, mmu_target_t target) +{ + (void)mmu_id; + for (int i = 0; i < MMU_ENTRY_NUM; i++) { + if (mmu_ll_check_entry_valid(mmu_id, i)) { + if (mmu_ll_get_entry_target(mmu_id, i) == target) { + if (((*(uint32_t *)(DR_REG_MMU_TABLE + i * 4)) & MMU_VALID_VAL_MASK) == mmu_val) { + return i; + } + } + } + } + + return -1; +} + +/** + * Convert MMU entry ID to vaddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + */ +static inline uint32_t mmu_ll_entry_id_to_vaddr_base(uint32_t mmu_id, uint32_t entry_id, mmu_vaddr_t type) +{ + (void)mmu_id; + uint32_t laddr = entry_id << 16; + + return mmu_ll_laddr_to_vaddr(laddr, type); } #ifdef __cplusplus diff --git a/components/hal/esp32c6/include/hal/cache_ll.h b/components/hal/esp32c6/include/hal/cache_ll.h index 6fd9a993765..5a826c2e0f6 100644 --- a/components/hal/esp32c6/include/hal/cache_ll.h +++ b/components/hal/esp32c6/include/hal/cache_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -54,9 +54,9 @@ static inline cache_bus_mask_t cache_ll_l1_get_bus(uint32_t cache_id, uint32_t v cache_bus_mask_t mask = 0; uint32_t vaddr_end = vaddr_start + len - 1; - if (vaddr_start >= IRAM0_CACHE_ADDRESS_LOW && vaddr_end < IRAM0_CACHE_ADDRESS_HIGH(CONFIG_MMU_PAGE_SIZE)) { + if (vaddr_start >= IRAM0_CACHE_ADDRESS_LOW && vaddr_end < IRAM0_CACHE_ADDRESS_HIGH) { mask |= CACHE_BUS_IBUS0; - } else if (vaddr_start >= DRAM0_CACHE_ADDRESS_LOW && vaddr_end < DRAM0_CACHE_ADDRESS_HIGH(CONFIG_MMU_PAGE_SIZE)) { + } else if (vaddr_start >= DRAM0_CACHE_ADDRESS_LOW && vaddr_end < DRAM0_CACHE_ADDRESS_HIGH) { mask |= CACHE_BUS_DBUS0; } else { HAL_ASSERT(0); //Out of region diff --git a/components/hal/esp32c6/include/hal/mmu_ll.h b/components/hal/esp32c6/include/hal/mmu_ll.h index 15a90902e2f..6bdd0db22dd 100644 --- a/components/hal/esp32c6/include/hal/mmu_ll.h +++ b/components/hal/esp32c6/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -20,11 +20,30 @@ extern "C" { #endif /** - * @brief The real MMU page size get from Kconfig. + * Convert MMU virtual address to linear address * - * @note Only used in this file + * @param vaddr virtual address + * + * @return linear address */ -#define MMU_LL_PAGE_SIZE (CONFIG_MMU_PAGE_SIZE) +static inline uint32_t mmu_ll_vaddr_to_laddr(uint32_t vaddr) +{ + return vaddr & SOC_MMU_LINEAR_ADDR_MASK; +} + +/** + * Convert MMU linear address to virtual address + * + * @param laddr linear address + * @param vaddr_type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + * + * @return virtual address + */ +static inline uint32_t mmu_ll_laddr_to_vaddr(uint32_t laddr, mmu_vaddr_t vaddr_type) +{ + //On ESP32C6, I/D share the same vaddr range + return SOC_MMU_IBUS_VADDR_BASE | laddr; +} __attribute__((always_inline)) static inline bool mmu_ll_cache_encryption_enabled(void) { @@ -82,7 +101,25 @@ static inline bool mmu_ll_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t { (void)mmu_id; uint32_t vaddr_end = vaddr_start + len; - return (ADDRESS_IN_IRAM0_CACHE(vaddr_start, MMU_LL_PAGE_SIZE) && ADDRESS_IN_IRAM0_CACHE(vaddr_end, MMU_LL_PAGE_SIZE)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start, MMU_LL_PAGE_SIZE) && ADDRESS_IN_DRAM0_CACHE(vaddr_end, MMU_LL_PAGE_SIZE)); + return (ADDRESS_IN_IRAM0_CACHE(vaddr_start) && ADDRESS_IN_IRAM0_CACHE(vaddr_end)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start) && ADDRESS_IN_DRAM0_CACHE(vaddr_end)); +} + +/** + * Check if the paddr region is valid + * + * @param mmu_id MMU ID + * @param paddr_start start of the physical address + * @param len length, in bytes + * + * @return + * True for valid + */ +static inline bool mmu_ll_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len) +{ + (void)mmu_id; + return (paddr_start < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + (len < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + ((paddr_start + len - 1) < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)); } /** @@ -110,10 +147,13 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) case MMU_PAGE_16KB: shift_code = 14; break; + case MMU_PAGE_8KB: + shift_code = 13; + break; default: HAL_ASSERT(shift_code); } - return ((vaddr & MMU_VADDR_MASK(page_size)) >> shift_code); + return ((vaddr & MMU_VADDR_MASK) >> shift_code); } /** @@ -121,14 +161,16 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) * * @param mmu_id MMU ID * @param paddr physical address to be mapped + * @param target paddr memory target, not used * * @return * mmu_val - paddr in MMU table supported format */ __attribute__((always_inline)) -static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr) +static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target) { (void)mmu_id; + (void)target; mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); uint32_t shift_code = 0; switch (page_size) { @@ -141,6 +183,9 @@ static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr) case MMU_PAGE_16KB: shift_code = 14; break; + case MMU_PAGE_8KB: + shift_code = 13; + break; default: HAL_ASSERT(shift_code); } @@ -163,8 +208,8 @@ __attribute__((always_inline)) static inline void mmu_ll_write_entry(uint32_t mm if (mmu_ll_cache_encryption_enabled()) { mmu_val |= MMU_SENSITIVE; } - /* Note: for ESP32-C6, invert invalid bit for compatible with upper-layer software */ - mmu_raw_value = mmu_val ^ MMU_INVALID_MASK; + + mmu_raw_value = mmu_val | MMU_VALID; REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); REG_WRITE(SPI_MEM_MMU_ITEM_CONTENT_REG(0), mmu_raw_value); } @@ -186,8 +231,10 @@ __attribute__((always_inline)) static inline uint32_t mmu_ll_read_entry(uint32_t if (mmu_ll_cache_encryption_enabled()) { mmu_raw_value &= ~MMU_SENSITIVE; } - /* Note: for ESP32-C6, invert invalid bit for compatible with upper-layer software */ - ret = mmu_raw_value ^ MMU_INVALID_MASK; + if (!(mmu_raw_value & MMU_VALID)) { + return 0; + } + ret = mmu_raw_value & MMU_VALID_VAL_MASK; return ret; } @@ -205,33 +252,144 @@ __attribute__((always_inline)) static inline void mmu_ll_set_entry_invalid(uint3 } /** - * Get MMU table entry is invalid + * Unmap all the items in the MMU table + * + * @param mmu_id MMU ID + */ +__attribute__((always_inline)) +static inline void mmu_ll_unmap_all(uint32_t mmu_id) +{ + for (int i = 0; i < MMU_ENTRY_NUM; i++) { + mmu_ll_set_entry_invalid(mmu_id, i); + } +} + +/** + * Check MMU table entry value is valid * * @param mmu_id MMU ID * @param entry_id MMU entry ID - * return ture for MMU entry is invalid, false for valid + * + * @return Ture for MMU entry is valid; False for invalid */ -__attribute__((always_inline)) static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { (void)mmu_id; - uint32_t mmu_raw_value; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); - mmu_raw_value = REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)); - /* Note: for ESP32-C6, the invalid-bit of MMU: 0 for invalid, 1 for valid */ - return (mmu_raw_value & MMU_INVALID_MASK) ? false : true; + return (REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)) & MMU_VALID) ? true : false; } /** - * Unmap all the items in the MMU table + * Get the MMU table entry target * - * @param mmu_id MMU ID + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return Target, see `mmu_target_t` */ -__attribute__((always_inline)) -static inline void mmu_ll_unmap_all(uint32_t mmu_id) +static inline mmu_target_t mmu_ll_get_entry_target(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + return MMU_TARGET_FLASH0; +} + +/** + * Convert MMU entry ID to paddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return paddr base + */ +static inline uint32_t mmu_ll_entry_id_to_paddr_base(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); + uint32_t shift_code = 0; + switch (page_size) { + case MMU_PAGE_64KB: + shift_code = 16; + break; + case MMU_PAGE_32KB: + shift_code = 15; + break; + case MMU_PAGE_16KB: + shift_code = 14; + break; + case MMU_PAGE_8KB: + shift_code = 13; + break; + default: + HAL_ASSERT(shift_code); + } + + REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); + return (REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)) & MMU_VALID_VAL_MASK) << shift_code; +} + +/** + * Find the MMU table entry ID based on table map value + * @note This function can only find the first match entry ID. However it is possible that a physical address + * is mapped to multiple virtual addresses + * + * @param mmu_id MMU ID + * @param mmu_val map value to be read from MMU table standing for paddr + * @param target physical memory target, see `mmu_target_t` + * + * @return MMU entry ID, -1 for invalid + */ +static inline int mmu_ll_find_entry_id_based_on_map_value(uint32_t mmu_id, uint32_t mmu_val, mmu_target_t target) { + (void)mmu_id; for (int i = 0; i < MMU_ENTRY_NUM; i++) { - mmu_ll_set_entry_invalid(mmu_id, i); + if (mmu_ll_check_entry_valid(mmu_id, i)) { + if (mmu_ll_get_entry_target(mmu_id, i) == target) { + REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), i); + if ((REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)) & MMU_VALID_VAL_MASK) == mmu_val) { + return i; + } + } + } + } + + return -1; +} + +/** + * Convert MMU entry ID to vaddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + */ +static inline uint32_t mmu_ll_entry_id_to_vaddr_base(uint32_t mmu_id, uint32_t entry_id, mmu_vaddr_t type) +{ + (void)mmu_id; + mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); + uint32_t shift_code = 0; + + switch (page_size) { + case MMU_PAGE_64KB: + shift_code = 16; + break; + case MMU_PAGE_32KB: + shift_code = 15; + break; + case MMU_PAGE_16KB: + shift_code = 14; + break; + case MMU_PAGE_8KB: + shift_code = 13; + break; + default: + HAL_ASSERT(shift_code); } + uint32_t laddr = entry_id << shift_code; + return mmu_ll_laddr_to_vaddr(laddr, type); } #ifdef __cplusplus diff --git a/components/hal/esp32h2/include/hal/cache_ll.h b/components/hal/esp32h2/include/hal/cache_ll.h index 63a95593cf4..1928e9d2900 100644 --- a/components/hal/esp32h2/include/hal/cache_ll.h +++ b/components/hal/esp32h2/include/hal/cache_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -54,9 +54,9 @@ static inline cache_bus_mask_t cache_ll_l1_get_bus(uint32_t cache_id, uint32_t v cache_bus_mask_t mask = 0; uint32_t vaddr_end = vaddr_start + len - 1; - if (vaddr_start >= IRAM0_CACHE_ADDRESS_LOW && vaddr_end < IRAM0_CACHE_ADDRESS_HIGH(CONFIG_MMU_PAGE_SIZE)) { + if (vaddr_start >= IRAM0_CACHE_ADDRESS_LOW && vaddr_end < IRAM0_CACHE_ADDRESS_HIGH) { mask |= CACHE_BUS_IBUS0; - } else if (vaddr_start >= DRAM0_CACHE_ADDRESS_LOW && vaddr_end < DRAM0_CACHE_ADDRESS_HIGH(CONFIG_MMU_PAGE_SIZE)) { + } else if (vaddr_start >= DRAM0_CACHE_ADDRESS_LOW && vaddr_end < DRAM0_CACHE_ADDRESS_HIGH) { mask |= CACHE_BUS_DBUS0; } else { HAL_ASSERT(0); //Out of region diff --git a/components/hal/esp32h2/include/hal/mmu_ll.h b/components/hal/esp32h2/include/hal/mmu_ll.h index 5a9ea6a90f5..a01c324676d 100644 --- a/components/hal/esp32h2/include/hal/mmu_ll.h +++ b/components/hal/esp32h2/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,12 +19,33 @@ extern "C" { #endif + +/** + * Convert MMU virtual address to linear address + * + * @param vaddr virtual address + * + * @return linear address + */ +static inline uint32_t mmu_ll_vaddr_to_laddr(uint32_t vaddr) +{ + return vaddr & SOC_MMU_LINEAR_ADDR_MASK; +} + /** - * @brief The real MMU page size get from Kconfig. + * Convert MMU linear address to virtual address * - * @note Only used in this file + * @param laddr linear address + * @param vaddr_type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + * + * @return virtual address */ -#define MMU_LL_PAGE_SIZE (CONFIG_MMU_PAGE_SIZE) +static inline uint32_t mmu_ll_laddr_to_vaddr(uint32_t laddr, mmu_vaddr_t vaddr_type) +{ + //On ESP32C6, I/D share the same vaddr range + return SOC_MMU_IBUS_VADDR_BASE | laddr; +} + __attribute__((always_inline)) static inline bool mmu_ll_cache_encryption_enabled(void) { @@ -83,7 +104,25 @@ static inline bool mmu_ll_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t { (void)mmu_id; uint32_t vaddr_end = vaddr_start + len; - return (ADDRESS_IN_IRAM0_CACHE(vaddr_start, MMU_LL_PAGE_SIZE) && ADDRESS_IN_IRAM0_CACHE(vaddr_end, MMU_LL_PAGE_SIZE)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start, MMU_LL_PAGE_SIZE) && ADDRESS_IN_DRAM0_CACHE(vaddr_end, MMU_LL_PAGE_SIZE)); + return (ADDRESS_IN_IRAM0_CACHE(vaddr_start) && ADDRESS_IN_IRAM0_CACHE(vaddr_end)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start) && ADDRESS_IN_DRAM0_CACHE(vaddr_end)); +} + +/** + * Check if the paddr region is valid + * + * @param mmu_id MMU ID + * @param paddr_start start of the physical address + * @param len length, in bytes + * + * @return + * True for valid + */ +static inline bool mmu_ll_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len) +{ + (void)mmu_id; + return (paddr_start < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + (len < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + ((paddr_start + len - 1) < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)); } /** @@ -119,7 +158,7 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) HAL_ASSERT(shift_code); } - return ((vaddr & MMU_VADDR_MASK(page_size)) >> shift_code); + return ((vaddr & MMU_VADDR_MASK) >> shift_code); } /** @@ -132,9 +171,10 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) * mmu_val - paddr in MMU table supported format */ __attribute__((always_inline)) -static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr) +static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target) { (void)mmu_id; + (void)target; mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); uint32_t shift_code = 0; @@ -217,39 +257,168 @@ __attribute__((always_inline)) static inline void mmu_ll_set_entry_invalid(uint3 REG_WRITE(SPI_MEM_MMU_ITEM_CONTENT_REG(0), MMU_INVALID); } +// /** +// * Get MMU table entry is invalid +// * +// * @param mmu_id MMU ID +// * @param entry_id MMU entry ID +// * return ture for MMU entry is invalid, false for valid +// */ +// __attribute__((always_inline)) static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +// { +// (void)mmu_id; + +// uint32_t mmu_raw_value; +// REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); +// mmu_raw_value = REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)); +// /* Note: for ESP32-H2, the invalid-bit of MMU: 0 for invalid, 1 for valid */ +// return (mmu_raw_value & MMU_INVALID_MASK) ? false : true; +// } + + /** - * Get MMU table entry is invalid + * Unmap all the items in the MMU table + * + * @param mmu_id MMU ID + */ +__attribute__((always_inline)) +static inline void mmu_ll_unmap_all(uint32_t mmu_id) +{ + for (int i = 0; i < MMU_ENTRY_NUM; i++) { + mmu_ll_set_entry_invalid(mmu_id, i); + } +} + +/** + * Check MMU table entry value is valid * * @param mmu_id MMU ID * @param entry_id MMU entry ID - * return ture for MMU entry is invalid, false for valid + * + * @return Ture for MMU entry is valid; False for invalid */ -__attribute__((always_inline)) static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); - uint32_t mmu_raw_value; REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); - mmu_raw_value = REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)); - /* Note: for ESP32-H2, the invalid-bit of MMU: 0 for invalid, 1 for valid */ - return (mmu_raw_value & MMU_INVALID_MASK) ? false : true; + return (REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)) & MMU_VALID) ? true : false; } -#ifdef __cplusplus +/** + * Get the MMU table entry target + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return Target, see `mmu_target_t` + */ +static inline mmu_target_t mmu_ll_get_entry_target(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + return MMU_TARGET_FLASH0; } -#endif +/** + * Convert MMU entry ID to paddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return paddr base + */ +static inline uint32_t mmu_ll_entry_id_to_paddr_base(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); + uint32_t shift_code = 0; + switch (page_size) { + case MMU_PAGE_64KB: + shift_code = 16; + break; + case MMU_PAGE_32KB: + shift_code = 15; + break; + case MMU_PAGE_16KB: + shift_code = 14; + break; + case MMU_PAGE_8KB: + shift_code = 13; + break; + default: + HAL_ASSERT(shift_code); + } + REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), entry_id); + return (REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)) & MMU_VALID_VAL_MASK) << shift_code; +} /** - * Unmap all the items in the MMU table + * Find the MMU table entry ID based on table map value + * @note This function can only find the first match entry ID. However it is possible that a physical address + * is mapped to multiple virtual addresses * - * @param mmu_id MMU ID + * @param mmu_id MMU ID + * @param mmu_val map value to be read from MMU table standing for paddr + * @param target physical memory target, see `mmu_target_t` + * + * @return MMU entry ID, -1 for invalid */ -__attribute__((always_inline)) -static inline void mmu_ll_unmap_all(uint32_t mmu_id) +static inline int mmu_ll_find_entry_id_based_on_map_value(uint32_t mmu_id, uint32_t mmu_val, mmu_target_t target) { + (void)mmu_id; for (int i = 0; i < MMU_ENTRY_NUM; i++) { - mmu_ll_set_entry_invalid(mmu_id, i); + if (mmu_ll_check_entry_valid(mmu_id, i)) { + if (mmu_ll_get_entry_target(mmu_id, i) == target) { + REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), i); + if ((REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0)) & MMU_VALID_VAL_MASK) == mmu_val) { + return i; + } + } + } } + + return -1; } + +/** + * Convert MMU entry ID to vaddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + */ +static inline uint32_t mmu_ll_entry_id_to_vaddr_base(uint32_t mmu_id, uint32_t entry_id, mmu_vaddr_t type) +{ + (void)mmu_id; + mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); + uint32_t shift_code = 0; + + switch (page_size) { + case MMU_PAGE_64KB: + shift_code = 16; + break; + case MMU_PAGE_32KB: + shift_code = 15; + break; + case MMU_PAGE_16KB: + shift_code = 14; + break; + case MMU_PAGE_8KB: + shift_code = 13; + break; + default: + HAL_ASSERT(shift_code); + } + uint32_t laddr = entry_id << shift_code; + return mmu_ll_laddr_to_vaddr(laddr, type); +} + + +#ifdef __cplusplus +} + +#endif diff --git a/components/hal/esp32h4/include/hal/mmu_ll.h b/components/hal/esp32h4/include/hal/mmu_ll.h index 799863b3ed1..c17910716f1 100644 --- a/components/hal/esp32h4/include/hal/mmu_ll.h +++ b/components/hal/esp32h4/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #pragma once +#include "esp_types.h" #include "soc/extmem_reg.h" #include "soc/ext_mem_defs.h" #include "hal/assert.h" @@ -18,6 +19,38 @@ extern "C" { #endif +/** + * Convert MMU virtual address to linear address + * + * @param vaddr virtual address + * + * @return linear address + */ +static inline uint32_t mmu_ll_vaddr_to_laddr(uint32_t vaddr) +{ + return vaddr & SOC_MMU_LINEAR_ADDR_MASK; +} + +/** + * Convert MMU linear address to virtual address + * + * @param laddr linear address + * @param vaddr_type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + * + * @return virtual address + */ +static inline uint32_t mmu_ll_laddr_to_vaddr(uint32_t laddr, mmu_vaddr_t vaddr_type) +{ + uint32_t vaddr_base = 0; + if (vaddr_type == MMU_VADDR_DATA) { + vaddr_base = SOC_MMU_DBUS_VADDR_BASE; + } else { + vaddr_base = SOC_MMU_IBUS_VADDR_BASE; + } + + return vaddr_base | laddr; +} + /** * Get MMU page size * @@ -64,6 +97,24 @@ static inline bool mmu_ll_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t return (ADDRESS_IN_IRAM0_CACHE(vaddr_start) && ADDRESS_IN_IRAM0_CACHE(vaddr_end)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start) && ADDRESS_IN_DRAM0_CACHE(vaddr_end)); } +/** + * Check if the paddr region is valid + * + * @param mmu_id MMU ID + * @param paddr_start start of the physical address + * @param len length, in bytes + * + * @return + * True for valid + */ +static inline bool mmu_ll_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len) +{ + (void)mmu_id; + return (paddr_start < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + (len < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + ((paddr_start + len - 1) < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)); +} + /** * To get the MMU table entry id to be mapped * @@ -85,14 +136,16 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) * * @param mmu_id MMU ID * @param paddr physical address to be mapped + * @param target paddr memory target, not used * * @return * mmu_val - paddr in MMU table supported format */ __attribute__((always_inline)) -static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr) +static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target) { (void)mmu_id; + (void)target; return paddr >> 16; } @@ -159,19 +212,93 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) } /** - * Get MMU table entry is invalid + * Check MMU table entry value is valid * * @param mmu_id MMU ID * @param entry_id MMU entry ID - * return ture for MMU entry is invalid, false for valid + * + * @return Ture for MMU entry is valid; False for invalid */ -__attribute__((always_inline)) -static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? false : true; +} + +/** + * Get the MMU table entry target + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return Target, see `mmu_target_t` + */ +static inline mmu_target_t mmu_ll_get_entry_target(uint32_t mmu_id, uint32_t entry_id) { (void)mmu_id; HAL_ASSERT(entry_id < MMU_ENTRY_NUM); - return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? true : false; + return MMU_TARGET_FLASH0; +} + +/** + * Convert MMU entry ID to paddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return paddr base + */ +static inline uint32_t mmu_ll_entry_id_to_paddr_base(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + return ((*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4)) & MMU_VALID_VAL_MASK) << 16; +} + +/** + * Find the MMU table entry ID based on table map value + * @note This function can only find the first match entry ID. However it is possible that a physical address + * is mapped to multiple virtual addresses + * + * @param mmu_id MMU ID + * @param mmu_val map value to be read from MMU table standing for paddr + * @param target physical memory target, see `mmu_target_t` + * + * @return MMU entry ID, -1 for invalid + */ +static inline int mmu_ll_find_entry_id_based_on_map_value(uint32_t mmu_id, uint32_t mmu_val, mmu_target_t target) +{ + (void)mmu_id; + for (int i = 0; i < MMU_ENTRY_NUM; i++) { + if (mmu_ll_check_entry_valid(mmu_id, i)) { + if (mmu_ll_get_entry_target(mmu_id, i) == target) { + if (((*(uint32_t *)(DR_REG_MMU_TABLE + i * 4)) & MMU_VALID_VAL_MASK) == mmu_val) { + return i; + } + } + } + } + + return -1; +} + +/** + * Convert MMU entry ID to vaddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + */ +static inline uint32_t mmu_ll_entry_id_to_vaddr_base(uint32_t mmu_id, uint32_t entry_id, mmu_vaddr_t type) +{ + (void)mmu_id; + uint32_t laddr = entry_id << 16; + + return mmu_ll_laddr_to_vaddr(laddr, type); } #ifdef __cplusplus diff --git a/components/hal/esp32s2/include/hal/cache_ll.h b/components/hal/esp32s2/include/hal/cache_ll.h index 6ef7621c656..d704aae45b2 100644 --- a/components/hal/esp32s2/include/hal/cache_ll.h +++ b/components/hal/esp32s2/include/hal/cache_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -38,7 +38,7 @@ __attribute__((always_inline)) #endif static inline cache_bus_mask_t cache_ll_l1_get_bus(uint32_t cache_id, uint32_t vaddr_start, uint32_t len) { - HAL_ASSERT(cache_id == 0); + (void)cache_id; cache_bus_mask_t mask = 0; uint32_t vaddr_end = vaddr_start + len - 1; @@ -87,7 +87,7 @@ __attribute__((always_inline)) #endif static inline void cache_ll_l1_enable_bus(uint32_t cache_id, cache_bus_mask_t mask) { - HAL_ASSERT(cache_id == 0); + (void)cache_id; uint32_t ibus_mask = 0; ibus_mask |= (mask & CACHE_BUS_IBUS0) ? EXTMEM_PRO_ICACHE_MASK_IRAM0 : 0; @@ -111,7 +111,7 @@ static inline void cache_ll_l1_enable_bus(uint32_t cache_id, cache_bus_mask_t ma __attribute__((always_inline)) static inline void cache_ll_l1_disable_bus(uint32_t cache_id, cache_bus_mask_t mask) { - HAL_ASSERT(cache_id == 0); + (void)cache_id; uint32_t ibus_mask = 0; ibus_mask |= (mask & CACHE_BUS_IBUS0) ? EXTMEM_PRO_ICACHE_MASK_IRAM0 : 0; diff --git a/components/hal/esp32s2/include/hal/mmu_ll.h b/components/hal/esp32s2/include/hal/mmu_ll.h index 43bfd9b39bc..a9017f8430b 100644 --- a/components/hal/esp32s2/include/hal/mmu_ll.h +++ b/components/hal/esp32s2/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -104,6 +104,24 @@ static inline bool mmu_ll_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t return (on_ibus || on_dbus); } +/** + * Check if the paddr region is valid + * + * @param mmu_id MMU ID + * @param paddr_start start of the physical address + * @param len length, in bytes + * + * @return + * True for valid + */ +static inline bool mmu_ll_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len) +{ + (void)mmu_id; + return (paddr_start < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + (len < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + ((paddr_start + len - 1) < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)); +} + /** * To get the MMU table entry id to be mapped * @@ -143,14 +161,16 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) * * @param mmu_id MMU ID * @param paddr physical address to be mapped + * @param target paddr memory target, not used * * @return * mmu_val - paddr in MMU table supported format */ __attribute__((always_inline)) -static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr) +static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target) { (void)mmu_id; + (void)target; return paddr >> 16; } @@ -217,19 +237,137 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) } /** - * Get MMU table entry is invalid + * Check MMU table entry value is valid * * @param mmu_id MMU ID * @param entry_id MMU entry ID - * return ture for MMU entry is invalid, false for valid + * + * @return Ture for MMU entry is valid; False for invalid */ -__attribute__((always_inline)) -static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) { (void)mmu_id; HAL_ASSERT(entry_id < MMU_ENTRY_NUM); - return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? true : false; + return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? false : true; +} + +/** + * Get the MMU table entry target + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return Target, see `mmu_target_t` + */ +static inline mmu_target_t mmu_ll_get_entry_target(uint32_t mmu_id, uint32_t entry_id) +{ + HAL_ASSERT(mmu_ll_check_entry_valid(mmu_id, entry_id)); + + if ((*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4)) & MMU_ACCESS_FLASH) { + return MMU_TARGET_FLASH0; + } else { + return MMU_TARGET_PSRAM0; + } + +} + +/** + * Convert MMU entry ID to paddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return paddr base + */ +static inline uint32_t mmu_ll_entry_id_to_paddr_base(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + + return ((*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4)) & MMU_VALID_VAL_MASK) << 16; +} + +/** + * Find the MMU table entry ID based on table map value + * @note This function can only find the first match entry ID. However it is possible that a physical address + * is mapped to multiple virtual addresses + * + * @param mmu_id MMU ID + * @param mmu_val map value to be read from MMU table standing for paddr + * @param target physical memory target, see `mmu_target_t` + * + * @return MMU entry ID, -1 for invalid + */ +static inline int mmu_ll_find_entry_id_based_on_map_value(uint32_t mmu_id, uint32_t mmu_val, mmu_target_t target) +{ + (void)mmu_id; + for (int i = 0; i < MMU_ENTRY_NUM; i++) { + if (mmu_ll_check_entry_valid(mmu_id, i)) { + if (mmu_ll_get_entry_target(mmu_id, i) == target) { + if (((*(uint32_t *)(DR_REG_MMU_TABLE + i * 4)) & MMU_VALID_VAL_MASK) == mmu_val) { + return i; + } + } + } + } + + return -1; +} + +/** + * Convert MMU entry ID to vaddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + */ +static inline uint32_t mmu_ll_entry_id_to_vaddr_base(uint32_t mmu_id, uint32_t entry_id, mmu_vaddr_t type) +{ + (void)mmu_id; + (void)type; + + uint32_t vaddr_base = 0; + if (entry_id < 0x40) { + if (type != MMU_VADDR_INSTRUCTION) { + return 0; + } + entry_id -= 0; + vaddr_base = 0x40000000; + } else if (entry_id >= 0x40 && entry_id < 0x80) { + if (type != MMU_VADDR_INSTRUCTION) { + return 0; + } + entry_id -= 0x40; + vaddr_base = 0x40000000; + } else if (entry_id >= 0x80 && entry_id < 0xC0) { + if (type != MMU_VADDR_DATA) { + return 0; + } + entry_id -= 0x80; + vaddr_base = 0x3f000000; + } else if (entry_id >= 0xC0 && entry_id < 0x100) { + if (type != MMU_VADDR_DATA) { + return 0; + } + entry_id -= 0xC0; + vaddr_base = 0x3f000000; + } else if (entry_id >= 0x100 && entry_id < 0x140) { + if (type != MMU_VADDR_DATA) { + return 0; + } + entry_id -= 0x100; + vaddr_base = 0x3f000000; + } else if (entry_id >= 0x140 && entry_id < 0x180) { + if (type != MMU_VADDR_DATA) { + return 0; + } + entry_id -= 0x140; + vaddr_base = 0x3f000000; + } else { + HAL_ASSERT(false); + } + + return vaddr_base + (entry_id << 16); } #ifdef __cplusplus diff --git a/components/hal/esp32s3/include/hal/mmu_ll.h b/components/hal/esp32s3/include/hal/mmu_ll.h index dfe70f1dee3..aaa51bd7e77 100644 --- a/components/hal/esp32s3/include/hal/mmu_ll.h +++ b/components/hal/esp32s3/include/hal/mmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,6 +8,7 @@ #pragma once +#include "esp_types.h" #include "soc/extmem_reg.h" #include "soc/ext_mem_defs.h" #include "hal/assert.h" @@ -96,6 +97,24 @@ static inline bool mmu_ll_check_valid_ext_vaddr_region(uint32_t mmu_id, uint32_t return (ADDRESS_IN_IRAM0_CACHE(vaddr_start) && ADDRESS_IN_IRAM0_CACHE(vaddr_end)) || (ADDRESS_IN_DRAM0_CACHE(vaddr_start) && ADDRESS_IN_DRAM0_CACHE(vaddr_end)); } +/** + * Check if the paddr region is valid + * + * @param mmu_id MMU ID + * @param paddr_start start of the physical address + * @param len length, in bytes + * + * @return + * True for valid + */ +static inline bool mmu_ll_check_valid_paddr_region(uint32_t mmu_id, uint32_t paddr_start, uint32_t len) +{ + (void)mmu_id; + return (paddr_start < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + (len < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)) && + ((paddr_start + len - 1) < (mmu_ll_get_page_size(mmu_id) * MMU_MAX_PADDR_PAGE_NUM)); +} + /** * To get the MMU table entry id to be mapped * @@ -117,14 +136,16 @@ static inline uint32_t mmu_ll_get_entry_id(uint32_t mmu_id, uint32_t vaddr) * * @param mmu_id MMU ID * @param paddr physical address to be mapped + * @param target paddr memory target, not used * * @return * mmu_val - paddr in MMU table supported format */ __attribute__((always_inline)) -static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr) +static inline uint32_t mmu_ll_format_paddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target) { (void)mmu_id; + (void)target; return paddr >> 16; } @@ -191,19 +212,94 @@ static inline void mmu_ll_unmap_all(uint32_t mmu_id) } /** - * Get MMU table entry is invalid + * Check MMU table entry value is valid * * @param mmu_id MMU ID * @param entry_id MMU entry ID - * return ture for MMU entry is invalid, false for valid + * + * @return Ture for MMU entry is valid; False for invalid */ -__attribute__((always_inline)) -static inline bool mmu_ll_get_entry_is_invalid(uint32_t mmu_id, uint32_t entry_id) +static inline bool mmu_ll_check_entry_valid(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? false : true; +} + +/** + * Get the MMU table entry target + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return Target, see `mmu_target_t` + */ +static inline mmu_target_t mmu_ll_get_entry_target(uint32_t mmu_id, uint32_t entry_id) +{ + (void)mmu_id; + HAL_ASSERT(entry_id < MMU_ENTRY_NUM); + + bool target_code = (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4)) & MMU_TYPE; + return (target_code == MMU_ACCESS_FLASH) ? MMU_TARGET_FLASH0 : MMU_TARGET_PSRAM0; +} + +/** + * Convert MMU entry ID to paddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * + * @return paddr base + */ +static inline uint32_t mmu_ll_entry_id_to_paddr_base(uint32_t mmu_id, uint32_t entry_id) { (void)mmu_id; HAL_ASSERT(entry_id < MMU_ENTRY_NUM); - return (*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4) & MMU_INVALID) ? true : false; + return ((*(uint32_t *)(DR_REG_MMU_TABLE + entry_id * 4)) & MMU_VALID_VAL_MASK) << 16; +} + +/** + * Find the MMU table entry ID based on table map value + * @note This function can only find the first match entry ID. However it is possible that a physical address + * is mapped to multiple virtual addresses + * + * @param mmu_id MMU ID + * @param mmu_val map value to be read from MMU table standing for paddr + * @param target physical memory target, see `mmu_target_t` + * + * @return MMU entry ID, -1 for invalid + */ +static inline int mmu_ll_find_entry_id_based_on_map_value(uint32_t mmu_id, uint32_t mmu_val, mmu_target_t target) +{ + (void)mmu_id; + for (int i = 0; i < MMU_ENTRY_NUM; i++) { + if (mmu_ll_check_entry_valid(mmu_id, i)) { + if (mmu_ll_get_entry_target(mmu_id, i) == target) { + if (((*(uint32_t *)(DR_REG_MMU_TABLE + i * 4)) & MMU_VALID_VAL_MASK) == mmu_val) { + return i; + } + } + } + } + + return -1; +} + +/** + * Convert MMU entry ID to vaddr base + * + * @param mmu_id MMU ID + * @param entry_id MMU entry ID + * @param type virtual address type, could be instruction type or data type. See `mmu_vaddr_t` + */ +static inline uint32_t mmu_ll_entry_id_to_vaddr_base(uint32_t mmu_id, uint32_t entry_id, mmu_vaddr_t type) +{ + (void)mmu_id; + uint32_t laddr = entry_id << 16; + + return mmu_ll_laddr_to_vaddr(laddr, type); } #ifdef __cplusplus diff --git a/components/hal/include/hal/cache_hal.h b/components/hal/include/hal/cache_hal.h index a8f5c522389..c147aaf868a 100644 --- a/components/hal/include/hal/cache_hal.h +++ b/components/hal/include/hal/cache_hal.h @@ -36,6 +36,14 @@ void cache_hal_disable(cache_type_t type); */ void cache_hal_enable(cache_type_t type); +/** + * Invalidate a Cache item for either ICache or DCache. + * + * @param vaddr Start address of the region to be invalidated + * @param size Size of the region to be invalidated + */ +void cache_hal_invalidate_addr(uint32_t vaddr, uint32_t size); + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/mmu_hal.h b/components/hal/include/hal/mmu_hal.h index 33418d32f2b..bd1287f1f4d 100644 --- a/components/hal/include/hal/mmu_hal.h +++ b/components/hal/include/hal/mmu_hal.h @@ -6,6 +6,7 @@ #pragma once +#include #include "hal/mmu_types.h" #ifdef __cplusplus @@ -17,7 +18,6 @@ extern "C" { */ void mmu_hal_init(void); -#if !CONFIG_IDF_TARGET_ESP32 /** * Helper functions to convert the MMU page numbers into bytes. e.g.: * - When MMU page size is 16KB, page_num = 2 will be converted into 32KB @@ -45,7 +45,7 @@ uint32_t mmu_hal_pages_to_bytes(uint32_t mmu_id, uint32_t page_num); uint32_t mmu_hal_bytes_to_pages(uint32_t mmu_id, uint32_t bytes); /** - * To map a virtual address region to a physical memory region + * To map a virtual address block to a physical memory block * * @param mmu_id MMU ID * @param mem_type physical memory type, see `mmu_target_t` @@ -57,7 +57,47 @@ uint32_t mmu_hal_bytes_to_pages(uint32_t mmu_id, uint32_t bytes); * @note vaddr and paddr should be aligned with the mmu page size, see CONFIG_MMU_PAGE_SIZE */ void mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr, uint32_t paddr, uint32_t len, uint32_t *out_len); -#endif + +/** + * To unmap a virtual address block that is mapped to a physical memory block previously + * + * @param[in] mmu_id MMU ID + * @param[in] vaddr start virtual address + * @param[in] len length to be unmapped, in bytes + */ +void mmu_hal_unmap_region(uint32_t mmu_id, uint32_t vaddr, uint32_t len); + +/** + * Convert virtual address to physical address + * + * @param mmu_id MMU ID + * @param vaddr virtual address + * @param[out] out_paddr physical address + * @param[out] out_target Indicating the vaddr/paddr is mapped on which target, see `mmu_target_t` + * + * @return + * - true: virtual address is valid + * - false: virtual address isn't valid + */ +bool mmu_hal_vaddr_to_paddr(uint32_t mmu_id, uint32_t vaddr, uint32_t *out_paddr, mmu_target_t *out_target); + +/** + * Convert physical address to virtual address + * + * @note This function can only find the first match virtual address. + * However it is possible that a physical address is mapped to multiple virtual addresses. + * + * @param mmu_id MMU ID + * @param paddr physical address + * @param target physical memory target, see `mmu_target_t` + * @param type virtual address type, could be instruction or data + * @param[out] out_vaddr virtual address + * + * @return + * - true: found a matched vaddr + * - false: not found a matched vaddr + */ +bool mmu_hal_paddr_to_vaddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target, mmu_vaddr_t type, uint32_t *out_vaddr); #ifdef __cplusplus } diff --git a/components/hal/include/hal/mmu_types.h b/components/hal/include/hal/mmu_types.h index 37a3a2cd5db..2f4562b6861 100644 --- a/components/hal/include/hal/mmu_types.h +++ b/components/hal/include/hal/mmu_types.h @@ -6,11 +6,20 @@ #pragma once +#include "esp_bit_defs.h" #ifdef __cplusplus extern "C" { #endif +typedef enum { + MMU_MEM_CAP_EXEC = BIT(0), + MMU_MEM_CAP_READ = BIT(1), + MMU_MEM_CAP_WRITE = BIT(2), + MMU_MEM_CAP_32BIT = BIT(3), + MMU_MEM_CAP_8BIT = BIT(4), +} mmu_mem_caps_t; + /** * MMU Page size */ @@ -33,8 +42,8 @@ typedef enum { * External physical memory */ typedef enum { - MMU_TARGET_FLASH0, - MMU_TARGET_PSRAM0, + MMU_TARGET_FLASH0 = BIT(0), + MMU_TARGET_PSRAM0 = BIT(1), } mmu_target_t; /** diff --git a/components/hal/mmu_hal.c b/components/hal/mmu_hal.c index fd7812fa690..d619ce5cb22 100644 --- a/components/hal/mmu_hal.c +++ b/components/hal/mmu_hal.c @@ -13,23 +13,6 @@ #include "hal/mmu_hal.h" #include "hal/mmu_ll.h" -#if CONFIG_IDF_TARGET_ESP32 -#include "esp32/rom/cache.h" -#include "soc/dport_reg.h" -#elif CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/rom/cache.h" -#elif CONFIG_IDF_TARGET_ESP32S3 -#include "esp32s3/rom/cache.h" -#elif CONFIG_IDF_TARGET_ESP32C3 -#include "esp32c3/rom/cache.h" -#elif CONFIG_IDF_TARGET_ESP32C2 -#include "esp32c2/rom/cache.h" -#elif CONFIG_IDF_TARGET_ESP32H4 -#include "esp32h4/rom/cache.h" -#elif CONFIG_IDF_TARGET_ESP32C6 -#include "esp32c6/rom/cache.h" -#endif - void mmu_hal_init(void) { mmu_ll_unmap_all(0); @@ -38,8 +21,6 @@ void mmu_hal_init(void) #endif } -#if !CONFIG_IDF_TARGET_ESP32 -//If decided, add a jira ticket for implementing these APIs on ESP32 uint32_t mmu_hal_pages_to_bytes(uint32_t mmu_id, uint32_t page_num) { mmu_page_size_t page_size = mmu_ll_get_page_size(mmu_id); @@ -85,7 +66,7 @@ void mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr, uint32_t page_size_in_bytes = mmu_hal_pages_to_bytes(mmu_id, 1); HAL_ASSERT(vaddr % page_size_in_bytes == 0); HAL_ASSERT(paddr % page_size_in_bytes == 0); - HAL_ASSERT((paddr + len - 1) < mmu_hal_pages_to_bytes(mmu_id, MMU_MAX_PADDR_PAGE_NUM)); + HAL_ASSERT(mmu_ll_check_valid_paddr_region(mmu_id, paddr, len)); HAL_ASSERT(mmu_ll_check_valid_ext_vaddr_region(mmu_id, vaddr, len)); uint32_t page_num = (len + page_size_in_bytes - 1) / page_size_in_bytes; @@ -93,7 +74,7 @@ void mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr, uint32_t mmu_val; //This is the physical address in the format that MMU supported *out_len = mmu_hal_pages_to_bytes(mmu_id, page_num); - mmu_val = mmu_ll_format_paddr(mmu_id, paddr); + mmu_val = mmu_ll_format_paddr(mmu_id, paddr, mem_type); while (page_num) { entry_id = mmu_ll_get_entry_id(mmu_id, vaddr); @@ -103,4 +84,58 @@ void mmu_hal_map_region(uint32_t mmu_id, mmu_target_t mem_type, uint32_t vaddr, page_num--; } } -#endif //#if !CONFIG_IDF_TARGET_ESP32 + +void mmu_hal_unmap_region(uint32_t mmu_id, uint32_t vaddr, uint32_t len) +{ + uint32_t page_size_in_bytes = mmu_hal_pages_to_bytes(mmu_id, 1); + HAL_ASSERT(vaddr % page_size_in_bytes == 0); + HAL_ASSERT(mmu_ll_check_valid_ext_vaddr_region(mmu_id, vaddr, len)); + + uint32_t page_num = (len + page_size_in_bytes - 1) / page_size_in_bytes; + uint32_t entry_id = 0; + while (page_num) { + entry_id = mmu_ll_get_entry_id(mmu_id, vaddr); + mmu_ll_set_entry_invalid(mmu_id, entry_id); + vaddr += page_size_in_bytes; + page_num--; + } +} + +bool mmu_hal_vaddr_to_paddr(uint32_t mmu_id, uint32_t vaddr, uint32_t *out_paddr, mmu_target_t *out_target) +{ + HAL_ASSERT(mmu_ll_check_valid_ext_vaddr_region(mmu_id, vaddr, 1)); + uint32_t entry_id = mmu_ll_get_entry_id(mmu_id, vaddr); + if (!mmu_ll_check_entry_valid(mmu_id, entry_id)) { + return false; + } + + uint32_t page_size_in_bytes = mmu_hal_pages_to_bytes(mmu_id, 1); + uint32_t offset = (uint32_t)vaddr % page_size_in_bytes; + + *out_target = mmu_ll_get_entry_target(mmu_id, entry_id); + uint32_t paddr_base = mmu_ll_entry_id_to_paddr_base(mmu_id, entry_id); + *out_paddr = paddr_base | offset; + + return true; +} + +bool mmu_hal_paddr_to_vaddr(uint32_t mmu_id, uint32_t paddr, mmu_target_t target, mmu_vaddr_t type, uint32_t *out_vaddr) +{ + HAL_ASSERT(mmu_ll_check_valid_paddr_region(mmu_id, paddr, 1)); + + uint32_t mmu_val = mmu_ll_format_paddr(mmu_id, paddr, target); + int entry_id = mmu_ll_find_entry_id_based_on_map_value(mmu_id, mmu_val, target); + if (entry_id == -1) { + return false; + } + + uint32_t page_size_in_bytes = mmu_hal_pages_to_bytes(mmu_id, 1); + uint32_t offset = paddr % page_size_in_bytes; + uint32_t vaddr_base = mmu_ll_entry_id_to_vaddr_base(mmu_id, entry_id, type); + if (vaddr_base == 0) { + return false; + } + *out_vaddr = vaddr_base | offset; + + return true; +} diff --git a/components/soc/esp32/include/soc/Kconfig.soc_caps.in b/components/soc/esp32/include/soc/Kconfig.soc_caps.in index 83e4718b4b5..03ffa47d610 100644 --- a/components/soc/esp32/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32/include/soc/Kconfig.soc_caps.in @@ -227,10 +227,6 @@ config SOC_SHARED_IDCACHE_SUPPORTED bool default y -config SOC_MMU_LINEAR_ADDRESS_REGION_NUM - int - default 5 - config SOC_CPU_CORES_NUM int default 2 @@ -443,6 +439,14 @@ config SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP int default 3 +config SOC_MMU_PERIPH_NUM + int + default 2 + +config SOC_MMU_LINEAR_ADDRESS_REGION_NUM + int + default 3 + config SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED bool default n diff --git a/components/soc/esp32/include/soc/ext_mem_defs.h b/components/soc/esp32/include/soc/ext_mem_defs.h index e4ec354ac16..305b97e72b1 100644 --- a/components/soc/esp32/include/soc/ext_mem_defs.h +++ b/components/soc/esp32/include/soc/ext_mem_defs.h @@ -39,7 +39,18 @@ extern "C" { #define MMU_INVALID BIT(8) -//MMU entry num, 384 entries that are used in IDF +/** + * Max MMU available paddr page num. + * `MMU_MAX_PADDR_PAGE_NUM * CONFIG_MMU_PAGE_SIZE` means the max paddr address supported by the MMU. e.g.: + * 256 * 64KB, means MMU can support 16MB paddr at most + */ +#define MMU_MAX_PADDR_PAGE_NUM 256 +/** + * This is the mask used for mapping. e.g.: + * 0x4008_0000 & MMU_VADDR_MASK + */ +#define MMU_VADDR_MASK 0x3FFFFF +//MMU entry num, 384 entries that are used in IDF for Flash #define MMU_ENTRY_NUM 384 diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index e7faae2f1a4..9099519090f 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -136,11 +136,8 @@ #define SOC_BROWNOUT_RESET_SUPPORTED 1 #endif - -/*-------------------------- CACHE/MMU CAPS ----------------------------------*/ +/*-------------------------- CACHE CAPS --------------------------------------*/ #define SOC_SHARED_IDCACHE_SUPPORTED 1 //Shared Cache for both instructions and data -#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM 5 - /*-------------------------- CPU CAPS ----------------------------------------*/ #define SOC_CPU_CORES_NUM 2 @@ -231,6 +228,10 @@ #define SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER (3) ///< The number of capture channels that each capture timer has #define SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP (3) ///< The number of GPIO synchros that each group has +/*-------------------------- MMU CAPS ----------------------------------------*/ +#define SOC_MMU_PERIPH_NUM 2 +#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM 3 + /*-------------------------- MPU CAPS ----------------------------------------*/ //TODO: correct the caller and remove unsupported lines #define SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED 0 diff --git a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in index c8bdeb8abad..41625862fff 100644 --- a/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c2/include/soc/Kconfig.soc_caps.in @@ -199,10 +199,6 @@ config SOC_CPU_IDRAM_SPLIT_USING_PMP bool default y -config SOC_MMU_PAGE_SIZE_CONFIGURABLE - bool - default y - config SOC_GDMA_GROUPS int default 1 @@ -307,6 +303,18 @@ config SOC_LEDC_GAMMA_FADE_RANGE_MAX int default 1 +config SOC_MMU_PAGE_SIZE_CONFIGURABLE + bool + default y + +config SOC_MMU_LINEAR_ADDRESS_REGION_NUM + int + default 1 + +config SOC_MMU_PERIPH_NUM + int + default 1 + config SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED bool default n diff --git a/components/soc/esp32c2/include/soc/ext_mem_defs.h b/components/soc/esp32c2/include/soc/ext_mem_defs.h index b5b65443d23..c343b118b64 100644 --- a/components/soc/esp32c2/include/soc/ext_mem_defs.h +++ b/components/soc/esp32c2/include/soc/ext_mem_defs.h @@ -3,40 +3,42 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef _CACHE_MEMORY_H_ -#define _CACHE_MEMORY_H_ +#pragma once + +#include +#include "sdkconfig.h" #include "esp_bit_defs.h" #ifdef __cplusplus extern "C" { #endif -#include + /*IRAM0 is connected with Cache IBUS0*/ #define IRAM0_ADDRESS_LOW 0x4037C000 #define IRAM0_ADDRESS_HIGH 0x403C0000 #define IRAM0_CACHE_ADDRESS_LOW 0x42000000 -#define IRAM0_CACHE_ADDRESS_HIGH(page_size) (IRAM0_CACHE_ADDRESS_LOW + ((page_size) * 64)) // MMU has 64 pages +#define IRAM0_CACHE_ADDRESS_HIGH (IRAM0_CACHE_ADDRESS_LOW + ((CONFIG_MMU_PAGE_SIZE) * MMU_ENTRY_NUM)) // MMU has 64 pages /*DRAM0 is connected with Cache DBUS0*/ #define DRAM0_ADDRESS_LOW 0x3FCA0000 #define DRAM0_ADDRESS_HIGH 0x3FCE0000 #define DRAM0_CACHE_ADDRESS_LOW 0x3C000000 -#define DRAM0_CACHE_ADDRESS_HIGH(page_size) (DRAM0_CACHE_ADDRESS_LOW + ((page_size) * 64)) // MMU has 64 pages -#define DRAM0_CACHE_OPERATION_HIGH(page_size) DRAM0_CACHE_ADDRESS_HIGH(page_size) +#define DRAM0_CACHE_ADDRESS_HIGH (DRAM0_CACHE_ADDRESS_LOW + ((CONFIG_MMU_PAGE_SIZE) * MMU_ENTRY_NUM)) // MMU has 64 pages +#define DRAM0_CACHE_OPERATION_HIGH DRAM0_CACHE_ADDRESS_HIGH -#define BUS_SIZE(bus_name, page_size) (bus_name##_ADDRESS_HIGH(page_size) - bus_name##_ADDRESS_LOW) -#define ADDRESS_IN_BUS(bus_name, vaddr, page_size) ((vaddr) >= bus_name##_ADDRESS_LOW && (vaddr) < bus_name##_ADDRESS_HIGH(page_size)) +#define BUS_SIZE(bus_name) (bus_name##_ADDRESS_HIGH - bus_name##_ADDRESS_LOW) +#define ADDRESS_IN_BUS(bus_name, vaddr) ((vaddr) >= bus_name##_ADDRESS_LOW && (vaddr) < bus_name##_ADDRESS_HIGH) -#define ADDRESS_IN_IRAM0(vaddr, page_size) ADDRESS_IN_BUS(IRAM0, vaddr, page_size) -#define ADDRESS_IN_IRAM0_CACHE(vaddr, page_size) ADDRESS_IN_BUS(IRAM0_CACHE, vaddr, page_size) -#define ADDRESS_IN_DRAM0(vaddr, page_size) ADDRESS_IN_BUS(DRAM0, vaddr, page_size) -#define ADDRESS_IN_DRAM0_CACHE(vaddr, page_size) ADDRESS_IN_BUS(DRAM0_CACHE, vaddr, page_size) +#define ADDRESS_IN_IRAM0(vaddr) ADDRESS_IN_BUS(IRAM0, vaddr) +#define ADDRESS_IN_IRAM0_CACHE(vaddr) ADDRESS_IN_BUS(IRAM0_CACHE, vaddr) +#define ADDRESS_IN_DRAM0(vaddr) ADDRESS_IN_BUS(DRAM0, vaddr) +#define ADDRESS_IN_DRAM0_CACHE(vaddr) ADDRESS_IN_BUS(DRAM0_CACHE, vaddr) -#define BUS_IRAM0_CACHE_SIZE(page_size) BUS_SIZE(IRAM0_CACHE, page_size) -#define BUS_DRAM0_CACHE_SIZE(page_size) BUS_SIZE(DRAM0_CACHE, page_size) +#define BUS_IRAM0_CACHE_SIZE BUS_SIZE(IRAM0_CACHE) +#define BUS_DRAM0_CACHE_SIZE BUS_SIZE(DRAM0_CACHE) #define CACHE_IBUS 0 #define CACHE_IBUS_MMU_START 0 @@ -71,9 +73,6 @@ extern "C" { #define CACHE_MAX_SYNC_NUM 0x400000 #define CACHE_MAX_LOCK_NUM 0x8000 -#define FLASH_MMU_TABLE ((volatile uint32_t*) DR_REG_MMU_TABLE) -#define FLASH_MMU_TABLE_SIZE (ICACHE_MMU_SIZE/sizeof(uint32_t)) - /** * MMU entry valid bit mask for mapping value. For an entry: * valid bit + value bits @@ -91,7 +90,7 @@ extern "C" { * This is the mask used for mapping. e.g.: * 0x4200_0000 & MMU_VADDR_MASK */ -#define MMU_VADDR_MASK(page_size) ((page_size) * 64 - 1) +#define MMU_VADDR_MASK ((CONFIG_MMU_PAGE_SIZE) * 64 - 1) //MMU entry num #define MMU_ENTRY_NUM 64 @@ -104,9 +103,65 @@ extern "C" { #define CACHE_MEMORY_IBANK0_ADDR 0x4037C000 +#define SOC_MMU_DBUS_VADDR_BASE 0x3C000000 +#define SOC_MMU_IBUS_VADDR_BASE 0x42000000 + +/*------------------------------------------------------------------------------ + * MMU Linear Address + *----------------------------------------------------------------------------*/ +#if (CONFIG_MMU_PAGE_SIZE == 0x10000) +/** + * - 64KB MMU page size: the last 0xFFFF, which is the offset + * - 64 MMU entries, needs 0x3F to hold it. + * + * Therefore, 0x3F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x3FFFFF + +#elif (CONFIG_MMU_PAGE_SIZE == 0x8000) +/** + * - 32KB MMU page size: the last 0x7FFF, which is the offset + * - 64 MMU entries, needs 0x3F to hold it. + * + * Therefore, 0x1F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x1FFFFF + +#elif (CONFIG_MMU_PAGE_SIZE == 0x4000) +/** + * - 16KB MMU page size: the last 0x3FFF, which is the offset + * - 64 MMU entries, needs 0x3F to hold it. + * + * Therefore, 0xF,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0xFFFFF +#endif //CONFIG_MMU_PAGE_SIZE + +/** + * - If high linear address isn't 0, this means MMU can recognize these addresses + * - If high linear address is 0, this means MMU linear address range is equal or smaller than vaddr range. + * Under this condition, we use the max linear space. + */ +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW (IRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW (DRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +/** + * I/D share the MMU linear address range + */ +_Static_assert(SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW == SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW, "IRAM0 and DRAM0 linear address should be same"); + #ifdef __cplusplus } #endif - -#endif /*_CACHE_MEMORY_H_ */ diff --git a/components/soc/esp32c2/include/soc/soc_caps.h b/components/soc/esp32c2/include/soc/soc_caps.h index e2baa106234..75dffa610ab 100644 --- a/components/soc/esp32c2/include/soc/soc_caps.h +++ b/components/soc/esp32c2/include/soc/soc_caps.h @@ -97,9 +97,6 @@ #define SOC_CPU_IDRAM_SPLIT_USING_PMP 1 -/*-------------------------- MMU CAPS ----------------------------------------*/ -#define SOC_MMU_PAGE_SIZE_CONFIGURABLE (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 @@ -154,6 +151,11 @@ #define SOC_LEDC_SUPPORT_FADE_STOP (1) #define SOC_LEDC_GAMMA_FADE_RANGE_MAX (1U) // The target does not support gamma curve fading +/*-------------------------- MMU CAPS ----------------------------------------*/ +#define SOC_MMU_PAGE_SIZE_CONFIGURABLE (1) +#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM (1U) +#define SOC_MMU_PERIPH_NUM (1U) + /*-------------------------- MPU CAPS ----------------------------------------*/ #define SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED 0 #define SOC_MPU_MIN_REGION_SIZE 0x20000000U diff --git a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in index 8befab9582d..4952e6cc088 100644 --- a/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c3/include/soc/Kconfig.soc_caps.in @@ -439,6 +439,14 @@ config SOC_LEDC_GAMMA_FADE_RANGE_MAX int default 1 +config SOC_MMU_LINEAR_ADDRESS_REGION_NUM + int + default 1 + +config SOC_MMU_PERIPH_NUM + int + default 1 + config SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED bool default n diff --git a/components/soc/esp32c3/include/soc/ext_mem_defs.h b/components/soc/esp32c3/include/soc/ext_mem_defs.h index 8415315cbf0..d14e74daf31 100644 --- a/components/soc/esp32c3/include/soc/ext_mem_defs.h +++ b/components/soc/esp32c3/include/soc/ext_mem_defs.h @@ -69,9 +69,6 @@ extern "C" { #define CACHE_MAX_SYNC_NUM 0x400000 #define CACHE_MAX_LOCK_NUM 0x8000 -#define FLASH_MMU_TABLE ((volatile uint32_t*) DR_REG_MMU_TABLE) -#define FLASH_MMU_TABLE_SIZE (ICACHE_MMU_SIZE/sizeof(uint32_t)) - /** * MMU entry valid bit mask for mapping value. For an entry: * valid bit + value bits @@ -99,6 +96,45 @@ extern "C" { #define CACHE_MEMORY_IBANK0_ADDR 0x4037c000 +#define SOC_MMU_DBUS_VADDR_BASE 0x3C000000 +#define SOC_MMU_IBUS_VADDR_BASE 0x42000000 + +/*------------------------------------------------------------------------------ + * MMU Linear Address + *----------------------------------------------------------------------------*/ +/** + * - 64KB MMU page size: the last 0xFFFF, which is the offset + * - 128 MMU entries, needs 0x7F to hold it. + * + * Therefore, 0x7F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x7FFFFF + +/** + * - If high linear address isn't 0, this means MMU can recognize these addresses + * - If high linear address is 0, this means MMU linear address range is equal or smaller than vaddr range. + * Under this condition, we use the max linear space. + */ +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW (IRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW (DRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +/** + * I/D share the MMU linear address range + */ +_Static_assert(SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW == SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW, "IRAM0 and DRAM0 linear address should be same"); + + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 32c29d55e08..73169c38ce6 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -204,6 +204,10 @@ #define SOC_LEDC_SUPPORT_FADE_STOP (1) #define SOC_LEDC_GAMMA_FADE_RANGE_MAX (1U) // The target does not support gamma curve fading +/*-------------------------- MMU CAPS ----------------------------------------*/ +#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM (1U) +#define SOC_MMU_PERIPH_NUM (1U) + /*-------------------------- MPU CAPS ----------------------------------------*/ #define SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED 0 #define SOC_MPU_MIN_REGION_SIZE 0x20000000U diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index cbe020885ce..9045aea2501 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -311,10 +311,6 @@ config SOC_CPU_IDRAM_SPLIT_USING_PMP bool default y -config SOC_MMU_PAGE_SIZE_CONFIGURABLE - bool - default y - config SOC_DS_SIGNATURE_MAX_BIT_LEN int default 3072 @@ -511,6 +507,18 @@ config SOC_LEDC_GAMMA_FADE_RANGE_MAX int default 16 +config SOC_MMU_PAGE_SIZE_CONFIGURABLE + bool + default y + +config SOC_MMU_PERIPH_NUM + int + default 1 + +config SOC_MMU_LINEAR_ADDRESS_REGION_NUM + int + default 1 + config SOC_MMU_DI_VADDR_SHARED bool default y diff --git a/components/soc/esp32c6/include/soc/ext_mem_defs.h b/components/soc/esp32c6/include/soc/ext_mem_defs.h index 805022d07d0..9be2303cbd4 100644 --- a/components/soc/esp32c6/include/soc/ext_mem_defs.h +++ b/components/soc/esp32c6/include/soc/ext_mem_defs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,35 +13,24 @@ extern "C" { #endif -#define IRAM0_ADDRESS_LOW 0x40800000 -#define IRAM0_ADDRESS_HIGH 0x40880000 + #define IRAM0_CACHE_ADDRESS_LOW 0x42000000 -#define IRAM0_CACHE_ADDRESS_HIGH(page_size) (IRAM0_CACHE_ADDRESS_LOW + ((page_size) * 256)) +#define IRAM0_CACHE_ADDRESS_HIGH (IRAM0_CACHE_ADDRESS_LOW + ((CONFIG_MMU_PAGE_SIZE) * MMU_ENTRY_NUM)) -#define DRAM0_ADDRESS_LOW IRAM0_ADDRESS_LOW //I/D share the same vaddr range -#define DRAM0_ADDRESS_HIGH IRAM0_ADDRESS_HIGH //I/D share the same vaddr range #define DRAM0_CACHE_ADDRESS_LOW IRAM0_CACHE_ADDRESS_LOW //I/D share the same vaddr range -#define DRAM0_CACHE_ADDRESS_HIGH(page_size) IRAM0_CACHE_ADDRESS_HIGH(page_size) //I/D share the same vaddr range -#define DRAM0_CACHE_OPERATION_HIGH(page_size) DRAM0_CACHE_ADDRESS_HIGH(page_size) - -#define BUS_SIZE(bus_name, page_size) (bus_name##_ADDRESS_HIGH(page_size) - bus_name##_ADDRESS_LOW) -#define ADDRESS_IN_BUS(bus_name, vaddr, page_size) ((vaddr) >= bus_name##_ADDRESS_LOW && (vaddr) < bus_name##_ADDRESS_HIGH(page_size)) +#define DRAM0_CACHE_ADDRESS_HIGH IRAM0_CACHE_ADDRESS_HIGH //I/D share the same vaddr range +#define DRAM0_CACHE_OPERATION_HIGH DRAM0_CACHE_ADDRESS_HIGH -#define ADDRESS_IN_IRAM0(vaddr, page_size) ADDRESS_IN_BUS(IRAM0, vaddr, page_size) -#define ADDRESS_IN_IRAM0_CACHE(vaddr, page_size) ADDRESS_IN_BUS(IRAM0_CACHE, vaddr, page_size) -#define ADDRESS_IN_DRAM0(vaddr, page_size) ADDRESS_IN_BUS(DRAM0, vaddr, page_size) -#define ADDRESS_IN_DRAM0_CACHE(vaddr, page_size) ADDRESS_IN_BUS(DRAM0_CACHE, vaddr, page_size) +#define BUS_SIZE(bus_name) (bus_name##_ADDRESS_HIGH - bus_name##_ADDRESS_LOW) +#define ADDRESS_IN_BUS(bus_name, vaddr) ((vaddr) >= bus_name##_ADDRESS_LOW && (vaddr) < bus_name##_ADDRESS_HIGH) -#define BUS_IRAM0_CACHE_SIZE(page_size) BUS_SIZE(IRAM0_CACHE, page_size) -#define BUS_DRAM0_CACHE_SIZE(page_size) BUS_SIZE(DRAM0_CACHE, page_size) +#define ADDRESS_IN_IRAM0(vaddr) ADDRESS_IN_BUS(IRAM0, vaddr) +#define ADDRESS_IN_IRAM0_CACHE(vaddr) ADDRESS_IN_BUS(IRAM0_CACHE, vaddr) +#define ADDRESS_IN_DRAM0(vaddr) ADDRESS_IN_BUS(DRAM0, vaddr) +#define ADDRESS_IN_DRAM0_CACHE(vaddr) ADDRESS_IN_BUS(DRAM0_CACHE, vaddr) -#define CACHE_IBUS 0 -#define CACHE_IBUS_MMU_START 0 -#define CACHE_IBUS_MMU_END 0x200 - -#define CACHE_DBUS 1 -#define CACHE_DBUS_MMU_START 0 -#define CACHE_DBUS_MMU_END 0x200 +#define BUS_IRAM0_CACHE_SIZE BUS_SIZE(IRAM0_CACHE) +#define BUS_DRAM0_CACHE_SIZE BUS_SIZE(DRAM0_CACHE) //TODO, remove these cache function dependencies #define CACHE_IROM_MMU_START 0 @@ -66,11 +55,9 @@ extern "C" { #define MMU_MSPI_SENSITIVE BIT(10) #define MMU_ACCESS_FLASH MMU_MSPI_ACCESS_FLASH -#define MMU_ACCESS_SPIRAM MMU_MSPI_ACCESS_SPIRAM #define MMU_VALID MMU_MSPI_VALID #define MMU_SENSITIVE MMU_MSPI_SENSITIVE -// ESP32C6-TODO #define MMU_INVALID_MASK MMU_MSPI_VALID #define MMU_INVALID MMU_MSPI_INVALID @@ -79,9 +66,6 @@ extern "C" { #define CACHE_MAX_SYNC_NUM 0x400000 #define CACHE_MAX_LOCK_NUM 0x8000 -#define FLASH_MMU_TABLE ((volatile uint32_t*) DR_REG_MMU_TABLE) -#define FLASH_MMU_TABLE_SIZE (ICACHE_MMU_SIZE/sizeof(uint32_t)) - /** * MMU entry valid bit mask for mapping value. For an entry: * valid bit + value bits @@ -101,10 +85,70 @@ extern "C" { * This is the mask used for mapping. e.g.: * 0x4200_0000 & MMU_VADDR_MASK */ -#define MMU_VADDR_MASK(page_size) ((page_size) * MMU_ENTRY_NUM - 1) +#define MMU_VADDR_MASK ((CONFIG_MMU_PAGE_SIZE) * MMU_ENTRY_NUM - 1) #define CACHE_MEMORY_IBANK0_ADDR 0x40800000 + +#define SOC_MMU_DBUS_VADDR_BASE 0x42000000 +#define SOC_MMU_IBUS_VADDR_BASE 0x42000000 + +/*------------------------------------------------------------------------------ + * MMU Linear Address + *----------------------------------------------------------------------------*/ +#if (CONFIG_MMU_PAGE_SIZE == 0x10000) +/** + * - 64KB MMU page size: the last 0xFFFF, which is the offset + * - 128 MMU entries, needs 0x7F to hold it. + * + * Therefore, 0x7F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x7FFFFF + +#elif (CONFIG_MMU_PAGE_SIZE == 0x8000) +/** + * - 32KB MMU page size: the last 0x7FFF, which is the offset + * - 128 MMU entries, needs 0x7F to hold it. + * + * Therefore, 0x3F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x3FFFFF + +#elif (CONFIG_MMU_PAGE_SIZE == 0x4000) +/** + * - 16KB MMU page size: the last 0x3FFF, which is the offset + * - 128 MMU entries, needs 0x7F to hold it. + * + * Therefore, 0x1F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x1FFFFF +#endif //CONFIG_MMU_PAGE_SIZE + +/** + * - If high linear address isn't 0, this means MMU can recognize these addresses + * - If high linear address is 0, this means MMU linear address range is equal or smaller than vaddr range. + * Under this condition, we use the max linear space. + */ +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW (IRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW (DRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +/** + * I/D share the MMU linear address range + */ +_Static_assert(SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW == SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW, "IRAM0 and DRAM0 linear address should be same"); + + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c6/include/soc/mmu.h b/components/soc/esp32c6/include/soc/mmu.h index 4ce5d7326f0..e4b92941460 100644 --- a/components/soc/esp32c6/include/soc/mmu.h +++ b/components/soc/esp32c6/include/soc/mmu.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,7 +23,6 @@ extern "C" { #define SOC_MMU_INVALID_ENTRY_VAL MMU_TABLE_INVALID_VAL #define SOC_MMU_ADDR_MASK (MMU_VALID - 1) #define SOC_MMU_PAGE_IN_FLASH(page) (page) //Always in Flash -#define SOC_MMU_DPORT_PRO_FLASH_MMU_TABLE FLASH_MMU_TABLE #define SOC_MMU_VADDR1_START_ADDR IRAM0_CACHE_ADDRESS_LOW #define SOC_MMU_PRO_IRAM0_FIRST_USABLE_PAGE SOC_MMU_IROM0_PAGES_START #define SOC_MMU_VADDR0_START_ADDR (SOC_IROM_LOW + (SOC_MMU_DROM0_PAGES_START * SPI_FLASH_MMU_PAGE_SIZE)) diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 98a025c33cd..d670c7ccc37 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -134,10 +134,6 @@ #define SOC_CPU_HAS_PMA 1 #define SOC_CPU_IDRAM_SPLIT_USING_PMP 1 -// TODO: IDF-5339 (Copy from esp32c3, need check) -/*-------------------------- MMU CAPS ----------------------------------------*/ -#define SOC_MMU_PAGE_SIZE_CONFIGURABLE (1) - // TODO: IDF-5360 (Copy from esp32c3, need check) /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/ /** The maximum length of a Digital Signature in bits. */ @@ -233,6 +229,9 @@ #define SOC_LEDC_GAMMA_FADE_RANGE_MAX (16) /*-------------------------- MMU CAPS ----------------------------------------*/ +#define SOC_MMU_PAGE_SIZE_CONFIGURABLE (1) +#define SOC_MMU_PERIPH_NUM (1U) +#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM (1U) #define SOC_MMU_DI_VADDR_SHARED (1) /*!< D/I vaddr are shared */ /*-------------------------- MPU CAPS ----------------------------------------*/ diff --git a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in index 69adb76e9ee..69cc116a329 100644 --- a/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h2/include/soc/Kconfig.soc_caps.in @@ -223,6 +223,18 @@ config SOC_MMU_PAGE_SIZE_CONFIGURABLE bool default y +config SOC_MMU_PERIPH_NUM + int + default 1 + +config SOC_MMU_LINEAR_ADDRESS_REGION_NUM + int + default 1 + +config SOC_MMU_DI_VADDR_SHARED + bool + default y + config SOC_DS_SIGNATURE_MAX_BIT_LEN int default 3072 diff --git a/components/soc/esp32h2/include/soc/ext_mem_defs.h b/components/soc/esp32h2/include/soc/ext_mem_defs.h index 397a577d757..3d9abf12747 100644 --- a/components/soc/esp32h2/include/soc/ext_mem_defs.h +++ b/components/soc/esp32h2/include/soc/ext_mem_defs.h @@ -13,38 +13,23 @@ extern "C" { #endif -/*IRAM0 is connected with Cache IBUS0*/ -#define IRAM0_CACHE_ADDRESS_LOW 0x42000000 -#define IRAM0_CACHE_ADDRESS_HIGH(page_size) (IRAM0_CACHE_ADDRESS_LOW + ((page_size) * 128)) // MMU has 256 pages, first 128 for instruction -#define IRAM0_ADDRESS_LOW 0x40000000 -#define IRAM0_ADDRESS_HIGH(page_size) IRAM0_CACHE_ADDRESS_HIGH(page_size) - -/*DRAM0 is connected with Cache DBUS0*/ -#define DRAM0_ADDRESS_LOW 0x42000000 -#define DRAM0_ADDRESS_HIGH 0x43000000 -#define DRAM0_CACHE_ADDRESS_LOW IRAM0_CACHE_ADDRESS_HIGH(CONFIG_MMU_PAGE_SIZE) // ESP32H2-TODO : IDF-6370 -#define DRAM0_CACHE_ADDRESS_HIGH(page_size) (IRAM0_CACHE_ADDRESS_HIGH(page_size) + ((page_size) * 128)) // MMU has 256 pages, second 128 for data -#define DRAM0_CACHE_OPERATION_HIGH(page_size) DRAM0_CACHE_ADDRESS_HIGH(page_size) -#define ESP_CACHE_TEMP_ADDR 0x42000000 - -#define BUS_SIZE(bus_name, page_size) (bus_name##_ADDRESS_HIGH(page_size) - bus_name##_ADDRESS_LOW) -#define ADDRESS_IN_BUS(bus_name, vaddr, page_size) ((vaddr) >= bus_name##_ADDRESS_LOW && (vaddr) < bus_name##_ADDRESS_HIGH(page_size)) - -#define ADDRESS_IN_IRAM0(vaddr, page_size) ADDRESS_IN_BUS(IRAM0, vaddr, page_size) -#define ADDRESS_IN_IRAM0_CACHE(vaddr, page_size) ADDRESS_IN_BUS(IRAM0_CACHE, vaddr, page_size) -#define ADDRESS_IN_DRAM0(vaddr, page_size) ADDRESS_IN_BUS(DRAM0, vaddr, page_size) -#define ADDRESS_IN_DRAM0_CACHE(vaddr, page_size) ADDRESS_IN_BUS(DRAM0_CACHE, vaddr, page_size) - -#define BUS_IRAM0_CACHE_SIZE(page_size) BUS_SIZE(IRAM0_CACHE, page_size) -#define BUS_DRAM0_CACHE_SIZE(page_size) BUS_SIZE(DRAM0_CACHE, page_size) - -#define CACHE_IBUS 0 -#define CACHE_IBUS_MMU_START 0 -#define CACHE_IBUS_MMU_END 0x200 - -#define CACHE_DBUS 1 -#define CACHE_DBUS_MMU_START 0 -#define CACHE_DBUS_MMU_END 0x200 +#define IRAM0_CACHE_ADDRESS_LOW 0x42000000 +#define IRAM0_CACHE_ADDRESS_HIGH (IRAM0_CACHE_ADDRESS_LOW + ((CONFIG_MMU_PAGE_SIZE) * MMU_ENTRY_NUM)) + +#define DRAM0_CACHE_ADDRESS_LOW IRAM0_CACHE_ADDRESS_LOW //I/D share the same vaddr range +#define DRAM0_CACHE_ADDRESS_HIGH IRAM0_CACHE_ADDRESS_HIGH //I/D share the same vaddr range +#define DRAM0_CACHE_OPERATION_HIGH DRAM0_CACHE_ADDRESS_HIGH + +#define BUS_SIZE(bus_name) (bus_name##_ADDRESS_HIGH - bus_name##_ADDRESS_LOW) +#define ADDRESS_IN_BUS(bus_name, vaddr) ((vaddr) >= bus_name##_ADDRESS_LOW && (vaddr) < bus_name##_ADDRESS_HIGH) + +#define ADDRESS_IN_IRAM0(vaddr) ADDRESS_IN_BUS(IRAM0, vaddr) +#define ADDRESS_IN_IRAM0_CACHE(vaddr) ADDRESS_IN_BUS(IRAM0_CACHE, vaddr) +#define ADDRESS_IN_DRAM0(vaddr) ADDRESS_IN_BUS(DRAM0, vaddr) +#define ADDRESS_IN_DRAM0_CACHE(vaddr) ADDRESS_IN_BUS(DRAM0_CACHE, vaddr) + +#define BUS_IRAM0_CACHE_SIZE(page_size) BUS_SIZE(IRAM0_CACHE) +#define BUS_DRAM0_CACHE_SIZE(page_size) BUS_SIZE(DRAM0_CACHE) //TODO, remove these cache function dependencies #define CACHE_IROM_MMU_START 0 @@ -69,11 +54,9 @@ extern "C" { #define MMU_MSPI_SENSITIVE BIT(10) #define MMU_ACCESS_FLASH MMU_MSPI_ACCESS_FLASH -#define MMU_ACCESS_SPIRAM MMU_MSPI_ACCESS_SPIRAM #define MMU_VALID MMU_MSPI_VALID #define MMU_SENSITIVE MMU_MSPI_SENSITIVE -// ESP32H2-TODO : IDF-6251 #define MMU_INVALID_MASK MMU_MSPI_VALID #define MMU_INVALID MMU_MSPI_INVALID @@ -82,9 +65,6 @@ extern "C" { #define CACHE_MAX_SYNC_NUM 0x400000 #define CACHE_MAX_LOCK_NUM 0x8000 -#define FLASH_MMU_TABLE ((volatile uint32_t*) DR_REG_MMU_TABLE) -#define FLASH_MMU_TABLE_SIZE (ICACHE_MMU_SIZE/sizeof(uint32_t)) - /** * MMU entry valid bit mask for mapping value. For an entry: * valid bit + value bits @@ -104,10 +84,70 @@ extern "C" { * This is the mask used for mapping. e.g.: * 0x4200_0000 & MMU_VADDR_MASK */ -#define MMU_VADDR_MASK(page_size) ((page_size) * MMU_ENTRY_NUM - 1) +#define MMU_VADDR_MASK ((CONFIG_MMU_PAGE_SIZE) * MMU_ENTRY_NUM - 1) #define CACHE_MEMORY_IBANK0_ADDR 0x40800000 + +#define SOC_MMU_DBUS_VADDR_BASE 0x42000000 +#define SOC_MMU_IBUS_VADDR_BASE 0x42000000 + +/*------------------------------------------------------------------------------ + * MMU Linear Address + *----------------------------------------------------------------------------*/ +#if (CONFIG_MMU_PAGE_SIZE == 0x10000) +/** + * - 64KB MMU page size: the last 0xFFFF, which is the offset + * - 128 MMU entries, needs 0x7F to hold it. + * + * Therefore, 0x7F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x7FFFFF + +#elif (CONFIG_MMU_PAGE_SIZE == 0x8000) +/** + * - 32KB MMU page size: the last 0x7FFF, which is the offset + * - 128 MMU entries, needs 0x7F to hold it. + * + * Therefore, 0x3F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x3FFFFF + +#elif (CONFIG_MMU_PAGE_SIZE == 0x4000) +/** + * - 16KB MMU page size: the last 0x3FFF, which is the offset + * - 128 MMU entries, needs 0x7F to hold it. + * + * Therefore, 0x1F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x1FFFFF +#endif //CONFIG_MMU_PAGE_SIZE + +/** + * - If high linear address isn't 0, this means MMU can recognize these addresses + * - If high linear address is 0, this means MMU linear address range is equal or smaller than vaddr range. + * Under this condition, we use the max linear space. + */ +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW (IRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW (DRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +/** + * I/D share the MMU linear address range + */ +_Static_assert(SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW == SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW, "IRAM0 and DRAM0 linear address should be same"); + + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32h2/include/soc/mmu.h b/components/soc/esp32h2/include/soc/mmu.h index 4ce5d7326f0..e4b92941460 100644 --- a/components/soc/esp32h2/include/soc/mmu.h +++ b/components/soc/esp32h2/include/soc/mmu.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,7 +23,6 @@ extern "C" { #define SOC_MMU_INVALID_ENTRY_VAL MMU_TABLE_INVALID_VAL #define SOC_MMU_ADDR_MASK (MMU_VALID - 1) #define SOC_MMU_PAGE_IN_FLASH(page) (page) //Always in Flash -#define SOC_MMU_DPORT_PRO_FLASH_MMU_TABLE FLASH_MMU_TABLE #define SOC_MMU_VADDR1_START_ADDR IRAM0_CACHE_ADDRESS_LOW #define SOC_MMU_PRO_IRAM0_FIRST_USABLE_PAGE SOC_MMU_IROM0_PAGES_START #define SOC_MMU_VADDR0_START_ADDR (SOC_IROM_LOW + (SOC_MMU_DROM0_PAGES_START * SPI_FLASH_MMU_PAGE_SIZE)) diff --git a/components/soc/esp32h2/include/soc/soc.h b/components/soc/esp32h2/include/soc/soc.h index 28063eb22df..ba22c6e7b81 100644 --- a/components/soc/esp32h2/include/soc/soc.h +++ b/components/soc/esp32h2/include/soc/soc.h @@ -156,9 +156,9 @@ */ #define SOC_IROM_LOW 0x42000000 -#define SOC_IROM_HIGH (SOC_IROM_LOW + (CONFIG_MMU_PAGE_SIZE<<7)) -#define SOC_DROM_LOW SOC_IROM_HIGH -#define SOC_DROM_HIGH (SOC_IROM_LOW + (CONFIG_MMU_PAGE_SIZE<<8)) // ESP32H2 MMU-TODO: IDF-6251 +#define SOC_IROM_HIGH (SOC_IROM_LOW + (CONFIG_MMU_PAGE_SIZE<<8)) +#define SOC_DROM_LOW SOC_IROM_LOW +#define SOC_DROM_HIGH SOC_IROM_HIGH #define SOC_IROM_MASK_LOW 0x40000000 #define SOC_IROM_MASK_HIGH 0x4001C400 #define SOC_DROM_MASK_LOW 0x4001C400 diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index b33453a3be8..c9ddaf27cd7 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -124,9 +124,11 @@ #define SOC_CPU_WATCHPOINTS_NUM 4 #define SOC_CPU_WATCHPOINT_SIZE 0x80000000 // bytes -// TODO: IDF-6370 (Copy from esp32c6, need check) /*-------------------------- MMU CAPS ----------------------------------------*/ -#define SOC_MMU_PAGE_SIZE_CONFIGURABLE (1) +#define SOC_MMU_PAGE_SIZE_CONFIGURABLE (1) +#define SOC_MMU_PERIPH_NUM (1U) +#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM (1U) +#define SOC_MMU_DI_VADDR_SHARED (1) /*!< D/I vaddr are shared */ // TODO: IDF-6285 (Copy from esp32c6, need check) /*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/ diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index a09386b6461..69649712f5d 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -415,6 +415,14 @@ config SOC_LEDC_GAMMA_FADE_RANGE_MAX int default 1 +config SOC_MMU_LINEAR_ADDRESS_REGION_NUM + int + default 1 + +config SOC_MMU_PERIPH_NUM + int + default 1 + config SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED bool default n diff --git a/components/soc/esp32h4/include/soc/ext_mem_defs.h b/components/soc/esp32h4/include/soc/ext_mem_defs.h index c7d8e2aa888..1c2eae3293c 100644 --- a/components/soc/esp32h4/include/soc/ext_mem_defs.h +++ b/components/soc/esp32h4/include/soc/ext_mem_defs.h @@ -69,9 +69,6 @@ extern "C" { #define CACHE_MAX_SYNC_NUM 0x400000 #define CACHE_MAX_LOCK_NUM 0x8000 -#define FLASH_MMU_TABLE ((volatile uint32_t*) DR_REG_MMU_TABLE) -#define FLASH_MMU_TABLE_SIZE (ICACHE_MMU_SIZE/sizeof(uint32_t)) - /** * MMU entry valid bit mask for mapping value. For an entry: * valid bit + value bits @@ -99,6 +96,45 @@ extern "C" { #define CACHE_MEMORY_IBANK0_ADDR 0x4037c000 +#define SOC_MMU_DBUS_VADDR_BASE 0x3C000000 +#define SOC_MMU_IBUS_VADDR_BASE 0x42000000 + +/*------------------------------------------------------------------------------ + * MMU Linear Address + *----------------------------------------------------------------------------*/ +/** + * - 64KB MMU page size: the last 0xFFFF, which is the offset + * - 128 MMU entries, needs 0x7F to hold it. + * + * Therefore, 0x7F,FFFF + */ +#define SOC_MMU_LINEAR_ADDR_MASK 0x7FFFFF + +/** + * - If high linear address isn't 0, this means MMU can recognize these addresses + * - If high linear address is 0, this means MMU linear address range is equal or smaller than vaddr range. + * Under this condition, we use the max linear space. + */ +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW (IRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (IRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_IRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW (DRAM0_CACHE_ADDRESS_LOW & SOC_MMU_LINEAR_ADDR_MASK) +#if ((DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) > 0) +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (DRAM0_CACHE_ADDRESS_HIGH & SOC_MMU_LINEAR_ADDR_MASK) +#else +#define SOC_MMU_DRAM0_LINEAR_ADDRESS_HIGH (SOC_MMU_LINEAR_ADDR_MASK + 1) +#endif + +/** + * I/D share the MMU linear address range + */ +_Static_assert(SOC_MMU_IRAM0_LINEAR_ADDRESS_LOW == SOC_MMU_DRAM0_LINEAR_ADDRESS_LOW, "IRAM0 and DRAM0 linear address should be same"); + + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 0f4d3b1ec3c..b80adba46a3 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -211,6 +211,10 @@ #define SOC_LEDC_SUPPORT_FADE_STOP (1) #define SOC_LEDC_GAMMA_FADE_RANGE_MAX (1U) // The target does not support gamma curve fading +/*-------------------------- MMU CAPS ----------------------------------------*/ +#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM (1U) +#define SOC_MMU_PERIPH_NUM (1U) + /*-------------------------- MPU CAPS ----------------------------------------*/ #define SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED 0 #define SOC_MPU_MIN_REGION_SIZE 0x20000000U diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index eb3d0124852..6c10d3f13d7 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -255,10 +255,6 @@ config SOC_BROWNOUT_RESET_SUPPORTED bool default y -config SOC_MMU_LINEAR_ADDRESS_REGION_NUM - int - default 6 - config SOC_CP_DMA_MAX_BUFFER_SIZE int default 4095 @@ -455,6 +451,14 @@ config SOC_LEDC_GAMMA_FADE_RANGE_MAX int default 1 +config SOC_MMU_LINEAR_ADDRESS_REGION_NUM + int + default 5 + +config SOC_MMU_PERIPH_NUM + int + default 1 + config SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED bool default n diff --git a/components/soc/esp32s2/include/soc/ext_mem_defs.h b/components/soc/esp32s2/include/soc/ext_mem_defs.h index b5554d503cb..a46b22584df 100644 --- a/components/soc/esp32s2/include/soc/ext_mem_defs.h +++ b/components/soc/esp32s2/include/soc/ext_mem_defs.h @@ -98,9 +98,6 @@ extern "C" { #define MMU_ACCESS_FLASH BIT(15) #define MMU_ACCESS_SPIRAM BIT(16) -#define FLASH_MMU_TABLE ((volatile uint32_t*) DR_REG_MMU_TABLE) -#define FLASH_MMU_TABLE_SIZE (ICACHE_MMU_SIZE/sizeof(uint32_t)) - /** * MMU entry valid bit mask for mapping value. For an entry: * valid bit + value bits diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index e86100526fb..24cbf21252c 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -119,9 +119,6 @@ /*-------------------------- BROWNOUT CAPS -----------------------------------*/ #define SOC_BROWNOUT_RESET_SUPPORTED 1 -/*-------------------------- CACHE/MMU CAPS ----------------------------------*/ -#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM 6 - /*-------------------------- CP-DMA CAPS -------------------------------------*/ #define SOC_CP_DMA_MAX_BUFFER_SIZE (4095) /*!< Maximum size of the buffer that can be attached to descriptor */ @@ -211,6 +208,10 @@ #define SOC_LEDC_SUPPORT_FADE_STOP (1) #define SOC_LEDC_GAMMA_FADE_RANGE_MAX (1U) // The target does not support gamma curve fading +/*-------------------------- MMU CAPS ----------------------------------------*/ +#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM 5 +#define SOC_MMU_PERIPH_NUM (1U) + /*-------------------------- MPU CAPS ----------------------------------------*/ //TODO: correct the caller and remove unsupported lines #define SOC_MPU_CONFIGURABLE_REGIONS_SUPPORTED 0 diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index cfcc25dfb65..f9b143ec225 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -299,10 +299,6 @@ config SOC_BROWNOUT_RESET_SUPPORTED bool default y -config SOC_MMU_LINEAR_ADDRESS_REGION_NUM - int - default 1 - config SOC_CPU_CORES_NUM int default 2 @@ -539,6 +535,14 @@ config SOC_MCPWM_SWSYNC_CAN_PROPAGATE bool default y +config SOC_MMU_LINEAR_ADDRESS_REGION_NUM + int + default 1 + +config SOC_MMU_PERIPH_NUM + int + default 1 + config SOC_PCNT_GROUPS int default 1 diff --git a/components/soc/esp32s3/include/soc/ext_mem_defs.h b/components/soc/esp32s3/include/soc/ext_mem_defs.h index b37f7fbfc3f..9d556940077 100644 --- a/components/soc/esp32s3/include/soc/ext_mem_defs.h +++ b/components/soc/esp32s3/include/soc/ext_mem_defs.h @@ -69,9 +69,6 @@ extern "C" { #define CACHE_MAX_SYNC_NUM 0x400000 #define CACHE_MAX_LOCK_NUM 0x8000 -#define FLASH_MMU_TABLE ((volatile uint32_t*) DR_REG_MMU_TABLE) -#define FLASH_MMU_TABLE_SIZE (ICACHE_MMU_SIZE/sizeof(uint32_t)) - /** * MMU entry valid bit mask for mapping value. For an entry: * valid bit + value bits diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index f593592a1cd..4bc7a63e99e 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -116,9 +116,6 @@ /*-------------------------- BROWNOUT CAPS -----------------------------------*/ #define SOC_BROWNOUT_RESET_SUPPORTED 1 -/*-------------------------- CACHE/MMU CAPS ----------------------------------*/ -#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM (1U) - /*-------------------------- CPU CAPS ----------------------------------------*/ #define SOC_CPU_CORES_NUM 2 #define SOC_CPU_INTR_NUM 32 @@ -221,6 +218,10 @@ #define SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP (3) ///< The number of GPIO synchros that each group has #define SOC_MCPWM_SWSYNC_CAN_PROPAGATE (1) ///< Software sync event can be routed to its output +/*-------------------------- MMU CAPS ----------------------------------------*/ +#define SOC_MMU_LINEAR_ADDRESS_REGION_NUM (1U) +#define SOC_MMU_PERIPH_NUM (1U) + /*-------------------------- MPU CAPS ----------------------------------------*/ #include "mpu_caps.h" diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index c3b32e2bed7..edd09e5fdad 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -45,7 +45,7 @@ else() "spi_flash_os_func_noos.c") list(APPEND srcs ${cache_srcs}) - set(priv_requires bootloader_support app_update soc driver) + set(priv_requires bootloader_support app_update soc driver esp_mm) endif() idf_component_register(SRCS "${srcs}" diff --git a/components/spi_flash/flash_mmap.c b/components/spi_flash/flash_mmap.c index 505f90ac814..b8860f9e04b 100644 --- a/components/spi_flash/flash_mmap.c +++ b/components/spi_flash/flash_mmap.c @@ -8,30 +8,30 @@ #include #include #include - #include -#include -#include -#include "soc/mmu.h" #include "sdkconfig.h" #include "esp_attr.h" -#include "esp_memory_utils.h" -#include "spi_flash_mmap.h" -#include "esp_flash_encrypt.h" #include "esp_log.h" -#include "esp_private/cache_utils.h" #include "hal/mmu_ll.h" -#include "esp_rom_spiflash.h" +#include "soc/mmu.h" + +#include "esp_private/esp_mmu_map_private.h" +#include "esp_mmu_map.h" +#if CONFIG_SPIRAM +#include "esp_private/esp_psram_extram.h" +#include "esp_private/mmu_psram_flash.h" +#endif + +#include "esp_private/cache_utils.h" +#include "spi_flash_mmap.h" + #if CONFIG_IDF_TARGET_ESP32 -#include "soc/dport_reg.h" #include "esp32/rom/cache.h" #elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/cache.h" -#include "soc/extmem_reg.h" #elif CONFIG_IDF_TARGET_ESP32S3 #include "esp32s3/rom/cache.h" -#include "soc/extmem_reg.h" #elif CONFIG_IDF_TARGET_ESP32C3 #include "esp32c3/rom/cache.h" #elif CONFIG_IDF_TARGET_ESP32H4 @@ -44,21 +44,6 @@ #include "esp32h2/rom/cache.h" #endif -#if CONFIG_SPIRAM -#include "esp_private/esp_psram_extram.h" -#include "esp_private/mmu_psram_flash.h" -#endif - -#ifndef NDEBUG -// Enable built-in checks in queue.h in debug builds -#define INVARIANTS -#endif -#include "sys/queue.h" - -#define IROM0_PAGES_NUM (SOC_MMU_IROM0_PAGES_END - SOC_MMU_IROM0_PAGES_START) -#define DROM0_PAGES_NUM (SOC_MMU_DROM0_PAGES_END - SOC_MMU_DROM0_PAGES_START) -#define PAGES_LIMIT ((SOC_MMU_IROM0_PAGES_END > SOC_MMU_DROM0_PAGES_END) ? SOC_MMU_IROM0_PAGES_END:SOC_MMU_DROM0_PAGES_END) -#define INVALID_PHY_PAGE(page_size) ((page_size) - 1) #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS extern int _instruction_reserved_start; @@ -72,387 +57,292 @@ extern int _rodata_reserved_end; #if !CONFIG_SPI_FLASH_ROM_IMPL -typedef struct mmap_entry_{ - uint32_t handle; - int page; - int count; - LIST_ENTRY(mmap_entry_) entries; -} mmap_entry_t; - -static LIST_HEAD(mmap_entries_head, mmap_entry_) s_mmap_entries_head = - LIST_HEAD_INITIALIZER(s_mmap_entries_head); -static uint8_t s_mmap_page_refcnt[SOC_MMU_REGIONS_COUNT * SOC_MMU_PAGES_PER_REGION] = {0}; -static uint32_t s_mmap_last_handle = 0; +typedef struct mmap_block_t { + uint32_t *vaddr_list; + int list_num; +} mmap_block_t; -static void IRAM_ATTR spi_flash_mmap_init(void) +esp_err_t spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t memory, + const void** out_ptr, spi_flash_mmap_handle_t* out_handle) { - if (s_mmap_page_refcnt[SOC_MMU_DROM0_PAGES_START] != 0) { - return; /* mmap data already initialised */ - } - for (int i = 0; i < SOC_MMU_REGIONS_COUNT * SOC_MMU_PAGES_PER_REGION; ++i) { - uint32_t entry_pro = mmu_ll_read_entry(MMU_TABLE_CORE0, i); -#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32 - uint32_t entry_app = mmu_ll_read_entry(MMU_TABLE_CORE1, i); - - if (entry_pro != entry_app) { - // clean up entries used by boot loader - mmu_ll_set_entry_invalid(MMU_TABLE_CORE0, i); - } -#endif - bool entry_pro_invalid = mmu_ll_get_entry_is_invalid(MMU_TABLE_CORE0, i); - if (!entry_pro_invalid && (i == SOC_MMU_DROM0_PAGES_START || i == SOC_MMU_PRO_IRAM0_FIRST_USABLE_PAGE || entry_pro != 0)) { - s_mmap_page_refcnt[i] = 1; - } else { - mmu_ll_set_entry_invalid(MMU_TABLE_CORE0, i); -#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32 - mmu_ll_set_entry_invalid(MMU_TABLE_CORE1, i); -#endif - } + esp_err_t ret = ESP_FAIL; + mmu_mem_caps_t caps = 0; + void *ptr = NULL; + mmap_block_t *block = NULL; + uint32_t *vaddr_list = NULL; + + block = heap_caps_calloc(1, sizeof(mmap_block_t), MALLOC_CAP_INTERNAL); + if (!block) { + ret = ESP_ERR_NO_MEM; + goto err; } -} -static void IRAM_ATTR get_mmu_region(spi_flash_mmap_memory_t memory, int* out_begin, int* out_size,uint32_t* region_addr) -{ - if (memory == SPI_FLASH_MMAP_DATA) { - // Vaddr0 - *out_begin = SOC_MMU_DROM0_PAGES_START; - *out_size = DROM0_PAGES_NUM; - *region_addr = SOC_MMU_VADDR0_START_ADDR; - } else { - // only part of VAddr1 is usable, so adjust for that - *out_begin = SOC_MMU_PRO_IRAM0_FIRST_USABLE_PAGE; - *out_size = SOC_MMU_IROM0_PAGES_END - *out_begin; - *region_addr = SOC_MMU_VADDR1_FIRST_USABLE_ADDR; + vaddr_list = heap_caps_calloc(1, 1 * sizeof(uint32_t), MALLOC_CAP_INTERNAL); + if (!vaddr_list) { + ret = ESP_ERR_NO_MEM; + goto err; } -} -esp_err_t IRAM_ATTR spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t memory, - const void** out_ptr, spi_flash_mmap_handle_t* out_handle) -{ - esp_err_t ret; - if (src_addr & INVALID_PHY_PAGE(CONFIG_MMU_PAGE_SIZE)) { - return ESP_ERR_INVALID_ARG; + block->vaddr_list = vaddr_list; + + if (memory == SPI_FLASH_MMAP_INST) { + caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_32BIT; + } else { + caps = MMU_MEM_CAP_READ | MMU_MEM_CAP_8BIT; } - if ((src_addr + size) > g_rom_flashchip.chip_size) { - return ESP_ERR_INVALID_ARG; + ret = esp_mmu_map(src_addr, size, caps, MMU_TARGET_FLASH0, &ptr); + if (ret == ESP_OK) { + vaddr_list[0] = (uint32_t)ptr; + block->list_num = 1; + + } else if (ret == ESP_ERR_INVALID_STATE) { + /** + * paddr region is mapped already, + * to keep `flash_mmap.c` original behaviour, we consider this as a valid behaviour. + * Set `list_num` to 0 so we don't need to call `esp_mmu_unmap` to this one, as `esp_mmu_map` + * doesn't really create a new handle. + */ + block->list_num = 0; + } else { + goto err; } - // region which should be mapped - int phys_page = src_addr / SPI_FLASH_MMU_PAGE_SIZE; - int page_count = (size + SPI_FLASH_MMU_PAGE_SIZE - 1) / SPI_FLASH_MMU_PAGE_SIZE; - // prepare a linear pages array to feed into spi_flash_mmap_pages - int *pages = heap_caps_malloc(sizeof(int)*page_count, MALLOC_CAP_INTERNAL); - if (pages == NULL) { - return ESP_ERR_NO_MEM; + + *out_ptr = ptr; + *out_handle = (uint32_t)block; + + return ESP_OK; + +err: + if (vaddr_list) { + free(vaddr_list); } - for (int i = 0; i < page_count; i++) { - pages[i] = (phys_page+i); + if (block) { + free(block); } - ret = spi_flash_mmap_pages(pages, page_count, memory, out_ptr, out_handle); - free(pages); return ret; } -esp_err_t IRAM_ATTR spi_flash_mmap_pages(const int *pages, size_t page_count, spi_flash_mmap_memory_t memory, - const void** out_ptr, spi_flash_mmap_handle_t* out_handle) + +static int s_find_non_contiguous_block_nums(const int *pages, int page_count) { - esp_err_t ret; - const void* temp_ptr = *out_ptr = NULL; - spi_flash_mmap_handle_t temp_handle = *out_handle = (spi_flash_mmap_handle_t)NULL; - bool need_flush = false; - if (!page_count) { - return ESP_ERR_INVALID_ARG; - } - if (!esp_ptr_internal(pages)) { - return ESP_ERR_INVALID_ARG; - } - for (int i = 0; i < page_count; i++) { - if (pages[i] < 0 || pages[i]*SPI_FLASH_MMU_PAGE_SIZE >= g_rom_flashchip.chip_size) { - return ESP_ERR_INVALID_ARG; + int nums = 1; + int last_end = pages[0] + 1; + + for (int i = 1; i < page_count; i++) { + if (pages[i] != last_end) { + nums++; } + last_end = pages[i] + 1; } - mmap_entry_t* new_entry = (mmap_entry_t*) heap_caps_malloc(sizeof(mmap_entry_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); - if (new_entry == 0) { - return ESP_ERR_NO_MEM; + return nums; +} + +static void s_merge_contiguous_pages(const int *pages, uint32_t page_count, int block_nums, int (*out_blocks)[2]) +{ + uint32_t last_end = pages[0] + 1; + int new_array_id = 0; + out_blocks[new_array_id][0] = pages[0]; + out_blocks[new_array_id][1] = 1; + + for (int i = 1; i < page_count; i++) { + + if (pages[i] != last_end) { + new_array_id += 1; + assert(new_array_id < block_nums); + out_blocks[new_array_id][0] = pages[i]; + out_blocks[new_array_id][1] = 1; + } else { + out_blocks[new_array_id][1] += 1; + } + + last_end = pages[i] + 1; } +} - spi_flash_disable_interrupts_caches_and_other_cpu(); - - spi_flash_mmap_init(); - // figure out the memory region where we should look for pages - int region_begin; // first page to check - int region_size; // number of pages to check - uint32_t region_addr; // base address of memory region - get_mmu_region(memory,®ion_begin,®ion_size,®ion_addr); - if (region_size < page_count) { - spi_flash_enable_interrupts_caches_and_other_cpu(); - return ESP_ERR_NO_MEM; +static void s_pages_to_bytes(int (*blocks)[2], int block_nums) +{ + for (int i = 0; i < block_nums; i++) { + blocks[i][0] = blocks[i][0] * CONFIG_MMU_PAGE_SIZE; + blocks[i][1] = blocks[i][1] * CONFIG_MMU_PAGE_SIZE; } - // The following part searches for a range of MMU entries which can be used. - // Algorithm is essentially naïve strstr algorithm, except that unused MMU - // entries are treated as wildcards. - int start; - // the " + 1" is a fix when loop the MMU table pages, because the last MMU page - // is valid as well if it have not been used - int end = region_begin + region_size - page_count + 1; - for (start = region_begin; start < end; ++start) { - int pageno = 0; - int pos; - for (pos = start; pos < start + page_count; ++pos, ++pageno) { - int table_val = (int) mmu_ll_read_entry(MMU_TABLE_CORE0, pos); - uint8_t refcnt = s_mmap_page_refcnt[pos]; - if (refcnt != 0 && table_val != SOC_MMU_PAGE_IN_FLASH(pages[pageno])) { - break; - } - } - // whole mapping range matched, bail out - if (pos - start == page_count) { - break; - } +} + +esp_err_t spi_flash_mmap_pages(const int *pages, size_t page_count, spi_flash_mmap_memory_t memory, + const void** out_ptr, spi_flash_mmap_handle_t* out_handle) +{ + esp_err_t ret = ESP_FAIL; + mmu_mem_caps_t caps = 0; + mmap_block_t *block = NULL; + uint32_t *vaddr_list = NULL; + int successful_cnt = 0; + + int block_num = s_find_non_contiguous_block_nums(pages, page_count); + int paddr_blocks[block_num][2]; + s_merge_contiguous_pages(pages, page_count, block_num, paddr_blocks); + s_pages_to_bytes(paddr_blocks, block_num); + + block = heap_caps_calloc(1, sizeof(mmap_block_t), MALLOC_CAP_INTERNAL); + if (!block) { + ret = ESP_ERR_NO_MEM; + goto err; } - // checked all the region(s) and haven't found anything? - if (start == end) { + + vaddr_list = heap_caps_calloc(1, block_num * sizeof(uint32_t), MALLOC_CAP_INTERNAL); + if (!vaddr_list) { ret = ESP_ERR_NO_MEM; - } else { - // set up mapping using pages - uint32_t pageno = 0; - for (int i = start; i != start + page_count; ++i, ++pageno) { - // sanity check: we won't reconfigure entries with non-zero reference count - uint32_t entry_pro = mmu_ll_read_entry(MMU_TABLE_CORE0, i); -#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32 - uint32_t entry_app = mmu_ll_read_entry(MMU_TABLE_CORE1, i); -#endif - assert(s_mmap_page_refcnt[i] == 0 || - (entry_pro == SOC_MMU_PAGE_IN_FLASH(pages[pageno]) -#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32 - && entry_app == SOC_MMU_PAGE_IN_FLASH(pages[pageno]) -#endif - )); - if (s_mmap_page_refcnt[i] == 0) { - if (entry_pro != SOC_MMU_PAGE_IN_FLASH(pages[pageno]) -#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32 - || entry_app != SOC_MMU_PAGE_IN_FLASH(pages[pageno]) -#endif - ) { - mmu_ll_write_entry(MMU_TABLE_CORE0, i, pages[pageno], 0); -#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32 - mmu_ll_write_entry(MMU_TABLE_CORE1, i, pages[pageno], 0); -#endif + goto err; + } -#if !CONFIG_IDF_TARGET_ESP32 - Cache_Invalidate_Addr(region_addr + (i - region_begin) * SPI_FLASH_MMU_PAGE_SIZE, SPI_FLASH_MMU_PAGE_SIZE); -#endif - need_flush = true; - } - } - ++s_mmap_page_refcnt[i]; + if (memory == SPI_FLASH_MMAP_INST) { + caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_32BIT; + } else { + caps = MMU_MEM_CAP_READ | MMU_MEM_CAP_8BIT; + } + for (int i = 0; i < block_num; i++) { + void *ptr = NULL; + ret = esp_mmu_map(paddr_blocks[i][0], paddr_blocks[i][1], caps, MMU_TARGET_FLASH0, &ptr); + if (ret == ESP_OK) { + vaddr_list[i] = (uint32_t)ptr; + successful_cnt++; + } else { + /** + * A note for `ret == ESP_ERR_INVALID_STATE`: + * If one of the `*pages` are mapped already, this means we can't find a + * consecutive vaddr block for these `*pages` + */ + goto err; } - LIST_INSERT_HEAD(&s_mmap_entries_head, new_entry, entries); - new_entry->page = start; - new_entry->count = page_count; - new_entry->handle = ++s_mmap_last_handle; - temp_handle = new_entry->handle; - temp_ptr = (void*) (region_addr + (start - region_begin) * SPI_FLASH_MMU_PAGE_SIZE); - ret = ESP_OK; + vaddr_list[i] = (uint32_t)ptr; } - /* This is a temporary fix for an issue where some - cache reads may see stale data. + block->vaddr_list = vaddr_list; + block->list_num = successful_cnt; - Working on a long term fix that doesn't require invalidating - entire cache. - */ - if (need_flush) { -#if CONFIG_IDF_TARGET_ESP32 -#if CONFIG_SPIRAM - esp_psram_extram_writeback_cache(); -#endif // CONFIG_SPIRAM - Cache_Flush(0); -#if !CONFIG_FREERTOS_UNICORE - Cache_Flush(1); -#endif // !CONFIG_FREERTOS_UNICORE -#endif // CONFIG_IDF_TARGET_ESP32 - } + /** + * We get a contiguous vaddr block, but may contain multiple esp_mmu handles. + * The first handle vaddr is the start address of this contiguous vaddr block. + */ + *out_ptr = (void *)vaddr_list[0]; + *out_handle = (uint32_t)block; - spi_flash_enable_interrupts_caches_and_other_cpu(); - if (temp_ptr == NULL) { - free(new_entry); + return ESP_OK; + +err: + for (int i = 0; i < successful_cnt; i++) { + esp_mmu_unmap((void *)vaddr_list[i]); + } + if (vaddr_list) { + free(vaddr_list); + } + if (block) { + free(block); } - *out_ptr = temp_ptr; - *out_handle = temp_handle; return ret; } -void IRAM_ATTR spi_flash_munmap(spi_flash_mmap_handle_t handle) + +void spi_flash_munmap(spi_flash_mmap_handle_t handle) { - spi_flash_disable_interrupts_caches_and_other_cpu(); - mmap_entry_t* it; - // look for handle in linked list - for (it = LIST_FIRST(&s_mmap_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { - if (it->handle == handle) { - // for each page, decrement reference counter - // if reference count is zero, disable MMU table entry to - // facilitate debugging of use-after-free conditions - for (int i = it->page; i < it->page + it->count; ++i) { - assert(s_mmap_page_refcnt[i] > 0); - if (--s_mmap_page_refcnt[i] == 0) { - mmu_ll_set_entry_invalid(MMU_TABLE_CORE0, i); -#if !CONFIG_FREERTOS_UNICORE && CONFIG_IDF_TARGET_ESP32 - mmu_ll_set_entry_invalid(MMU_TABLE_CORE1, i); -#endif - } - } - LIST_REMOVE(it, entries); - break; + esp_err_t ret = ESP_FAIL; + mmap_block_t *block = (void *)handle; + + for (int i = 0; i < block->list_num; i++) { + ret = esp_mmu_unmap((void *)block->vaddr_list[i]); + if (ret == ESP_ERR_NOT_FOUND) { + assert(0 && "invalid handle, or handle already unmapped"); } } - spi_flash_enable_interrupts_caches_and_other_cpu(); - if (it == NULL) { - assert(0 && "invalid handle, or handle already unmapped"); - } - free(it); -} -static void IRAM_ATTR NOINLINE_ATTR spi_flash_protected_mmap_init(void) -{ - spi_flash_disable_interrupts_caches_and_other_cpu(); - spi_flash_mmap_init(); - spi_flash_enable_interrupts_caches_and_other_cpu(); + free(block->vaddr_list); + free(block); } -static uint32_t IRAM_ATTR NOINLINE_ATTR spi_flash_protected_read_mmu_entry(int index) -{ - uint32_t value; - spi_flash_disable_interrupts_caches_and_other_cpu(); - value = mmu_ll_read_entry(MMU_TABLE_CORE0, index); - spi_flash_enable_interrupts_caches_and_other_cpu(); - return value; -} void spi_flash_mmap_dump(void) { - spi_flash_protected_mmap_init(); - - mmap_entry_t* it; - for (it = LIST_FIRST(&s_mmap_entries_head); it != NULL; it = LIST_NEXT(it, entries)) { - printf("handle=%d page=%d count=%d\n", it->handle, it->page, it->count); - } - for (int i = 0; i < SOC_MMU_REGIONS_COUNT * SOC_MMU_PAGES_PER_REGION; ++i) { - if (s_mmap_page_refcnt[i] != 0) { - uint32_t paddr = spi_flash_protected_read_mmu_entry(i); - printf("page %d: refcnt=%d paddr=%d\n", i, (int) s_mmap_page_refcnt[i], paddr); - } - } + esp_mmu_map_dump_mapped_blocks(stdout); } -uint32_t IRAM_ATTR spi_flash_mmap_get_free_pages(spi_flash_mmap_memory_t memory) + +uint32_t spi_flash_mmap_get_free_pages(spi_flash_mmap_memory_t memory) { - spi_flash_disable_interrupts_caches_and_other_cpu(); - spi_flash_mmap_init(); - int count = 0; - int region_begin; // first page to check - int region_size; // number of pages to check - uint32_t region_addr; // base address of memory region - get_mmu_region(memory,®ion_begin,®ion_size,®ion_addr); - for (int i = region_begin; i < region_begin + region_size; ++i) { - bool entry_is_invalid = mmu_ll_get_entry_is_invalid(MMU_TABLE_CORE0, i); - if (s_mmap_page_refcnt[i] == 0 && entry_is_invalid) { - count++; - } + mmu_mem_caps_t caps = 0; + if (memory == SPI_FLASH_MMAP_INST) { + caps = MMU_MEM_CAP_EXEC | MMU_MEM_CAP_32BIT; + } else { + caps = MMU_MEM_CAP_READ | MMU_MEM_CAP_8BIT; } - spi_flash_enable_interrupts_caches_and_other_cpu(); - return count; + + size_t len = 0; + esp_mmu_map_get_max_consecutive_free_block_size(caps, MMU_TARGET_FLASH0, &len); + return len / CONFIG_MMU_PAGE_SIZE; } + size_t spi_flash_cache2phys(const void *cached) { - intptr_t c = (intptr_t)cached; - size_t cache_page; - int offset = 0; - if (c >= SOC_MMU_VADDR1_START_ADDR && c < SOC_MMU_VADDR1_FIRST_USABLE_ADDR) { - /* IRAM address, doesn't map to flash */ + if (cached == NULL) { return SPI_FLASH_CACHE2PHYS_FAIL; } - if (c < SOC_MMU_VADDR1_FIRST_USABLE_ADDR) { - /* expect cache is in DROM */ - cache_page = (c - SOC_MMU_VADDR0_START_ADDR) / SPI_FLASH_MMU_PAGE_SIZE + SOC_MMU_DROM0_PAGES_START; + + esp_err_t ret = ESP_FAIL; + uint32_t paddr = 0; + mmu_target_t target = 0; + + ret = esp_mmu_vaddr_to_paddr((void *)cached, &paddr, &target); + if (ret != ESP_OK) { + return SPI_FLASH_CACHE2PHYS_FAIL; + } + + int offset = 0; #if CONFIG_SPIRAM_RODATA - if (c >= (uint32_t)&_rodata_reserved_start && c <= (uint32_t)&_rodata_reserved_end) { - offset = rodata_flash2spiram_offset(); - } + if ((uint32_t)cached >= (uint32_t)&_rodata_reserved_start && (uint32_t)cached <= (uint32_t)&_rodata_reserved_end) { + offset = rodata_flash2spiram_offset(); + } #endif - } else { - /* expect cache is in IROM */ - cache_page = (c - SOC_MMU_VADDR1_START_ADDR) / SPI_FLASH_MMU_PAGE_SIZE + SOC_MMU_IROM0_PAGES_START; #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS - if (c >= (uint32_t)&_instruction_reserved_start && c <= (uint32_t)&_instruction_reserved_end) { - offset = instruction_flash2spiram_offset(); - } -#endif + if ((uint32_t)cached >= (uint32_t)&_instruction_reserved_start && (uint32_t)cached <= (uint32_t)&_instruction_reserved_end) { + offset = instruction_flash2spiram_offset(); } +#endif - if (cache_page >= PAGES_LIMIT) { - /* cached address was not in IROM or DROM */ - return SPI_FLASH_CACHE2PHYS_FAIL; - } - uint32_t phys_page = spi_flash_protected_read_mmu_entry(cache_page); - bool entry_is_invalid = mmu_ll_get_entry_is_invalid(MMU_TABLE_CORE0, cache_page); - if (entry_is_invalid) { - /* page is not mapped */ - return SPI_FLASH_CACHE2PHYS_FAIL; - } - uint32_t phys_offs = ((phys_page & SOC_MMU_ADDR_MASK) + offset) * SPI_FLASH_MMU_PAGE_SIZE; - return phys_offs | (c & (SPI_FLASH_MMU_PAGE_SIZE-1)); + return paddr + offset * CONFIG_MMU_PAGE_SIZE; } -const void *IRAM_ATTR spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memory) + +const void * spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memory) { - uint32_t phys_page = phys_offs / SPI_FLASH_MMU_PAGE_SIZE; - int start, end, page_delta; - intptr_t base; - - if (memory == SPI_FLASH_MMAP_DATA) { - start = SOC_MMU_DROM0_PAGES_START; - end = SOC_MMU_DROM0_PAGES_END; - base = SOC_MMU_VADDR0_START_ADDR; - page_delta = SOC_MMU_DROM0_PAGES_START; - } else { - start = SOC_MMU_PRO_IRAM0_FIRST_USABLE_PAGE; - end = SOC_MMU_IROM0_PAGES_END; - base = SOC_MMU_VADDR1_START_ADDR; - page_delta = SOC_MMU_IROM0_PAGES_START; - } - spi_flash_disable_interrupts_caches_and_other_cpu(); - for (int i = start; i < end; i++) { - uint32_t mmu_value = mmu_ll_read_entry(MMU_TABLE_CORE0, i); + esp_err_t ret = ESP_FAIL; + void *ptr = NULL; + mmu_target_t target = MMU_TARGET_FLASH0; + + __attribute__((unused)) uint32_t phys_page = phys_offs / CONFIG_MMU_PAGE_SIZE; #if CONFIG_SPIRAM_FETCH_INSTRUCTIONS - if (phys_page >= instruction_flash_start_page_get() && phys_page <= instruction_flash_end_page_get()) { - if (mmu_value & MMU_ACCESS_SPIRAM) { - mmu_value += instruction_flash2spiram_offset(); - mmu_value = (mmu_value & SOC_MMU_ADDR_MASK) | MMU_ACCESS_FLASH; - } - } + if (phys_page >= instruction_flash_start_page_get() && phys_page <= instruction_flash_end_page_get()) { + target = MMU_TARGET_PSRAM0; + phys_offs -= instruction_flash2spiram_offset() * CONFIG_MMU_PAGE_SIZE; + } #endif + #if CONFIG_SPIRAM_RODATA - if (phys_page >= rodata_flash_start_page_get() && phys_page <= rodata_flash_start_page_get()) { - if (mmu_value & MMU_ACCESS_SPIRAM) { - mmu_value += rodata_flash2spiram_offset(); - mmu_value = (mmu_value & SOC_MMU_ADDR_MASK) | MMU_ACCESS_FLASH; - } - } + if (phys_page >= rodata_flash_start_page_get() && phys_page <= rodata_flash_start_page_get()) { + target = MMU_TARGET_PSRAM0; + phys_offs -= rodata_flash2spiram_offset() * CONFIG_MMU_PAGE_SIZE; + } #endif - if (mmu_value == SOC_MMU_PAGE_IN_FLASH(phys_page)) { - i -= page_delta; - intptr_t cache_page = base + (SPI_FLASH_MMU_PAGE_SIZE * i); - spi_flash_enable_interrupts_caches_and_other_cpu(); - return (const void *) (cache_page | (phys_offs & (SPI_FLASH_MMU_PAGE_SIZE-1))); - } + + mmu_vaddr_t type = (memory == SPI_FLASH_MMAP_DATA) ? MMU_VADDR_DATA : MMU_VADDR_INSTRUCTION; + ret = esp_mmu_paddr_to_vaddr(phys_offs, target, type, &ptr); + if (ret == ESP_ERR_NOT_FOUND) { + return NULL; } - spi_flash_enable_interrupts_caches_and_other_cpu(); - return NULL; + assert(ret == ESP_OK); + return (const void *)ptr; } + static bool IRAM_ATTR is_page_mapped_in_cache(uint32_t phys_page, const void **out_ptr) { int start[2], end[2]; diff --git a/components/spi_flash/include/spi_flash_mmap.h b/components/spi_flash/include/spi_flash_mmap.h index 057b0d76c5f..32e4ead2d3c 100644 --- a/components/spi_flash/include/spi_flash_mmap.h +++ b/components/spi_flash/include/spi_flash_mmap.h @@ -34,8 +34,8 @@ extern "C" { * @brief Enumeration which specifies memory space requested in an mmap call */ typedef enum { - SPI_FLASH_MMAP_DATA, /**< map to data memory (Vaddr0), allows byte-aligned access, 4 MB total */ - SPI_FLASH_MMAP_INST, /**< map to instruction memory (Vaddr1-3), allows only 4-byte-aligned access, 11 MB total */ + SPI_FLASH_MMAP_DATA, /**< map to data memory, allows byte-aligned access*/ + SPI_FLASH_MMAP_INST, /**< map to instruction memory, allows only 4-byte-aligned access*/ } spi_flash_mmap_memory_t; /** diff --git a/components/spi_flash/test_apps/esp_flash/main/test_app_main.c b/components/spi_flash/test_apps/esp_flash/main/test_app_main.c index 45e15bcca0d..3f6f58e6015 100644 --- a/components/spi_flash/test_apps/esp_flash/main/test_app_main.c +++ b/components/spi_flash/test_apps/esp_flash/main/test_app_main.c @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" // Some resources are lazy allocated in flash encryption, the threadhold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (-300) +#define TEST_MEMORY_LEAK_THRESHOLD (400) static size_t before_free_8bit; static size_t before_free_32bit; diff --git a/components/spi_flash/test_apps/flash_encryption/main/test_app_main.c b/components/spi_flash/test_apps/flash_encryption/main/test_app_main.c index 928235d659e..9d62df53034 100644 --- a/components/spi_flash/test_apps/flash_encryption/main/test_app_main.c +++ b/components/spi_flash/test_apps/flash_encryption/main/test_app_main.c @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" // Some resources are lazy allocated in flash encryption, the threadhold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (-300) +#define TEST_MEMORY_LEAK_THRESHOLD (-400) static size_t before_free_8bit; static size_t before_free_32bit; @@ -37,21 +37,18 @@ void tearDown(void) void app_main(void) { - // ####### ####### - // # # ## #### # # # #### # # ##### # # ##### ##### # #### # # - // # # # # # # # # # # ## # # # # # # # # # # # ## # - // ##### # # # #### ###### ##### # # # # # # # # # # # # # # # # - // # # ###### # # # # # # # # ##### # ##### # # # # # # # - // # # # # # # # # # # # # ## # # # # # # # # # ## - // # ###### # # #### # # ####### #### # # # # # # # # #### # # - - printf(" ####### ####### \n"); - printf("# # ## #### # # # #### # # ##### # # ##### ##### # #### # #\n"); - printf("# # # # # # # # # # ## # # # # # # # # # # # ## #\n"); - printf("##### # # # #### ###### ##### # # # # # # # # # # # # # # # #\n"); - printf("# # ###### # # # # # # # # ##### # ##### # # # # # # #\n"); - printf("# # # # # # # # # # # # ## # # # # # # # # # ##\n"); - printf("# ###### # # #### # # ####### #### # # # # # # # # #### # #\n"); + + // ________ ___ _____ __ __ _______ ______________ ______ ______________ _ __ + // / ____/ / / | / ___// / / / / ____/ | / / ____/ __ \ \/ / __ \/_ __/ _/ __ \/ | / / + // / /_ / / / /| | \__ \/ /_/ / / __/ / |/ / / / /_/ /\ / /_/ / / / / // / / / |/ / + // / __/ / /___/ ___ |___/ / __ / / /___/ /| / /___/ _, _/ / / ____/ / / _/ // /_/ / /| / + // /_/ /_____/_/ |_/____/_/ /_/ /_____/_/ |_/\____/_/ |_| /_/_/ /_/ /___/\____/_/ |_/ + + printf(" ________ ___ _____ __ __ _______ ______________ ______ ______________ _ __ \n"); + printf(" / ____/ / / | / ___// / / / / ____/ | / / ____/ __ \\ \\/ / __ \\/_ __/ _/ __ \\/ | / / \n"); + printf(" / /_ / / / /| | \\__ \\/ /_/ / / __/ / |/ / / / /_/ /\\ / /_/ / / / / // / / / |/ / \n"); + printf(" / __/ / /___/ ___ |___/ / __ / / /___/ /| / /___/ _, _/ / / ____/ / / _/ // /_/ / /| / \n"); + printf("/_/ /_____/_/ |_/____/_/ /_/ /_____/_/ |_/\\____/_/ |_| /_/_/ /_/ /___/\\____/_/ |_/ \n"); unity_run_menu(); } diff --git a/components/spi_flash/test_apps/flash_mmap/CMakeLists.txt b/components/spi_flash/test_apps/flash_mmap/CMakeLists.txt index 64369167525..0bd6bf58022 100644 --- a/components/spi_flash/test_apps/flash_mmap/CMakeLists.txt +++ b/components/spi_flash/test_apps/flash_mmap/CMakeLists.txt @@ -4,4 +4,4 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components") include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(test_mmap) +project(test_flash_mmap) diff --git a/components/spi_flash/test_apps/flash_mmap/main/CMakeLists.txt b/components/spi_flash/test_apps/flash_mmap/main/CMakeLists.txt index 38ba2ec4a72..c75f516f7c4 100644 --- a/components/spi_flash/test_apps/flash_mmap/main/CMakeLists.txt +++ b/components/spi_flash/test_apps/flash_mmap/main/CMakeLists.txt @@ -1,5 +1,5 @@ set(srcs "test_app_main.c" - "test_mmap.c") + "test_flash_mmap.c") # In order for the cases defined by `TEST_CASE` to be linked into the final elf, # the component can be registered as WHOLE_ARCHIVE diff --git a/components/spi_flash/test_apps/flash_mmap/main/test_app_main.c b/components/spi_flash/test_apps/flash_mmap/main/test_app_main.c index dcd6932b69d..635327c2032 100644 --- a/components/spi_flash/test_apps/flash_mmap/main/test_app_main.c +++ b/components/spi_flash/test_apps/flash_mmap/main/test_app_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" // Some resources are lazy allocated, the threadhold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (-600) +#define TEST_MEMORY_LEAK_THRESHOLD (600) static size_t before_free_8bit; static size_t before_free_32bit; diff --git a/components/spi_flash/test_apps/flash_mmap/main/test_mmap.c b/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c similarity index 93% rename from components/spi_flash/test_apps/flash_mmap/main/test_mmap.c rename to components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c index 4567a14f327..3849a61d337 100644 --- a/components/spi_flash/test_apps/flash_mmap/main/test_mmap.c +++ b/components/spi_flash/test_apps/flash_mmap/main/test_flash_mmap.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -101,6 +101,7 @@ static void setup_mmap_tests(void) } } + TEST_CASE("Can mmap into data address space", "[spi_flash][mmap]") { esp_err_t ret = ESP_FAIL; @@ -111,8 +112,6 @@ TEST_CASE("Can mmap into data address space", "[spi_flash][mmap]") TEST_ESP_OK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); printf("mmap_res: handle=%"PRIx32" ptr=%p\n", (uint32_t)handle1, ptr1); - spi_flash_mmap_dump(); - srand(0); const uint32_t *data = (const uint32_t *) ptr1; for (int block = 0; block < (end - start) / 0x10000; ++block) { @@ -130,9 +129,8 @@ TEST_CASE("Can mmap into data address space", "[spi_flash][mmap]") printf("mmap_res: handle=%"PRIx32" ptr=%p\n", (uint32_t)handle2, ptr2); TEST_ASSERT_EQUAL_HEX32(start - 0x10000, spi_flash_cache2phys(ptr2)); - TEST_ASSERT_EQUAL_PTR(ptr2, spi_flash_phys2cache(start - 0x10000, SPI_FLASH_MMAP_DATA)); - spi_flash_mmap_dump(); + TEST_ASSERT_EQUAL_PTR(ptr2, spi_flash_phys2cache(start - 0x10000, SPI_FLASH_MMAP_DATA)); printf("Mapping %"PRIx32" (+%x)\n", start, 0x10000); const void *ptr3; @@ -145,17 +143,13 @@ TEST_CASE("Can mmap into data address space", "[spi_flash][mmap]") TEST_ASSERT_EQUAL_PTR(ptr3, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA)); TEST_ASSERT_EQUAL_PTR((intptr_t)ptr3 + 0x4444, spi_flash_phys2cache(start + 0x4444, SPI_FLASH_MMAP_DATA)); - spi_flash_mmap_dump(); - printf("Unmapping handle1\n"); spi_flash_munmap(handle1); handle1 = 0; - spi_flash_mmap_dump(); printf("Unmapping handle2\n"); spi_flash_munmap(handle2); handle2 = 0; - spi_flash_mmap_dump(); printf("Unmapping handle3\n"); spi_flash_munmap(handle3); @@ -165,11 +159,6 @@ TEST_CASE("Can mmap into data address space", "[spi_flash][mmap]") TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA)); } -#if !(CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6) -/* On S3/C3/C2 the cache is programmatically split between Icache and dcache and with the default setup we dont leave a lot pages - available for additional mmaps into instruction space. Disabling this test for now since any hypothetical use case for this - is no longer supported "out of the box" -*/ TEST_CASE("Can mmap into instruction address space", "[spi_flash][mmap]") { setup_mmap_tests(); @@ -180,8 +169,6 @@ TEST_CASE("Can mmap into instruction address space", "[spi_flash][mmap]") TEST_ESP_OK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_INST, &ptr1, &handle1) ); printf("mmap_res: handle=%"PRIx32" ptr=%p\n", (uint32_t)handle1, ptr1); - spi_flash_mmap_dump(); - srand(0); const uint32_t *data = (const uint32_t *) ptr1; for (int block = 0; block < (end - start) / 0x10000; ++block) { @@ -200,8 +187,6 @@ TEST_CASE("Can mmap into instruction address space", "[spi_flash][mmap]") TEST_ASSERT_EQUAL_HEX32(start - 0x10000, spi_flash_cache2phys(ptr2)); TEST_ASSERT_EQUAL_PTR(ptr2, spi_flash_phys2cache(start - 0x10000, SPI_FLASH_MMAP_INST)); - spi_flash_mmap_dump(); - printf("Mapping %"PRIx32" (+%x)\n", start, 0x10000); spi_flash_mmap_handle_t handle3; const void *ptr3; @@ -211,20 +196,15 @@ TEST_CASE("Can mmap into instruction address space", "[spi_flash][mmap]") TEST_ASSERT_EQUAL_HEX32(start, spi_flash_cache2phys(ptr3)); TEST_ASSERT_EQUAL_PTR(ptr3, spi_flash_phys2cache(start, SPI_FLASH_MMAP_INST)); - spi_flash_mmap_dump(); - printf("Unmapping handle1\n"); spi_flash_munmap(handle1); - spi_flash_mmap_dump(); printf("Unmapping handle2\n"); spi_flash_munmap(handle2); - spi_flash_mmap_dump(); printf("Unmapping handle3\n"); spi_flash_munmap(handle3); } -#endif // #if !CONFIG_IDF_TARGET_ESP32C2 TEST_CASE("Can mmap unordered pages into contiguous memory", "[spi_flash][mmap]") { @@ -251,7 +231,6 @@ TEST_CASE("Can mmap unordered pages into contiguous memory", "[spi_flash][mmap]" TEST_ESP_OK( spi_flash_mmap_pages(pages, nopages, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); printf("mmap_res: handle=%"PRIx32" ptr=%p\n", (uint32_t)handle1, ptr1); - spi_flash_mmap_dump(); #if (CONFIG_MMU_PAGE_SIZE == 0x10000) uint32_t words_per_sector = 1024; #elif (CONFIG_MMU_PAGE_SIZE == 0x8000) @@ -335,8 +314,6 @@ TEST_CASE("flash_mmap can mmap after get enough free MMU pages", "[spi_flash][mm TEST_ESP_OK( spi_flash_mmap(start, end - start, SPI_FLASH_MMAP_DATA, &ptr1, &handle1) ); printf("mmap_res: handle=%"PRIx32" ptr=%p\n", (uint32_t)handle1, ptr1); - spi_flash_mmap_dump(); - srand(0); const uint32_t *data = (const uint32_t *) ptr1; for (int block = 0; block < (end - start) / 0x10000; ++block) { @@ -359,18 +336,13 @@ TEST_CASE("flash_mmap can mmap after get enough free MMU pages", "[spi_flash][mm TEST_ESP_OK( spi_flash_mmap(0, free_pages * SPI_FLASH_MMU_PAGE_SIZE, SPI_FLASH_MMAP_DATA, &ptr2, &handle2) ); printf("mmap_res: handle=%"PRIx32" ptr=%p\n", (uint32_t)handle2, ptr2); - spi_flash_mmap_dump(); - - printf("Unmapping handle1\n"); spi_flash_munmap(handle1); handle1 = 0; - spi_flash_mmap_dump(); printf("Unmapping handle2\n"); spi_flash_munmap(handle2); handle2 = 0; - spi_flash_mmap_dump(); TEST_ASSERT_EQUAL_PTR(NULL, spi_flash_phys2cache(start, SPI_FLASH_MMAP_DATA)); } @@ -394,11 +366,6 @@ TEST_CASE("phys2cache/cache2phys basic checks", "[spi_flash][mmap]") spi_flash_read_maybe_encrypted(phys, buf, sizeof(buf)); TEST_ASSERT_EQUAL_HEX32_ARRAY((void *)esp_partition_find, buf, sizeof(buf) / sizeof(uint32_t)); - /* spi_flash_mmap is in IRAM */ - printf("%p\n", spi_flash_mmap); - TEST_ASSERT_EQUAL_HEX32(SPI_FLASH_CACHE2PHYS_FAIL, - spi_flash_cache2phys(spi_flash_mmap)); - /* 'constant_data' should be in DROM */ phys = spi_flash_cache2phys(&constant_data); TEST_ASSERT_NOT_EQUAL(SPI_FLASH_CACHE2PHYS_FAIL, phys); diff --git a/components/spi_flash/test_apps/flash_mmap/pytest_mmap.py b/components/spi_flash/test_apps/flash_mmap/pytest_flash_mmap.py similarity index 86% rename from components/spi_flash/test_apps/flash_mmap/pytest_mmap.py rename to components/spi_flash/test_apps/flash_mmap/pytest_flash_mmap.py index 7e72f45cc7b..8695e2841b3 100644 --- a/components/spi_flash/test_apps/flash_mmap/pytest_mmap.py +++ b/components/spi_flash/test_apps/flash_mmap/pytest_flash_mmap.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import pytest diff --git a/examples/openthread/ot_br/partitions.csv b/examples/openthread/ot_br/partitions.csv index d18753121df..a484b990107 100644 --- a/examples/openthread/ot_br/partitions.csv +++ b/examples/openthread/ot_br/partitions.csv @@ -2,5 +2,5 @@ # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap nvs, data, nvs, 0x9000, 0x6000, phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 1500K, +factory, app, factory, 0x10000, 1600K, ot_storage, data, 0x3a, , 0x2000, diff --git a/tools/test_apps/system/g0_components/CMakeLists.txt b/tools/test_apps/system/g0_components/CMakeLists.txt index 45ba143eaf5..5b71435e8d4 100644 --- a/tools/test_apps/system/g0_components/CMakeLists.txt +++ b/tools/test_apps/system/g0_components/CMakeLists.txt @@ -26,10 +26,11 @@ idf_build_set_property(__BUILD_COMPONENT_DEPGRAPH_ENABLED 1) project(g0_components) -# As a workaround for ESP32-C2, we need to define the MMU page size here, until MMU hal-driver -# is refactored -if(CONFIG_IDF_TARGET_ESP32C2 OR CONFIG_IDF_TARGET_ESP32C6 OR CONFIG_IDF_TARGET_ESP32H2) - idf_build_set_property(C_COMPILE_OPTIONS "-DCONFIG_MMU_PAGE_SIZE=64" APPEND) +# As a workaround, we need to define the MMU page size here, until MMU hal-driver +# is refactored. +# IDF-5219 +if(CONFIG_SOC_MMU_PAGE_SIZE_CONFIGURABLE) + idf_build_set_property(C_COMPILE_OPTIONS "-DCONFIG_MMU_PAGE_SIZE=0x10000" APPEND) endif() if(CONFIG_IDF_TARGET_ESP32C2) diff --git a/tools/test_apps/system/g1_components/CMakeLists.txt b/tools/test_apps/system/g1_components/CMakeLists.txt index 3c2324800c2..31c6c2fdc5e 100644 --- a/tools/test_apps/system/g1_components/CMakeLists.txt +++ b/tools/test_apps/system/g1_components/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.16) set(g0_components soc hal esp_common esp_rom) # also , i.e. xtensa or riscv, will be added below -set(g1_components spi_flash freertos log heap newlib esp_system esp_hw_support) +set(g1_components spi_flash freertos log heap newlib esp_system esp_hw_support esp_mm) set(COMPONENTS ${g0_components} ${g1_components} main) include($ENV{IDF_PATH}/tools/cmake/project.cmake) diff --git a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_bin_crc b/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_bin_crc index 627ace5460b..8dd420e18f3 100644 --- a/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_bin_crc +++ b/tools/test_apps/system/panic/sdkconfig.ci.coredump_flash_bin_crc @@ -1,3 +1,6 @@ CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN=y CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y + +# static D/IRAM usage 97%, add this to reduce +CONFIG_HAL_ASSERTION_DISABLE=y diff --git a/tools/unit-test-app/configs/test_utils_psram b/tools/unit-test-app/configs/test_utils_psram index bee6b71a503..2d2475232b9 100644 --- a/tools/unit-test-app/configs/test_utils_psram +++ b/tools/unit-test-app/configs/test_utils_psram @@ -4,3 +4,4 @@ CONFIG_IDF_TARGET="esp32" TEST_COMPONENTS=test_utils CONFIG_ESP_IPC_TASK_STACK_SIZE=3072 CONFIG_SPIRAM=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y diff --git a/tools/unit-test-app/partition_table_unit_test_app_2m.csv b/tools/unit-test-app/partition_table_unit_test_app_2m.csv index 00666358430..e722873b1f3 100644 --- a/tools/unit-test-app/partition_table_unit_test_app_2m.csv +++ b/tools/unit-test-app/partition_table_unit_test_app_2m.csv @@ -5,7 +5,7 @@ nvs, data, nvs, 0xb000, 0x5000 otadata, data, ota, 0x10000, 0x2000 phy_init, data, phy, 0x12000, 0x1000 -factory, 0, 0, 0x20000, 0x160000 +factory, 0, 0, 0x20000, 0x150000 # these OTA partitions are used for tests, but can't fit real OTA apps in them # (done this way to reduce total flash usage.) ota_0, 0, ota_0, , 64K