diff --git a/components/bootloader_support/bootloader_flash/include/bootloader_flash_priv.h b/components/bootloader_support/bootloader_flash/include/bootloader_flash_priv.h index d8060476ae..50f31caf2d 100644 --- a/components/bootloader_support/bootloader_flash/include/bootloader_flash_priv.h +++ b/components/bootloader_support/bootloader_flash/include/bootloader_flash_priv.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,7 @@ #include /* including in bootloader for error values */ #include "sdkconfig.h" #include "bootloader_flash.h" +#include "soc/ext_mem_defs.h" #ifdef __cplusplus extern "C" { @@ -20,8 +21,11 @@ extern "C" { #define FLASH_SECTOR_SIZE 0x1000 #define FLASH_BLOCK_SIZE 0x10000 + #define MMAP_ALIGNED_MASK (SPI_FLASH_MMU_PAGE_SIZE - 1) #define MMU_FLASH_MASK (~(SPI_FLASH_MMU_PAGE_SIZE - 1)) +#define MMU_FLASH_MASK_FROM_VAL(PAGE_SZ) (~((PAGE_SZ) - 1)) +#define MMU_DROM_END_ENTRY_VADDR_FROM_VAL(PAGE_SZ) (SOC_DRAM_FLASH_ADDRESS_HIGH - (PAGE_SZ)) /** * MMU mapping must always be in the unit of a SPI_FLASH_MMU_PAGE_SIZE @@ -89,7 +93,7 @@ uint32_t bootloader_mmap_get_free_pages(void); * @param length - Length of data to map. * * @return Pointer to mapped data memory (at src_addr), or NULL - * if an allocation error occured. + * if an allocation error occurred. */ const void *bootloader_mmap(uint32_t src_addr, uint32_t size); diff --git a/components/bootloader_support/include/esp_image_format.h b/components/bootloader_support/include/esp_image_format.h index f677b08fe5..4cc4ba063b 100644 --- a/components/bootloader_support/include/esp_image_format.h +++ b/components/bootloader_support/include/esp_image_format.h @@ -34,6 +34,7 @@ typedef struct { uint32_t image_len; /* Length of image on flash, in bytes */ uint8_t image_digest[32]; /* appended SHA-256 digest */ uint32_t secure_version; /* secure version for anti-rollback, it is covered by sha256 (set if CONFIG_BOOTLOADER_APP_ANTI_ROLLBACK=y) */ + uint32_t mmu_page_size; /* Flash MMU page size per binary header */ } esp_image_metadata_t; typedef enum { diff --git a/components/bootloader_support/src/bootloader_utility.c b/components/bootloader_support/src/bootloader_utility.c index d27aaaf539..3071db642b 100644 --- a/components/bootloader_support/src/bootloader_utility.c +++ b/components/bootloader_support/src/bootloader_utility.c @@ -20,6 +20,7 @@ #include "esp_rom_spiflash.h" #include "soc/soc.h" +#include "soc/soc_caps.h" #include "soc/rtc.h" #include "soc/efuse_periph.h" #include "soc/rtc_periph.h" @@ -66,7 +67,7 @@ static void set_cache_and_start_app(uint32_t drom_addr, uint32_t irom_addr, uint32_t irom_load_addr, uint32_t irom_size, - uint32_t entry_addr); + const esp_image_metadata_t *data); esp_err_t bootloader_common_read_otadata(const esp_partition_pos_t *ota_info, esp_ota_select_entry_t *two_otadata) { @@ -789,7 +790,7 @@ static void unpack_load_app(const esp_image_metadata_t *data) rom_addr[1], rom_load_addr[1], rom_size[1], - data->image.entry_addr); + data); } #else //!SOC_MMU_DI_VADDR_SHARED @@ -834,7 +835,7 @@ static void unpack_load_app(const esp_image_metadata_t *data) irom_addr, irom_load_addr, irom_size, - data->image.entry_addr); + data); } #endif //#if SOC_MMU_DI_VADDR_SHARED @@ -859,9 +860,11 @@ static void set_cache_and_start_app( uint32_t irom_addr, uint32_t irom_load_addr, uint32_t irom_size, - uint32_t entry_addr) + const esp_image_metadata_t *data) { int rc __attribute__((unused)); + const uint32_t entry_addr = data->image.entry_addr; + const uint32_t mmu_page_size = data->mmu_page_size; ESP_EARLY_LOGD(TAG, "configure drom and irom and start"); //-----------------------Disable Cache to do the mapping--------- @@ -871,12 +874,18 @@ static void set_cache_and_start_app( #else cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); #endif + +#if SOC_MMU_PAGE_SIZE_CONFIGURABLE + // re-configure MMU page size + mmu_ll_set_page_size(0, mmu_page_size); +#endif //SOC_MMU_PAGE_SIZE_CONFIGURABLE + //reset MMU table first mmu_hal_unmap_all(); //-----------------------MAP DROM-------------------------- - uint32_t drom_load_addr_aligned = drom_load_addr & MMU_FLASH_MASK; - uint32_t drom_addr_aligned = drom_addr & MMU_FLASH_MASK; + uint32_t drom_load_addr_aligned = drom_load_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size); + uint32_t drom_addr_aligned = drom_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size); ESP_EARLY_LOGV(TAG, "rodata starts from paddr=0x%08" PRIx32 ", vaddr=0x%08" PRIx32 ", size=0x%" PRIx32, drom_addr, drom_load_addr, drom_size); //The addr is aligned, so we add the mask off length to the size, to make sure the corresponding buses are enabled. drom_size = (drom_load_addr - drom_load_addr_aligned) + drom_size; @@ -894,13 +903,13 @@ static void set_cache_and_start_app( ESP_EARLY_LOGV(TAG, "after mapping rodata, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, drom_load_addr_aligned, actual_mapped_len); } //we use the MMU_LL_END_DROM_ENTRY_ID mmu entry as a map page for app to find the boot partition - mmu_hal_map_region(0, MMU_TARGET_FLASH0, MMU_LL_END_DROM_ENTRY_VADDR, drom_addr_aligned, CONFIG_MMU_PAGE_SIZE, &actual_mapped_len); + mmu_hal_map_region(0, MMU_TARGET_FLASH0, MMU_DROM_END_ENTRY_VADDR_FROM_VAL(mmu_page_size), drom_addr_aligned, mmu_page_size, &actual_mapped_len); ESP_EARLY_LOGV(TAG, "mapped one page of the rodata, from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", drom_addr_aligned, MMU_LL_END_DROM_ENTRY_VADDR, actual_mapped_len); #endif //-----------------------MAP IROM-------------------------- - uint32_t irom_load_addr_aligned = irom_load_addr & MMU_FLASH_MASK; - uint32_t irom_addr_aligned = irom_addr & MMU_FLASH_MASK; + uint32_t irom_load_addr_aligned = irom_load_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size); + uint32_t irom_addr_aligned = irom_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size); ESP_EARLY_LOGV(TAG, "text starts from paddr=0x%08" PRIx32 ", vaddr=0x%08" PRIx32 ", size=0x%" PRIx32, irom_addr, irom_load_addr, irom_size); //The addr is aligned, so we add the mask off length to the size, to make sure the corresponding buses are enabled. irom_size = (irom_load_addr - irom_load_addr_aligned) + irom_size; diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 6b2f88a7ba..12168825c8 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -22,6 +22,7 @@ #include "bootloader_memory_utils.h" #include "soc/soc_caps.h" #include "hal/cache_ll.h" +#include "spi_flash_mmap.h" #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) @@ -77,7 +78,7 @@ static esp_err_t process_segment_data(int segment, intptr_t load_addr, uint32_t static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent); /* Verify a segment header */ -static esp_err_t verify_segment_header(int index, const esp_image_segment_header_t *segment, uint32_t segment_data_offs, bool silent); +static esp_err_t verify_segment_header(int index, const esp_image_segment_header_t *segment, uint32_t segment_data_offs, esp_image_metadata_t *metadata, bool silent); /* Log-and-fail macro for use in esp_image_load */ #define FAIL_LOAD(...) do { \ @@ -559,7 +560,7 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme ESP_LOGV(TAG, "segment data length 0x%"PRIx32" data starts 0x%"PRIx32, data_len, data_addr); - CHECK_ERR(verify_segment_header(index, header, data_addr, silent)); + CHECK_ERR(verify_segment_header(index, header, data_addr, metadata, silent)); if (data_len % 4 != 0) { FAIL_LOAD("unaligned segment length 0x%"PRIx32, data_len); @@ -748,7 +749,7 @@ static esp_err_t process_segment_data(int segment, intptr_t load_addr, uint32_t return ESP_OK; } -static esp_err_t verify_segment_header(int index, const esp_image_segment_header_t *segment, uint32_t segment_data_offs, bool silent) +static esp_err_t verify_segment_header(int index, const esp_image_segment_header_t *segment, uint32_t segment_data_offs, esp_image_metadata_t *metadata, bool silent) { if ((segment->data_len & 3) != 0 || segment->data_len >= SIXTEEN_MB) { @@ -761,13 +762,42 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header uint32_t load_addr = segment->load_addr; bool map_segment = should_map(load_addr); +#if SOC_MMU_PAGE_SIZE_CONFIGURABLE + /* ESP APP descriptor is present in the DROM segment #0 */ + if (index == 0 && metadata->start_addr != ESP_BOOTLOADER_OFFSET) { + uint32_t data_len = segment->data_len; + const uint32_t *data = (const uint32_t *)bootloader_mmap(segment_data_offs, data_len); + if (!data) { + ESP_LOGE(TAG, "bootloader_mmap(0x%"PRIx32", 0x%"PRIx32") failed", + segment_data_offs, data_len); + return ESP_FAIL; + } + + esp_app_desc_t *app_desc = (esp_app_desc_t *)data; + // Convert from log base 2 number to actual size while handling legacy image case (value 0) + metadata->mmu_page_size = (app_desc->mmu_page_size > 0) ? (1UL << app_desc->mmu_page_size) : SPI_FLASH_MMU_PAGE_SIZE; + if (metadata->mmu_page_size != SPI_FLASH_MMU_PAGE_SIZE) { + ESP_LOGI(TAG, "MMU page size mismatch, configured: 0x%x, found: 0x%"PRIx32, SPI_FLASH_MMU_PAGE_SIZE, metadata->mmu_page_size); + } + bootloader_munmap(data); + } else if (index == 0 && metadata->start_addr == ESP_BOOTLOADER_OFFSET) { + // Bootloader always uses the default MMU page size + metadata->mmu_page_size = SPI_FLASH_MMU_PAGE_SIZE; + } +#else // SOC_MMU_PAGE_SIZE_CONFIGURABLE + metadata->mmu_page_size = SPI_FLASH_MMU_PAGE_SIZE; +#endif // !SOC_MMU_PAGE_SIZE_CONFIGURABLE + + const int mmu_page_size = metadata->mmu_page_size; + ESP_LOGV(TAG, "MMU page size 0x%x", mmu_page_size); + /* Check that flash cache mapped segment aligns correctly from flash to its mapped address, - relative to the 64KB page mapping size. + relative to the MMU page mapping size. */ ESP_LOGV(TAG, "segment %d map_segment %d segment_data_offs 0x%"PRIx32" load_addr 0x%"PRIx32, index, map_segment, segment_data_offs, load_addr); if (map_segment - && ((segment_data_offs % SPI_FLASH_MMU_PAGE_SIZE) != (load_addr % SPI_FLASH_MMU_PAGE_SIZE))) { + && ((segment_data_offs % mmu_page_size) != (load_addr % mmu_page_size))) { if (!silent) { ESP_LOGE(TAG, "Segment %d load address 0x%08"PRIx32", doesn't match data 0x%08"PRIx32, index, load_addr, segment_data_offs); diff --git a/components/esp_app_format/esp_app_desc.c b/components/esp_app_format/esp_app_desc.c index 27b821256d..302250b179 100644 --- a/components/esp_app_format/esp_app_desc.c +++ b/components/esp_app_format/esp_app_desc.c @@ -59,6 +59,7 @@ const __attribute__((weak)) __attribute__((section(".rodata_desc"))) esp_app_de #endif .min_efuse_blk_rev_full = CONFIG_ESP_EFUSE_BLOCK_REV_MIN_FULL, .max_efuse_blk_rev_full = CONFIG_ESP_EFUSE_BLOCK_REV_MAX_FULL, + .mmu_page_size = 31 - __builtin_clz(CONFIG_MMU_PAGE_SIZE), }; #ifndef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR diff --git a/components/esp_app_format/include/esp_app_desc.h b/components/esp_app_format/include/esp_app_desc.h index b4201a4d05..6cb73e3676 100644 --- a/components/esp_app_format/include/esp_app_desc.h +++ b/components/esp_app_format/include/esp_app_desc.h @@ -35,7 +35,9 @@ typedef struct { uint8_t app_elf_sha256[32]; /*!< sha256 of elf file */ uint16_t min_efuse_blk_rev_full; /*!< Minimal eFuse block revision supported by image, in format: major * 100 + minor */ uint16_t max_efuse_blk_rev_full; /*!< Maximal eFuse block revision supported by image, in format: major * 100 + minor */ - uint32_t reserv2[19]; /*!< reserv2 */ + uint8_t mmu_page_size; /*!< MMU page size in log base 2 format */ + uint8_t reserv3[3]; /*!< reserv3 */ + uint32_t reserv2[18]; /*!< reserv2 */ } esp_app_desc_t; /** @cond */