mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 09:09:10 -04:00
feat(esp_tee): Support for ESP-TEE - bootloader_support
component
This commit is contained in:
parent
f254f93594
commit
54c3f1bae4
@ -1,9 +1,38 @@
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
|
||||
|
||||
if(${target} STREQUAL "linux")
|
||||
return() # This component is not supported by the POSIX/Linux simulator
|
||||
endif()
|
||||
|
||||
if(esp_tee_build)
|
||||
set(tee_inc_dirs "include"
|
||||
"private_include"
|
||||
"bootloader_flash/include")
|
||||
|
||||
set(tee_srcs "src/flash_partitions.c"
|
||||
"src/${IDF_TARGET}/bootloader_sha.c"
|
||||
"src/bootloader_common_loader.c"
|
||||
"src/esp_image_format.c"
|
||||
"src/bootloader_utility.c"
|
||||
"src/bootloader_utility_tee.c"
|
||||
"bootloader_flash/src/bootloader_flash.c")
|
||||
|
||||
if(CONFIG_SECURE_BOOT_V2_ENABLED)
|
||||
if(CONFIG_SECURE_SIGNED_APPS_RSA_SCHEME OR CONFIG_SECURE_SIGNED_APPS_ECDSA_V2_SCHEME)
|
||||
list(APPEND tee_srcs "src/secure_boot_v2/secure_boot_signatures_bootloader.c"
|
||||
"src/secure_boot_v2/secure_boot.c"
|
||||
"src/${IDF_TARGET}/secure_boot_secure_features.c")
|
||||
endif()
|
||||
list(APPEND priv_requires efuse)
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${tee_srcs}
|
||||
INCLUDE_DIRS ${tee_inc_dirs}
|
||||
PRIV_REQUIRES efuse)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(srcs
|
||||
"src/bootloader_common.c"
|
||||
"src/bootloader_common_loader.c"
|
||||
@ -49,6 +78,9 @@ if(BOOTLOADER_BUILD OR CONFIG_APP_BUILD_TYPE_RAM)
|
||||
"src/${IDF_TARGET}/bootloader_soc.c"
|
||||
"src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c"
|
||||
)
|
||||
if(CONFIG_SECURE_ENABLE_TEE)
|
||||
list(APPEND srcs "src/bootloader_utility_tee.c")
|
||||
endif()
|
||||
list(APPEND priv_requires hal)
|
||||
if(CONFIG_ESP_ROM_REV0_HAS_NO_ECDSA_INTERFACE)
|
||||
list(APPEND srcs
|
||||
|
@ -13,11 +13,12 @@
|
||||
#include "hal/efuse_ll.h"
|
||||
#include "hal/efuse_hal.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#if !NON_OS_BUILD
|
||||
#include "spi_flash_mmap.h"
|
||||
#endif
|
||||
#include "hal/spi_flash_ll.h"
|
||||
#include "rom/spi_flash.h"
|
||||
#include "esp_private/cache_utils.h"
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
#include "hal/spimem_flash_ll.h"
|
||||
#endif
|
||||
@ -44,7 +45,7 @@
|
||||
#define ESP_BOOTLOADER_SPIFLASH_QE_GD_SR2 BIT1 // QE position when you write 8 bits(for SR2) at one time.
|
||||
#define ESP_BOOTLOADER_SPIFLASH_QE_SR1_2BYTE BIT9 // QE position when you write 16 bits at one time.
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#if !NON_OS_BUILD
|
||||
/* Normal app version maps to spi_flash_mmap.h operations...
|
||||
*/
|
||||
static const char *TAG = "bootloader_mmap";
|
||||
@ -111,7 +112,7 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
return esp_flash_erase_region(NULL, start_addr, size);
|
||||
}
|
||||
|
||||
#else //BOOTLOADER_BUILD
|
||||
#else // NON_OS_BUILD
|
||||
/* Bootloader version, uses ROM functions only */
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/cache.h"
|
||||
@ -128,15 +129,46 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
#elif CONFIG_IDF_TARGET_ESP32P4
|
||||
#include "esp32p4/rom/opi_flash.h"
|
||||
#endif
|
||||
|
||||
#if ESP_TEE_BUILD
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp32c6/rom/spi_flash.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "bootloader_flash";
|
||||
|
||||
/*
|
||||
* NOTE: Memory mapping strategy
|
||||
*
|
||||
* Bootloader:
|
||||
* - Uses the first N-1 MMU entries for general memory mapping.
|
||||
* - Reserves the Nth (last) MMU entry for flash read through the cache
|
||||
* (auto-decryption).
|
||||
* - This strategy is viable because the bootloader runs exclusively
|
||||
* on the device from the internal SRAM.
|
||||
*
|
||||
* ESP-TEE (Trusted Execution Environment)
|
||||
* - Cannot adopt the strategy used by the bootloader as the TEE app operates
|
||||
* in parallel to the REE.
|
||||
* - The few initial MMU entries have already been taken by the TEE and REE
|
||||
* application flash IDROM segments.
|
||||
* - The REE could have also mapped some custom flash partitions it requires.
|
||||
* - Therefore, the TEE uses MMU entries from the end of the range, with the number
|
||||
* of entries corresponding to the size of its IDROM segment sizes.
|
||||
* - The final MMU entry in this range is reserved for flash reads through the
|
||||
* cache (auto-decryption).
|
||||
* - The pages used by TEE are protected by PMP (Physical Memory Protection).
|
||||
* While REE attempts to mmap this protected area would trigger a load access
|
||||
* fault, this is unlikely since the MMU can address up to 16MB at once.
|
||||
*/
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/* Use first 50 blocks in MMU for bootloader_mmap,
|
||||
50th block for bootloader_flash_read
|
||||
*/
|
||||
#define MMU_BLOCK0_VADDR SOC_DROM_LOW
|
||||
#define MMAP_MMU_SIZE (0x320000)
|
||||
#define MMU_BLOCK50_VADDR (MMU_BLOCK0_VADDR + MMAP_MMU_SIZE)
|
||||
#define MMU_TOTAL_SIZE (0x320000)
|
||||
#define MMU_BLOCK50_VADDR (MMU_BLOCK0_VADDR + MMU_TOTAL_SIZE)
|
||||
#define FLASH_READ_VADDR MMU_BLOCK50_VADDR
|
||||
|
||||
#else // !CONFIG_IDF_TARGET_ESP32
|
||||
@ -150,21 +182,89 @@ static const char *TAG = "bootloader_flash";
|
||||
* On ESP32S2 we use `(SOC_DRAM0_CACHE_ADDRESS_HIGH - SOC_DRAM0_CACHE_ADDRESS_LOW)`.
|
||||
* As this code is in bootloader, we keep this on ESP32S2
|
||||
*/
|
||||
#define MMAP_MMU_SIZE (SOC_DRAM0_CACHE_ADDRESS_HIGH - SOC_DRAM0_CACHE_ADDRESS_LOW) // This mmu size means that the mmu size to be mapped
|
||||
#define MMU_TOTAL_SIZE (SOC_DRAM0_CACHE_ADDRESS_HIGH - SOC_DRAM0_CACHE_ADDRESS_LOW) // This mmu size means that the mmu size to be mapped
|
||||
#else
|
||||
#define MMAP_MMU_SIZE (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_DRAM_FLASH_ADDRESS_LOW) // This mmu size means that the mmu size to be mapped
|
||||
#define MMU_TOTAL_SIZE (SOC_DRAM_FLASH_ADDRESS_HIGH - SOC_DRAM_FLASH_ADDRESS_LOW) // This mmu size means that the mmu size to be mapped
|
||||
#endif
|
||||
#define MMU_BLOCK63_VADDR (MMU_BLOCK0_VADDR + MMAP_MMU_SIZE - SPI_FLASH_MMU_PAGE_SIZE)
|
||||
#define FLASH_READ_VADDR MMU_BLOCK63_VADDR
|
||||
#define MMU_END_VADDR (MMU_BLOCK0_VADDR + MMU_TOTAL_SIZE)
|
||||
#define MMU_BLOCKL_VADDR (MMU_END_VADDR - 1 * CONFIG_MMU_PAGE_SIZE)
|
||||
#define FLASH_READ_VADDR MMU_BLOCKL_VADDR
|
||||
#endif
|
||||
|
||||
#if !ESP_TEE_BUILD
|
||||
#define MMAP_MMU_SIZE (MMU_TOTAL_SIZE)
|
||||
// Represents the MMU pages available for mmapping by the bootloader
|
||||
#define MMU_FREE_PAGES (MMAP_MMU_SIZE / CONFIG_MMU_PAGE_SIZE)
|
||||
#define FLASH_MMAP_VADDR (MMU_BLOCK0_VADDR)
|
||||
#else /* ESP_TEE_BUILD */
|
||||
#define MMAP_MMU_SIZE (CONFIG_SECURE_TEE_IROM_SIZE + CONFIG_SECURE_TEE_DROM_SIZE)
|
||||
// Represents the MMU pages available for mmapping by the TEE
|
||||
#define MMU_FREE_PAGES (MMAP_MMU_SIZE / CONFIG_MMU_PAGE_SIZE)
|
||||
#define FLASH_MMAP_VADDR (MMU_END_VADDR - (MMU_FREE_PAGES + 1) * CONFIG_MMU_PAGE_SIZE)
|
||||
#endif /* !ESP_TEE_BUILD */
|
||||
|
||||
static bool mapped;
|
||||
|
||||
// Required for bootloader_flash_munmap() for ESP-TEE
|
||||
static uint32_t current_mapped_size;
|
||||
|
||||
// Current bootloader mapping (ab)used for bootloader_read()
|
||||
static uint32_t current_read_mapping = UINT32_MAX;
|
||||
|
||||
#if ESP_TEE_BUILD && CONFIG_IDF_TARGET_ESP32C6
|
||||
extern void spi_common_set_dummy_output(esp_rom_spiflash_read_mode_t mode);
|
||||
extern void spi_dummy_len_fix(uint8_t spi, uint8_t freqdiv);
|
||||
|
||||
/* TODO: [ESP-TEE] Workarounds for the ROM read API
|
||||
*
|
||||
* The esp_rom_spiflash_read API requires two workarounds on ESP32-C6 ECO0:
|
||||
*
|
||||
* 1. [IDF-7199] Call esp_rom_spiflash_write API once before reading.
|
||||
* Without this, reads return corrupted data.
|
||||
*
|
||||
* 2. Configure ROM flash parameters before each read using the function below.
|
||||
* Without this, the first byte read is corrupted.
|
||||
*
|
||||
* Note: These workarounds are not needed for ESP32-C6 ECO1 and later versions.
|
||||
*/
|
||||
static void rom_read_api_workaround(void)
|
||||
{
|
||||
static bool is_first_call = true;
|
||||
if (is_first_call) {
|
||||
uint32_t dummy_val = UINT32_MAX;
|
||||
uint32_t dest_addr = ESP_PARTITION_TABLE_OFFSET + ESP_PARTITION_TABLE_MAX_LEN;
|
||||
esp_rom_spiflash_write(dest_addr, &dummy_val, sizeof(dummy_val));
|
||||
is_first_call = false;
|
||||
}
|
||||
|
||||
uint32_t freqdiv = 0;
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_80M
|
||||
freqdiv = 1;
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_40M
|
||||
freqdiv = 2;
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_20M
|
||||
freqdiv = 4;
|
||||
#endif
|
||||
|
||||
esp_rom_spiflash_read_mode_t read_mode;
|
||||
#if CONFIG_ESPTOOLPY_FLASHMODE_QIO
|
||||
read_mode = ESP_ROM_SPIFLASH_QIO_MODE;
|
||||
#elif CONFIG_ESPTOOLPY_FLASHMODE_QOUT
|
||||
read_mode = ESP_ROM_SPIFLASH_QOUT_MODE;
|
||||
#elif CONFIG_ESPTOOLPY_FLASHMODE_DIO
|
||||
read_mode = ESP_ROM_SPIFLASH_DIO_MODE;
|
||||
#elif CONFIG_ESPTOOLPY_FLASHMODE_DOUT
|
||||
read_mode = ESP_ROM_SPIFLASH_DOUT_MODE;
|
||||
#endif
|
||||
|
||||
esp_rom_spiflash_config_clk(freqdiv, 1);
|
||||
spi_dummy_len_fix(1, freqdiv);
|
||||
esp_rom_spiflash_config_readmode(read_mode);
|
||||
spi_common_set_dummy_output(read_mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t bootloader_mmap_get_free_pages(void)
|
||||
{
|
||||
/**
|
||||
@ -188,13 +288,15 @@ const void *bootloader_mmap(uint32_t src_paddr, uint32_t size)
|
||||
uint32_t src_paddr_aligned = src_paddr & MMU_FLASH_MASK;
|
||||
//The addr is aligned, so we add the mask off length to the size, to make sure the corresponding buses are enabled.
|
||||
uint32_t size_after_paddr_aligned = (src_paddr - src_paddr_aligned) + size;
|
||||
|
||||
uint32_t actual_mapped_len = 0;
|
||||
/**
|
||||
* @note 1
|
||||
* Will add here a check to make sure the vaddr is on read-only and executable buses, since we use others for psram
|
||||
* Now simply check if it's valid vaddr, didn't check if it's readable, writable or executable.
|
||||
* TODO: IDF-4710
|
||||
*/
|
||||
if (mmu_ll_check_valid_ext_vaddr_region(0, MMU_BLOCK0_VADDR, size_after_paddr_aligned, MMU_VADDR_DATA | MMU_VADDR_INSTRUCTION) == 0) {
|
||||
if (mmu_ll_check_valid_ext_vaddr_region(0, FLASH_MMAP_VADDR, size_after_paddr_aligned, MMU_VADDR_DATA | MMU_VADDR_INSTRUCTION) == 0) {
|
||||
ESP_EARLY_LOGE(TAG, "vaddr not valid");
|
||||
return NULL;
|
||||
}
|
||||
@ -204,15 +306,25 @@ const void *bootloader_mmap(uint32_t src_paddr, uint32_t size)
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Flush(0);
|
||||
#else
|
||||
/* NOTE: [ESP-TEE] Cache suspension vs disabling
|
||||
*
|
||||
* For ESP-TEE , we use suspend the cache instead of disabling it to avoid flushing the entire cache.
|
||||
* This prevents performance hits when returning to the REE app due to cache misses.
|
||||
* This is not applicable to the bootloader as it runs exclusively on the device from the internal SRAM.
|
||||
*/
|
||||
#if !ESP_TEE_BUILD
|
||||
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#else
|
||||
cache_hal_suspend(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//---------------Do mapping------------------------
|
||||
ESP_EARLY_LOGD(TAG, "rodata starts from paddr=0x%08" PRIx32 ", size=0x%" PRIx32 ", will be mapped to vaddr=0x%08" PRIx32, src_paddr, size, (uint32_t)MMU_BLOCK0_VADDR);
|
||||
ESP_EARLY_LOGD(TAG, "rodata starts from paddr=0x%08" PRIx32 ", size=0x%" PRIx32 ", will be mapped to vaddr=0x%08" PRIx32, src_paddr, size, (uint32_t)FLASH_MMAP_VADDR);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t count = GET_REQUIRED_MMU_PAGES(size, src_paddr);
|
||||
int e = cache_flash_mmu_set(0, 0, MMU_BLOCK0_VADDR, src_paddr_aligned, 64, count);
|
||||
ESP_EARLY_LOGV(TAG, "after mapping, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", src_paddr_aligned, (uint32_t)MMU_BLOCK0_VADDR, count * SPI_FLASH_MMU_PAGE_SIZE);
|
||||
int e = cache_flash_mmu_set(0, 0, FLASH_MMAP_VADDR, src_paddr_aligned, 64, count);
|
||||
ESP_EARLY_LOGV(TAG, "after mapping, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", src_paddr_aligned, (uint32_t)FLASH_MMAP_VADDR, count * SPI_FLASH_MMU_PAGE_SIZE);
|
||||
if (e != 0) {
|
||||
ESP_EARLY_LOGE(TAG, "cache_flash_mmu_set failed: %d", e);
|
||||
Cache_Read_Enable(0);
|
||||
@ -223,9 +335,8 @@ const void *bootloader_mmap(uint32_t src_paddr, uint32_t size)
|
||||
* This hal won't return error, it assumes the inputs are valid. The related check should be done in `bootloader_mmap()`.
|
||||
* See above comments (note 1) about IDF-4710
|
||||
*/
|
||||
uint32_t actual_mapped_len = 0;
|
||||
mmu_hal_map_region(0, MMU_TARGET_FLASH0, MMU_BLOCK0_VADDR, src_paddr_aligned, size_after_paddr_aligned, &actual_mapped_len);
|
||||
ESP_EARLY_LOGV(TAG, "after mapping, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", src_paddr_aligned, (uint32_t)MMU_BLOCK0_VADDR, actual_mapped_len);
|
||||
mmu_hal_map_region(0, MMU_TARGET_FLASH0, FLASH_MMAP_VADDR, src_paddr_aligned, size_after_paddr_aligned, &actual_mapped_len);
|
||||
ESP_EARLY_LOGV(TAG, "after mapping, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", src_paddr_aligned, (uint32_t)FLASH_MMAP_VADDR, actual_mapped_len);
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -238,14 +349,19 @@ const void *bootloader_mmap(uint32_t src_paddr, uint32_t size)
|
||||
Cache_Read_Enable(0);
|
||||
#else
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, MMU_BLOCK0_VADDR, actual_mapped_len);
|
||||
cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, FLASH_MMAP_VADDR, actual_mapped_len);
|
||||
#endif
|
||||
#if !ESP_TEE_BUILD
|
||||
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#else
|
||||
cache_hal_resume(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mapped = true;
|
||||
current_mapped_size = actual_mapped_len;
|
||||
|
||||
return (void *)(MMU_BLOCK0_VADDR + (src_paddr - src_paddr_aligned));
|
||||
return (void *)(FLASH_MMAP_VADDR + (src_paddr - src_paddr_aligned));
|
||||
}
|
||||
|
||||
void bootloader_munmap(const void *mapping)
|
||||
@ -257,11 +373,18 @@ void bootloader_munmap(const void *mapping)
|
||||
Cache_Flush(0);
|
||||
mmu_init(0);
|
||||
#else
|
||||
#if !ESP_TEE_BUILD
|
||||
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
mmu_hal_unmap_all();
|
||||
#else
|
||||
cache_hal_suspend(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
mmu_hal_unmap_region(0, FLASH_MMAP_VADDR, current_mapped_size);
|
||||
cache_hal_invalidate_addr(FLASH_MMAP_VADDR, current_mapped_size);
|
||||
cache_hal_resume(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#endif
|
||||
#endif
|
||||
mapped = false;
|
||||
current_read_mapping = UINT32_MAX;
|
||||
current_mapped_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +408,11 @@ static esp_err_t bootloader_flash_read_no_decrypt(size_t src_addr, void *dest, s
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Flush(0);
|
||||
#else
|
||||
#if !ESP_TEE_BUILD
|
||||
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#elif CONFIG_ESP32C6_REV_MIN_0
|
||||
rom_read_api_workaround();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
esp_rom_spiflash_result_t r = esp_rom_spiflash_read(src_addr, dest, size);
|
||||
@ -293,7 +420,9 @@ static esp_err_t bootloader_flash_read_no_decrypt(size_t src_addr, void *dest, s
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
Cache_Read_Enable(0);
|
||||
#else
|
||||
#if !ESP_TEE_BUILD
|
||||
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return spi_to_esp_err(r);
|
||||
@ -316,7 +445,13 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Flush(0);
|
||||
#else
|
||||
#if !ESP_TEE_BUILD
|
||||
cache_hal_disable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#else
|
||||
cache_hal_suspend(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
//---------------Invalidating entries at to-be-mapped v_addr------------------------
|
||||
cache_hal_invalidate_addr(FLASH_READ_VADDR, SPI_FLASH_MMU_PAGE_SIZE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//---------------Do mapping------------------------
|
||||
@ -337,13 +472,18 @@ static esp_err_t bootloader_flash_read_allow_decrypt(size_t src_addr, void *dest
|
||||
Cache_Read_Enable(0);
|
||||
#else
|
||||
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
||||
cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, MMU_BLOCK0_VADDR, actual_mapped_len);
|
||||
cache_ll_invalidate_addr(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL, FLASH_MMAP_VADDR, actual_mapped_len);
|
||||
#endif
|
||||
#if !ESP_TEE_BUILD
|
||||
cache_hal_enable(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#else
|
||||
cache_hal_resume(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
map_ptr = (uint32_t *)(FLASH_READ_VADDR + (word_src - map_at));
|
||||
dest_words[word] = *map_ptr;
|
||||
current_read_mapping = UINT32_MAX;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -372,7 +512,6 @@ esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool a
|
||||
|
||||
esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool write_encrypted)
|
||||
{
|
||||
esp_err_t err;
|
||||
size_t alignment = write_encrypted ? 32 : 4;
|
||||
if ((dest_addr % alignment) != 0) {
|
||||
ESP_EARLY_LOGE(TAG, "bootloader_flash_write dest_addr 0x%x not %d-byte aligned", dest_addr, alignment);
|
||||
@ -387,16 +526,29 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
err = bootloader_flash_unlock();
|
||||
esp_err_t err = bootloader_flash_unlock();
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_rom_spiflash_result_t rc = ESP_ROM_SPIFLASH_RESULT_OK;
|
||||
|
||||
if (write_encrypted && !ENCRYPTION_IS_VIRTUAL) {
|
||||
return spi_to_esp_err(esp_rom_spiflash_write_encrypted(dest_addr, src, size));
|
||||
rc = esp_rom_spiflash_write_encrypted(dest_addr, src, size);
|
||||
} else {
|
||||
return spi_to_esp_err(esp_rom_spiflash_write(dest_addr, src, size));
|
||||
rc = esp_rom_spiflash_write(dest_addr, src, size);
|
||||
}
|
||||
/* NOTE: [ESP-TEE] Cache flushing after flash writes/erases
|
||||
*
|
||||
* After writing or erasing the flash, we need to flush the cache at locations
|
||||
* corresponding to the destination write/erase address. This prevents stale data
|
||||
* from being read from already memory-mapped addresses that were modified.
|
||||
*/
|
||||
#if ESP_TEE_BUILD
|
||||
spi_flash_check_and_flush_cache(dest_addr, size);
|
||||
#endif
|
||||
|
||||
return spi_to_esp_err(rc);
|
||||
}
|
||||
|
||||
esp_err_t bootloader_flash_erase_sector(size_t sector)
|
||||
@ -426,6 +578,10 @@ esp_err_t bootloader_flash_erase_range(uint32_t start_addr, uint32_t size)
|
||||
++sector;
|
||||
}
|
||||
}
|
||||
#if ESP_TEE_BUILD
|
||||
spi_flash_check_and_flush_cache(start_addr, size);
|
||||
#endif
|
||||
|
||||
return spi_to_esp_err(rc);
|
||||
}
|
||||
|
||||
@ -480,7 +636,7 @@ void bootloader_flash_32bits_address_map_enable(esp_rom_spiflash_read_mode_t fla
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BOOTLOADER_BUILD
|
||||
#endif // NON_OS_BUILD
|
||||
|
||||
|
||||
FORCE_INLINE_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip)
|
||||
@ -671,7 +827,7 @@ void bootloader_spi_flash_reset(void)
|
||||
#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT
|
||||
#define XMC_VENDOR_ID_1 0x20
|
||||
|
||||
#if BOOTLOADER_BUILD
|
||||
#if NON_OS_BUILD
|
||||
#define BOOTLOADER_FLASH_LOG(level, ...) ESP_EARLY_LOG##level(TAG, ##__VA_ARGS__)
|
||||
#else
|
||||
static DRAM_ATTR char bootloader_flash_tag[] = "bootloader_flash";
|
||||
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "esp_flash_partitions.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Fetch the currently running TEE partition
|
||||
*
|
||||
* @param[in] tee_ota_info TEE OTA data partition
|
||||
*
|
||||
* @return Subtype of the running TEE partition, or -1 if an error occurred
|
||||
*/
|
||||
int bootloader_utility_tee_get_boot_partition(const esp_partition_pos_t *tee_ota_info);
|
||||
|
||||
/**
|
||||
* @brief Set a new TEE boot partition in the TEE OTA data
|
||||
*
|
||||
* @param[in] tee_ota_info TEE OTA data partition
|
||||
* @param[in] tee_try_part Partition table entry for the new boot partition
|
||||
*
|
||||
* @return ESP_OK on success, or an error code otherwise
|
||||
*/
|
||||
esp_err_t bootloader_utility_tee_set_boot_partition(const esp_partition_pos_t *tee_ota_info, const esp_partition_info_t *tee_try_part);
|
||||
|
||||
/**
|
||||
* @brief Fetch the next TEE partition for update
|
||||
*
|
||||
* @param[in] tee_ota_info TEE OTA data partition
|
||||
*
|
||||
* @return Subtype of the next TEE partition for update, or -1 if an error occurred
|
||||
*/
|
||||
int bootloader_utility_tee_get_next_update_partition(const esp_partition_pos_t *tee_ota_info);
|
||||
|
||||
/**
|
||||
* @brief Mark the current TEE app as valid and cancel update rollback
|
||||
*
|
||||
* @param[in] tee_ota_info TEE OTA data partition
|
||||
*
|
||||
* @return ESP_OK on success, or an error code otherwise
|
||||
*/
|
||||
esp_err_t bootloader_utility_tee_mark_app_valid_and_cancel_rollback(const esp_partition_pos_t *tee_ota_info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -21,6 +21,8 @@ extern "C" {
|
||||
#define PART_SUBTYPE_OTA_FLAG 0x10
|
||||
#define PART_SUBTYPE_OTA_MASK 0x0f
|
||||
#define PART_SUBTYPE_TEST 0x20
|
||||
#define PART_SUBTYPE_TEE_0 0x30
|
||||
#define PART_SUBTYPE_TEE_1 0x31
|
||||
|
||||
#define PART_TYPE_DATA 0x01
|
||||
#define PART_SUBTYPE_DATA_OTA 0x00
|
||||
@ -38,6 +40,9 @@ extern "C" {
|
||||
#define PART_SUBTYPE_PARTITION_TABLE_PRIMARY 0x00
|
||||
#define PART_SUBTYPE_PARTITION_TABLE_OTA 0x01
|
||||
|
||||
#define PART_SUBTYPE_DATA_TEE_OTA 0x90
|
||||
#define PART_SUBTYPE_DATA_TEE_SEC_STORAGE 0x91
|
||||
|
||||
#define PART_TYPE_END 0xff
|
||||
#define PART_SUBTYPE_END 0xff
|
||||
|
||||
|
45
components/bootloader_support/include/esp_tee_ota_utils.h
Normal file
45
components/bootloader_support/include/esp_tee_ota_utils.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_image_format.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// TEE otadata magic is derived from sha256 of "tee_ota" string
|
||||
#define TEE_OTADATA_MAGIC 0x4337e1e1
|
||||
|
||||
/* TEE OTA selection structure (two copies in the TEE OTA data partition) */
|
||||
typedef struct {
|
||||
uint32_t magic; // A magic byte for otadata structure
|
||||
uint8_t version; // OTA image version
|
||||
uint8_t boot_partition; // Default boot partition
|
||||
uint8_t ota_state; // OTA_DATA states for checking operability of the app
|
||||
uint8_t reserved_1; // Reserved field 1
|
||||
uint32_t reserved_2[5]; // Reserved fields 2
|
||||
uint32_t crc; // CRC32 of all fields in the structure
|
||||
} __attribute__((packed)) esp_tee_ota_select_entry_t;
|
||||
|
||||
ESP_STATIC_ASSERT(offsetof(esp_tee_ota_select_entry_t, crc) == sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t));
|
||||
|
||||
// OTA_DATA states for checking operability of the app.
|
||||
typedef enum {
|
||||
ESP_TEE_OTA_IMG_NEW = 0x00U, /*!< Monitor the first boot - the bootloader changes the state to PENDING_VERIFY. */
|
||||
ESP_TEE_OTA_IMG_PENDING_VERIFY = 0x33U, /*!< If encountered during the second boot, the bootloader changes the state to INVALID. */
|
||||
ESP_TEE_OTA_IMG_INVALID = 0x55U, /*!< App was confirmed as workable - can boot and work without limits. */
|
||||
ESP_TEE_OTA_IMG_VALID = 0xAAU, /*!< App was confirmed as non-workable - will not selected to boot at all. */
|
||||
ESP_TEE_OTA_IMG_UNDEFINED = 0xFFU, /*!< Undefined. */
|
||||
} esp_tee_ota_img_states_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -21,11 +21,16 @@ extern "C"
|
||||
#define SPI_ERROR_LOG "spi flash error"
|
||||
|
||||
#define MAX_OTA_SLOTS 16
|
||||
#define MAX_TEE_OTA_SLOTS 2
|
||||
|
||||
typedef struct {
|
||||
esp_partition_pos_t ota_info;
|
||||
esp_partition_pos_t factory;
|
||||
esp_partition_pos_t test;
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
esp_partition_pos_t tee_ota_info;
|
||||
esp_partition_pos_t tee[MAX_TEE_OTA_SLOTS];
|
||||
#endif
|
||||
esp_partition_pos_t ota[MAX_OTA_SLOTS];
|
||||
uint32_t app_count;
|
||||
uint32_t selected_subtype;
|
||||
|
@ -38,6 +38,13 @@ bool bootloader_utility_load_partition_table(bootloader_state_t* bs);
|
||||
*/
|
||||
int bootloader_utility_get_selected_boot_partition(const bootloader_state_t *bs);
|
||||
|
||||
/**
|
||||
* @brief Load and verify the TEE image from the selected partition
|
||||
*
|
||||
* @param bs Bootloader state structure
|
||||
*/
|
||||
void bootloader_utility_load_tee_image(const bootloader_state_t *bs);
|
||||
|
||||
/**
|
||||
* @brief Load the selected partition and start application.
|
||||
*
|
||||
|
@ -52,6 +52,10 @@
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_fault.h"
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
#include "bootloader_utility_tee.h"
|
||||
#endif
|
||||
|
||||
static const char *TAG = "boot";
|
||||
|
||||
/* Reduce literal size for some generic string literals */
|
||||
@ -69,6 +73,21 @@ static void set_cache_and_start_app(uint32_t drom_addr,
|
||||
uint32_t irom_size,
|
||||
const esp_image_metadata_t *data);
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
/* NOTE: Required by other sources for secure boot routine */
|
||||
esp_image_metadata_t tee_data;
|
||||
static uint8_t tee_boot_part = UINT8_MAX;
|
||||
|
||||
static void unpack_load_tee_app(const esp_image_metadata_t *data);
|
||||
static void set_cache_and_load_tee_app(uint32_t drom_addr,
|
||||
uint32_t drom_load_addr,
|
||||
uint32_t drom_size,
|
||||
uint32_t irom_addr,
|
||||
uint32_t irom_load_addr,
|
||||
uint32_t irom_size,
|
||||
const esp_image_metadata_t *data);
|
||||
#endif
|
||||
|
||||
esp_err_t bootloader_common_read_otadata(const esp_partition_pos_t *ota_info, esp_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
const esp_ota_select_entry_t *ota_select_map;
|
||||
@ -162,6 +181,13 @@ bool bootloader_utility_load_partition_table(bootloader_state_t *bs)
|
||||
bs->test = partition->pos;
|
||||
partition_usage = "test app";
|
||||
break;
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
case PART_SUBTYPE_TEE_0: /* TEE binary */
|
||||
case PART_SUBTYPE_TEE_1:
|
||||
bs->tee[partition->subtype & 0x01] = partition->pos;
|
||||
partition_usage = "TEE app";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* OTA binary */
|
||||
if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
|
||||
@ -195,6 +221,15 @@ bool bootloader_utility_load_partition_table(bootloader_state_t *bs)
|
||||
esp_efuse_init_virtual_mode_in_flash(partition->pos.offset, partition->pos.size);
|
||||
#endif
|
||||
break;
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
case PART_SUBTYPE_DATA_TEE_OTA: /* TEE ota data */
|
||||
bs->tee_ota_info = partition->pos;
|
||||
partition_usage = "TEE OTA data";
|
||||
break;
|
||||
case PART_SUBTYPE_DATA_TEE_SEC_STORAGE: /* TEE secure storage */
|
||||
partition_usage = "TEE secure storage";
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
partition_usage = "Unknown data";
|
||||
break;
|
||||
@ -518,6 +553,29 @@ void bootloader_utility_load_boot_image_from_deep_sleep(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
void bootloader_utility_load_tee_image(const bootloader_state_t *bs)
|
||||
{
|
||||
esp_err_t err = ESP_FAIL;
|
||||
uint8_t tee_active_part = bootloader_utility_tee_get_boot_partition(&bs->tee_ota_info);
|
||||
if (tee_active_part != PART_SUBTYPE_TEE_0 && tee_active_part != PART_SUBTYPE_TEE_1) {
|
||||
ESP_LOGE(TAG, "Failed to find valid TEE app");
|
||||
bootloader_reset();
|
||||
}
|
||||
|
||||
uint8_t tee_part_idx = tee_active_part & 0x01;
|
||||
const esp_partition_pos_t *tee_active_part_pos = &bs->tee[tee_part_idx];
|
||||
err = bootloader_load_image(tee_active_part_pos, &tee_data);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to load TEE app");
|
||||
bootloader_reset();
|
||||
}
|
||||
tee_boot_part = tee_part_idx;
|
||||
|
||||
ESP_LOGI(TAG, "Loaded TEE app from partition at offset 0x%"PRIx32, tee_active_part_pos->offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define TRY_LOG_FORMAT "Trying partition index %d offs 0x%"PRIx32" size 0x%"PRIx32
|
||||
|
||||
void bootloader_utility_load_boot_image(const bootloader_state_t *bs, int start_index)
|
||||
@ -856,6 +914,127 @@ static bool s_flash_seg_needs_map(uint32_t vaddr)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* TODO: [IDF-11689] Unify the TEE-specific app loading implementation with
|
||||
* the existing app loading implementation.
|
||||
*/
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
static void unpack_load_tee_app(const esp_image_metadata_t *data)
|
||||
{
|
||||
/**
|
||||
* note:
|
||||
* On chips with shared D/I external vaddr, we don't divide them into either D or I,
|
||||
* as essentially they are the same.
|
||||
* We integrate all the hardware difference into this `unpack_load_app` function.
|
||||
*/
|
||||
uint32_t rom_addr[2] = {};
|
||||
uint32_t rom_load_addr[2] = {};
|
||||
uint32_t rom_size[2] = {};
|
||||
int rom_index = 0; //shall not exceed 2
|
||||
|
||||
// Find DROM & IROM addresses, to configure MMU mappings
|
||||
for (int i = 0; i < data->image.segment_count; i++) {
|
||||
const esp_image_segment_header_t *header = &data->segments[i];
|
||||
const uint32_t addr = header->load_addr;
|
||||
|
||||
//`SOC_DROM_LOW` and `SOC_DROM_HIGH` are the same as `SOC_IROM_LOW` and `SOC_IROM_HIGH`, reasons are in above `note`
|
||||
if ((addr >= SOC_DROM_LOW && addr < SOC_DROM_HIGH)
|
||||
#if SOC_MMU_PER_EXT_MEM_TARGET
|
||||
|| (addr >= SOC_EXTRAM_LOW && addr < SOC_EXTRAM_HIGH)
|
||||
#endif
|
||||
) {
|
||||
/**
|
||||
* D/I are shared, but there should not be a third segment on flash/psram
|
||||
*/
|
||||
assert(rom_index < 2);
|
||||
rom_addr[rom_index] = data->segment_data[i];
|
||||
rom_load_addr[rom_index] = header->load_addr;
|
||||
rom_size[rom_index] = header->data_len;
|
||||
rom_index++;
|
||||
}
|
||||
}
|
||||
assert(rom_index == 2);
|
||||
|
||||
ESP_EARLY_LOGD(TAG, "calling set_cache_and_start_tee_app");
|
||||
set_cache_and_load_tee_app(rom_addr[0],
|
||||
rom_load_addr[0],
|
||||
rom_size[0],
|
||||
rom_addr[1],
|
||||
rom_load_addr[1],
|
||||
rom_size[1],
|
||||
data);
|
||||
}
|
||||
|
||||
static void set_cache_and_load_tee_app(
|
||||
uint32_t drom_addr,
|
||||
uint32_t drom_load_addr,
|
||||
uint32_t drom_size,
|
||||
uint32_t irom_addr,
|
||||
uint32_t irom_load_addr,
|
||||
uint32_t irom_size,
|
||||
const esp_image_metadata_t *data)
|
||||
{
|
||||
uint32_t drom_load_addr_aligned = 0, drom_addr_aligned = 0;
|
||||
uint32_t irom_load_addr_aligned = 0, irom_addr_aligned = 0;
|
||||
uint32_t actual_mapped_len = 0;
|
||||
|
||||
const uint32_t mmu_page_size = data->mmu_page_size;
|
||||
#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
|
||||
|
||||
if (drom_addr != 0) {
|
||||
drom_load_addr_aligned = drom_load_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
|
||||
drom_addr_aligned = drom_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
|
||||
ESP_EARLY_LOGV(TAG, "TEE rodata starts from paddr=0x%08x, vaddr=0x%08x, size=0x%x", 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.
|
||||
if (s_flash_seg_needs_map(drom_load_addr_aligned)) {
|
||||
mmu_hal_map_region(0, MMU_TARGET_FLASH0, drom_load_addr_aligned, drom_addr_aligned, drom_size, &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
|
||||
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, drom_load_addr_aligned, actual_mapped_len);
|
||||
}
|
||||
|
||||
if (irom_addr != 0) {
|
||||
irom_load_addr_aligned = irom_load_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
|
||||
irom_addr_aligned = irom_addr & MMU_FLASH_MASK_FROM_VAL(mmu_page_size);
|
||||
ESP_EARLY_LOGV(TAG, "TEE text starts from paddr=0x%08x, vaddr=0x%08x, size=0x%x", 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;
|
||||
|
||||
if (s_flash_seg_needs_map(irom_load_addr_aligned)) {
|
||||
mmu_hal_map_region(0, MMU_TARGET_FLASH0, irom_load_addr_aligned, irom_addr_aligned, irom_size, &actual_mapped_len);
|
||||
ESP_EARLY_LOGV(TAG, "after mapping text, starting from paddr=0x%08" PRIx32 " and vaddr=0x%08" PRIx32 ", 0x%" PRIx32 " bytes are mapped", irom_addr_aligned, irom_load_addr_aligned, actual_mapped_len);
|
||||
}
|
||||
}
|
||||
|
||||
if (drom_load_addr_aligned != 0) {
|
||||
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, drom_load_addr_aligned, drom_size);
|
||||
cache_ll_l1_enable_bus(0, bus_mask);
|
||||
}
|
||||
|
||||
if (irom_load_addr_aligned != 0) {
|
||||
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(0, irom_load_addr_aligned, irom_size);
|
||||
cache_ll_l1_enable_bus(0, bus_mask);
|
||||
}
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
if (drom_load_addr_aligned != 0) {
|
||||
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(1, drom_load_addr_aligned, drom_size);
|
||||
cache_ll_l1_enable_bus(1, bus_mask);
|
||||
}
|
||||
|
||||
if (irom_load_addr_aligned != 0) {
|
||||
cache_bus_mask_t bus_mask = cache_ll_l1_get_bus(1, irom_load_addr_aligned, irom_size);
|
||||
cache_ll_l1_enable_bus(1, bus_mask);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // CONFIG_SECURE_ENABLE_TEE
|
||||
|
||||
static void set_cache_and_start_app(
|
||||
uint32_t drom_addr,
|
||||
uint32_t drom_load_addr,
|
||||
@ -943,6 +1122,11 @@ static void set_cache_and_start_app(
|
||||
cache_ll_l1_enable_bus(1, bus_mask);
|
||||
#endif
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
//----------------------Unpacking and loading the TEE app----------------
|
||||
unpack_load_tee_app(&tee_data);
|
||||
#endif
|
||||
|
||||
//----------------------Enable Cache----------------
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
// Application will need to do Cache_Flush(1) and Cache_Read_Enable(1)
|
||||
@ -953,12 +1137,26 @@ static void set_cache_and_start_app(
|
||||
|
||||
ESP_LOGD(TAG, "start: 0x%08"PRIx32, entry_addr);
|
||||
bootloader_atexit();
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
ESP_LOGI(TAG, "Current privilege level - %d", esp_cpu_get_curr_privilege_level());
|
||||
/* NOTE: TEE Initialization and REE Switch
|
||||
* This call will not return back. After TEE initialization,
|
||||
* it will switch to the REE and execute the user application.
|
||||
*/
|
||||
typedef void (*esp_tee_init_t)(uint32_t, uint32_t, uint8_t) __attribute__((noreturn));
|
||||
esp_tee_init_t esp_tee_init = ((esp_tee_init_t) tee_data.image.entry_addr);
|
||||
|
||||
ESP_LOGI(TAG, "Starting TEE: Entry point - 0x%"PRIx32, (uint32_t)esp_tee_init);
|
||||
(*esp_tee_init)(entry_addr, drom_addr, tee_boot_part);
|
||||
#else
|
||||
typedef void (*entry_t)(void) __attribute__((noreturn));
|
||||
entry_t entry = ((entry_t) entry_addr);
|
||||
|
||||
// TODO: we have used quite a bit of stack at this point.
|
||||
// use "movsp" instruction to reset stack back to where ROM stack starts.
|
||||
(*entry)();
|
||||
#endif
|
||||
}
|
||||
|
||||
void bootloader_reset(void)
|
||||
|
260
components/bootloader_support/src/bootloader_utility_tee.c
Normal file
260
components/bootloader_support/src/bootloader_utility_tee.c
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_rom_crc.h"
|
||||
|
||||
#include "hal/efuse_hal.h"
|
||||
|
||||
#include "esp_image_format.h"
|
||||
#include "bootloader_config.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
|
||||
#include "bootloader_utility.h"
|
||||
#include "bootloader_utility_tee.h"
|
||||
#include "esp_tee_ota_utils.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char *TAG = "boot_tee";
|
||||
|
||||
static esp_err_t write_tee_otadata_sector(esp_tee_ota_select_entry_t *tee_otadata, uint32_t offset)
|
||||
{
|
||||
if (tee_otadata == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_err_t err = bootloader_flash_erase_sector(offset / FLASH_SECTOR_SIZE);
|
||||
if (err == ESP_OK) {
|
||||
bool write_encrypted = false;
|
||||
#if !CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH
|
||||
write_encrypted = efuse_hal_flash_encryption_enabled();
|
||||
#endif
|
||||
err = bootloader_flash_write(offset, tee_otadata, sizeof(esp_tee_ota_select_entry_t), write_encrypted);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write otadata sector, 0x%x", err);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t read_tee_otadata(const esp_partition_pos_t *tee_ota_info, esp_tee_ota_select_entry_t *two_otadata)
|
||||
{
|
||||
if (tee_ota_info == NULL || two_otadata == NULL || tee_ota_info->offset == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (tee_ota_info->size < 2 * FLASH_SECTOR_SIZE) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "TEE OTA data offset 0x%"PRIx32, tee_ota_info->offset);
|
||||
|
||||
const esp_tee_ota_select_entry_t *ota_select_map = bootloader_mmap(tee_ota_info->offset, tee_ota_info->size);
|
||||
if (!ota_select_map) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%"PRIx32", 0x%"PRIx32") failed", tee_ota_info->offset, tee_ota_info->size);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
memcpy(&two_otadata[0], (uint8_t *)ota_select_map, sizeof(esp_tee_ota_select_entry_t));
|
||||
memcpy(&two_otadata[1], (uint8_t *)ota_select_map + FLASH_SECTOR_SIZE, sizeof(esp_tee_ota_select_entry_t));
|
||||
|
||||
bootloader_munmap(ota_select_map);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t write_tee_otadata(esp_tee_ota_select_entry_t *tee_otadata, const esp_partition_pos_t *tee_ota_info)
|
||||
{
|
||||
esp_err_t err = write_tee_otadata_sector(tee_otadata, tee_ota_info->offset);
|
||||
if (err == ESP_OK) {
|
||||
err = write_tee_otadata_sector(tee_otadata, tee_ota_info->offset + FLASH_SECTOR_SIZE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to update otadata sector, 0x%x", err);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t get_valid_tee_otadata(const esp_partition_pos_t *tee_ota_info, esp_tee_ota_select_entry_t *tee_otadata)
|
||||
{
|
||||
esp_tee_ota_select_entry_t two_otadata[2] = {0};
|
||||
if (read_tee_otadata(tee_ota_info, two_otadata) != ESP_OK) {
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_tee_ota_select_entry_t blank_otadata;
|
||||
memset(&blank_otadata, 0xff, sizeof(esp_tee_ota_select_entry_t));
|
||||
|
||||
// Check if the contents of both the otadata sectors match
|
||||
bool sectors_match = (memcmp(&two_otadata[0], &two_otadata[1], sizeof(esp_tee_ota_select_entry_t)) == 0);
|
||||
if (sectors_match) {
|
||||
if (memcmp(&two_otadata[0], &blank_otadata, sizeof(esp_tee_ota_select_entry_t)) != 0) {
|
||||
uint32_t crc = esp_rom_crc32_le(0, (uint8_t const *)two_otadata, (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
|
||||
if (two_otadata[0].magic != TEE_OTADATA_MAGIC || crc != two_otadata[0].crc) {
|
||||
ESP_LOGE(TAG, "TEE otadata[0] magic or CRC verification failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
memcpy(tee_otadata, &two_otadata[0], sizeof(esp_tee_ota_select_entry_t));
|
||||
ESP_LOGV(TAG, "Both tee_otadata sectors are the same");
|
||||
} else {
|
||||
uint32_t crc_otadata0 = esp_rom_crc32_le(0, (uint8_t const *)&two_otadata[0], (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
|
||||
uint32_t crc_otadata1 = esp_rom_crc32_le(0, (uint8_t const *)&two_otadata[1], (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
|
||||
|
||||
if (crc_otadata0 == two_otadata[0].crc) {
|
||||
ESP_LOGV(TAG, "Second tee_otadata sector is invalid - copying contents from first sector");
|
||||
// Copy contents of first tee_otadata sector into second
|
||||
write_tee_otadata_sector(&two_otadata[0], tee_ota_info->offset + FLASH_SECTOR_SIZE);
|
||||
memcpy(tee_otadata, &two_otadata[0], sizeof(esp_tee_ota_select_entry_t));
|
||||
} else if (crc_otadata1 == two_otadata[1].crc) {
|
||||
ESP_LOGV(TAG, "First tee_otadata sector is invalid - copying contents from second sector");
|
||||
// Copy contents of second tee_otadata sector into first
|
||||
write_tee_otadata_sector(&two_otadata[1], tee_ota_info->offset);
|
||||
memcpy(tee_otadata, &two_otadata[1], sizeof(esp_tee_ota_select_entry_t));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Both tee_otadata sectors are invalid!");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t update_tee_otadata(const esp_partition_pos_t *tee_ota_info, uint8_t boot_partition, uint8_t ota_state)
|
||||
{
|
||||
esp_tee_ota_select_entry_t otadata = {
|
||||
.magic = TEE_OTADATA_MAGIC,
|
||||
.boot_partition = boot_partition,
|
||||
.ota_state = ota_state,
|
||||
};
|
||||
otadata.crc = esp_rom_crc32_le(0, (uint8_t const *)&otadata, (sizeof(esp_tee_ota_select_entry_t) - sizeof(uint32_t)));
|
||||
return write_tee_otadata(&otadata, tee_ota_info);
|
||||
}
|
||||
|
||||
int bootloader_utility_tee_get_boot_partition(const esp_partition_pos_t *tee_ota_info)
|
||||
{
|
||||
esp_tee_ota_select_entry_t otadata = {}, blank_otadata;
|
||||
const int default_tee_app_slot = PART_SUBTYPE_TEE_0;
|
||||
|
||||
esp_err_t err = get_valid_tee_otadata(tee_ota_info, &otadata);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
ESP_LOGV(TAG, "otadata partition not found, booting from first partition");
|
||||
return default_tee_app_slot;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to get valid otadata, 0x%x", err);
|
||||
return -1;
|
||||
}
|
||||
memset(&blank_otadata, 0xff, sizeof(esp_tee_ota_select_entry_t));
|
||||
if (!memcmp(&blank_otadata, &otadata, sizeof(esp_tee_ota_select_entry_t))) {
|
||||
ESP_LOGV(TAG, "otadata partition empty, booting from first partition");
|
||||
/* NOTE: The first TEE partition will always be valid as it is flashed manually */
|
||||
if (update_tee_otadata(tee_ota_info, default_tee_app_slot, ESP_TEE_OTA_IMG_VALID) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Failed to setup TEE otadata as per the first partition!");
|
||||
}
|
||||
return default_tee_app_slot;
|
||||
}
|
||||
|
||||
int boot_partition = 0;
|
||||
|
||||
#if BOOTLOADER_BUILD
|
||||
switch(otadata.ota_state) {
|
||||
case ESP_TEE_OTA_IMG_NEW:
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image state: NEW");
|
||||
boot_partition = otadata.boot_partition;
|
||||
if (update_tee_otadata(tee_ota_info, otadata.boot_partition, ESP_TEE_OTA_IMG_PENDING_VERIFY) != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case ESP_TEE_OTA_IMG_UNDEFINED:
|
||||
case ESP_TEE_OTA_IMG_PENDING_VERIFY:
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image state: PENDING_VERIFY/UNDEFINED");
|
||||
boot_partition = (otadata.boot_partition == PART_SUBTYPE_TEE_0) ? PART_SUBTYPE_TEE_1 : PART_SUBTYPE_TEE_0;
|
||||
if (update_tee_otadata(tee_ota_info, boot_partition, ESP_TEE_OTA_IMG_INVALID) != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case ESP_TEE_OTA_IMG_INVALID:
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image state: INVALID");
|
||||
bootloader_reset();
|
||||
break;
|
||||
case ESP_TEE_OTA_IMG_VALID:
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image state: VALID");
|
||||
boot_partition = otadata.boot_partition;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
boot_partition = otadata.boot_partition;
|
||||
#endif
|
||||
|
||||
return boot_partition;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_utility_tee_set_boot_partition(const esp_partition_pos_t *tee_ota_info, const esp_partition_info_t *tee_try_part)
|
||||
{
|
||||
if (tee_ota_info == NULL || tee_try_part == NULL) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (tee_try_part->subtype != PART_SUBTYPE_TEE_0 && tee_try_part->subtype != PART_SUBTYPE_TEE_1) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
esp_image_metadata_t data = {};
|
||||
if (esp_image_verify(ESP_IMAGE_VERIFY, &tee_try_part->pos, &data) != ESP_OK) {
|
||||
return ESP_ERR_IMAGE_INVALID;
|
||||
}
|
||||
|
||||
return update_tee_otadata(tee_ota_info, tee_try_part->subtype, ESP_TEE_OTA_IMG_NEW);
|
||||
}
|
||||
|
||||
int bootloader_utility_tee_get_next_update_partition(const esp_partition_pos_t *tee_ota_info)
|
||||
{
|
||||
esp_tee_ota_select_entry_t otadata = {}, blank_otadata;
|
||||
const int default_tee_next_app_slot = PART_SUBTYPE_TEE_1;
|
||||
|
||||
esp_err_t err = get_valid_tee_otadata(tee_ota_info, &otadata);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to get valid otadata, 0x%x", err);
|
||||
return -1;
|
||||
}
|
||||
memset(&blank_otadata, 0xff, sizeof(esp_tee_ota_select_entry_t));
|
||||
if (!memcmp(&blank_otadata, &otadata, sizeof(esp_tee_ota_select_entry_t))) {
|
||||
return default_tee_next_app_slot;
|
||||
}
|
||||
|
||||
return (otadata.boot_partition == PART_SUBTYPE_TEE_0) ? PART_SUBTYPE_TEE_1 : PART_SUBTYPE_TEE_0;
|
||||
}
|
||||
|
||||
esp_err_t bootloader_utility_tee_mark_app_valid_and_cancel_rollback(const esp_partition_pos_t *tee_ota_info)
|
||||
{
|
||||
esp_tee_ota_select_entry_t two_otadata[2];
|
||||
|
||||
esp_err_t err = read_tee_otadata(tee_ota_info, two_otadata);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to fetch TEE otadata!");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (two_otadata[0].ota_state == ESP_TEE_OTA_IMG_VALID) {
|
||||
ESP_LOGD(TAG, "TEE otadata - Current image already has been marked VALID");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
int tee_app_slot = bootloader_utility_tee_get_boot_partition(tee_ota_info);
|
||||
return update_tee_otadata(tee_ota_info, (uint8_t)tee_app_slot, ESP_TEE_OTA_IMG_VALID);
|
||||
}
|
@ -23,6 +23,10 @@
|
||||
|
||||
#ifdef CONFIG_SECURE_BOOT_V2_ENABLED
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
extern esp_image_metadata_t tee_data;
|
||||
#endif
|
||||
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
static const char *TAG = "secure_boot_v2";
|
||||
|
||||
@ -268,6 +272,28 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
ESP_LOGW(TAG, "App has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?", app_key_digests.num_digests, boot_key_digests.num_digests);
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
/* Generate the TEE public key digests */
|
||||
bool tee_match = false;
|
||||
esp_image_sig_public_key_digests_t tee_key_digests = {0};
|
||||
|
||||
ret = s_calculate_image_public_key_digests(tee_data.start_addr, tee_data.image_len - SIG_BLOCK_PADDING, &tee_key_digests);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "TEE signature block is invalid.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tee_key_digests.num_digests == 0) {
|
||||
ESP_LOGE(TAG, "No valid TEE signature blocks found.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%d signature block(s) found appended to the tee.", tee_key_digests.num_digests);
|
||||
if (tee_key_digests.num_digests > boot_key_digests.num_digests) {
|
||||
ESP_LOGW(TAG, "TEE has %d signature blocks but bootloader only has %d. Some keys missing from bootloader?", tee_key_digests.num_digests, boot_key_digests.num_digests);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Confirm if at least one public key from the application matches a public key in the bootloader
|
||||
(Also, ensure if that public revoke bit is not set for the matched key) */
|
||||
bool match = false;
|
||||
@ -285,6 +311,18 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < tee_key_digests.num_digests; j++) {
|
||||
if (!memcmp(boot_key_digests.key_digests[i], tee_key_digests.key_digests[j], ESP_SECURE_BOOT_DIGEST_LEN)) {
|
||||
ESP_LOGI(TAG, "TEE key(%d) matches with bootloader key(%d).", j, i);
|
||||
tee_match = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (match == false) {
|
||||
@ -292,6 +330,13 @@ static esp_err_t check_and_generate_secure_boot_keys(const esp_image_metadata_t
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
#if CONFIG_SECURE_ENABLE_TEE
|
||||
if (tee_match == false) {
|
||||
ESP_LOGE(TAG, "No TEE key digest matches the bootloader key digest.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_EFUSE_REVOKE_BOOT_KEY_DIGESTS
|
||||
/* Revoke the empty signature blocks */
|
||||
if (boot_key_digests.num_digests < SECURE_BOOT_NUM_BLOCKS) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user