mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
feat(bootloader): add support to use MMU page size from app binary
For the SoCs that support configurable MMU page size, it is possible that the bootloader and application are built with different MMU page size configuration. This mismatch is not supported at the moment and application verification fails (at bootup or during OTA update). Configuring MMU page size helps to optimize the flash space by having smaller alignment and padding (secure) requirements. Please note that the MMU page size is tied with the flash size configuration at the moment (`ESPTOOLPY_FLASHSIZE_XMB`). This MR ensures that application verification happens using the MMU page size configured in its binary header. Thus, bootloader and application can now have different MMU page sizes and different combinations shall be supported.
This commit is contained in:
parent
9240757145
commit
07318a4987
@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -13,6 +13,7 @@
|
|||||||
#include <spi_flash_mmap.h> /* including in bootloader for error values */
|
#include <spi_flash_mmap.h> /* including in bootloader for error values */
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "bootloader_flash.h"
|
#include "bootloader_flash.h"
|
||||||
|
#include "soc/ext_mem_defs.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -20,8 +21,11 @@ extern "C" {
|
|||||||
|
|
||||||
#define FLASH_SECTOR_SIZE 0x1000
|
#define FLASH_SECTOR_SIZE 0x1000
|
||||||
#define FLASH_BLOCK_SIZE 0x10000
|
#define FLASH_BLOCK_SIZE 0x10000
|
||||||
|
|
||||||
#define MMAP_ALIGNED_MASK (SPI_FLASH_MMU_PAGE_SIZE - 1)
|
#define MMAP_ALIGNED_MASK (SPI_FLASH_MMU_PAGE_SIZE - 1)
|
||||||
#define MMU_FLASH_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
|
* 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.
|
* @param length - Length of data to map.
|
||||||
*
|
*
|
||||||
* @return Pointer to mapped data memory (at src_addr), or NULL
|
* @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);
|
const void *bootloader_mmap(uint32_t src_addr, uint32_t size);
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ typedef struct {
|
|||||||
uint32_t image_len; /* Length of image on flash, in bytes */
|
uint32_t image_len; /* Length of image on flash, in bytes */
|
||||||
uint8_t image_digest[32]; /* appended SHA-256 digest */
|
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 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;
|
} esp_image_metadata_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "esp_rom_spiflash.h"
|
#include "esp_rom_spiflash.h"
|
||||||
|
|
||||||
#include "soc/soc.h"
|
#include "soc/soc.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
#include "soc/rtc.h"
|
#include "soc/rtc.h"
|
||||||
#include "soc/efuse_periph.h"
|
#include "soc/efuse_periph.h"
|
||||||
#include "soc/rtc_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_addr,
|
||||||
uint32_t irom_load_addr,
|
uint32_t irom_load_addr,
|
||||||
uint32_t irom_size,
|
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)
|
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_addr[1],
|
||||||
rom_load_addr[1],
|
rom_load_addr[1],
|
||||||
rom_size[1],
|
rom_size[1],
|
||||||
data->image.entry_addr);
|
data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else //!SOC_MMU_DI_VADDR_SHARED
|
#else //!SOC_MMU_DI_VADDR_SHARED
|
||||||
@ -834,7 +835,7 @@ static void unpack_load_app(const esp_image_metadata_t *data)
|
|||||||
irom_addr,
|
irom_addr,
|
||||||
irom_load_addr,
|
irom_load_addr,
|
||||||
irom_size,
|
irom_size,
|
||||||
data->image.entry_addr);
|
data);
|
||||||
}
|
}
|
||||||
#endif //#if SOC_MMU_DI_VADDR_SHARED
|
#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_addr,
|
||||||
uint32_t irom_load_addr,
|
uint32_t irom_load_addr,
|
||||||
uint32_t irom_size,
|
uint32_t irom_size,
|
||||||
uint32_t entry_addr)
|
const esp_image_metadata_t *data)
|
||||||
{
|
{
|
||||||
int rc __attribute__((unused));
|
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");
|
ESP_EARLY_LOGD(TAG, "configure drom and irom and start");
|
||||||
//-----------------------Disable Cache to do the mapping---------
|
//-----------------------Disable Cache to do the mapping---------
|
||||||
@ -871,12 +874,18 @@ static void set_cache_and_start_app(
|
|||||||
#else
|
#else
|
||||||
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||||
#endif
|
#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
|
//reset MMU table first
|
||||||
mmu_hal_unmap_all();
|
mmu_hal_unmap_all();
|
||||||
|
|
||||||
//-----------------------MAP DROM--------------------------
|
//-----------------------MAP DROM--------------------------
|
||||||
uint32_t drom_load_addr_aligned = drom_load_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;
|
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);
|
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.
|
//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;
|
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);
|
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
|
//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);
|
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
|
#endif
|
||||||
|
|
||||||
//-----------------------MAP IROM--------------------------
|
//-----------------------MAP IROM--------------------------
|
||||||
uint32_t irom_load_addr_aligned = irom_load_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;
|
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);
|
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.
|
//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;
|
irom_size = (irom_load_addr - irom_load_addr_aligned) + irom_size;
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "bootloader_memory_utils.h"
|
#include "bootloader_memory_utils.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "hal/cache_ll.h"
|
#include "hal/cache_ll.h"
|
||||||
|
#include "spi_flash_mmap.h"
|
||||||
|
|
||||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
#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);
|
static esp_err_t verify_image_header(uint32_t src_addr, const esp_image_header_t *image, bool silent);
|
||||||
|
|
||||||
/* Verify a segment header */
|
/* 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 */
|
/* Log-and-fail macro for use in esp_image_load */
|
||||||
#define FAIL_LOAD(...) do { \
|
#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);
|
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) {
|
if (data_len % 4 != 0) {
|
||||||
FAIL_LOAD("unaligned segment length 0x%"PRIx32, data_len);
|
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;
|
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
|
if ((segment->data_len & 3) != 0
|
||||||
|| segment->data_len >= SIXTEEN_MB) {
|
|| 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;
|
uint32_t load_addr = segment->load_addr;
|
||||||
bool map_segment = should_map(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,
|
/* 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,
|
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);
|
index, map_segment, segment_data_offs, load_addr);
|
||||||
if (map_segment
|
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) {
|
if (!silent) {
|
||||||
ESP_LOGE(TAG, "Segment %d load address 0x%08"PRIx32", doesn't match data 0x%08"PRIx32,
|
ESP_LOGE(TAG, "Segment %d load address 0x%08"PRIx32", doesn't match data 0x%08"PRIx32,
|
||||||
index, load_addr, segment_data_offs);
|
index, load_addr, segment_data_offs);
|
||||||
|
@ -59,6 +59,7 @@ const __attribute__((weak)) __attribute__((section(".rodata_desc"))) esp_app_de
|
|||||||
#endif
|
#endif
|
||||||
.min_efuse_blk_rev_full = CONFIG_ESP_EFUSE_BLOCK_REV_MIN_FULL,
|
.min_efuse_blk_rev_full = CONFIG_ESP_EFUSE_BLOCK_REV_MIN_FULL,
|
||||||
.max_efuse_blk_rev_full = CONFIG_ESP_EFUSE_BLOCK_REV_MAX_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
|
#ifndef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR
|
||||||
|
@ -35,7 +35,9 @@ typedef struct {
|
|||||||
uint8_t app_elf_sha256[32]; /*!< sha256 of elf file */
|
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 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 */
|
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;
|
} esp_app_desc_t;
|
||||||
|
|
||||||
/** @cond */
|
/** @cond */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user