mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
bootloader: Calculate SHA256 hash of image on every boot
Makes app image booting more reliable (256-bit rather than 8-bit verification.) Some measurements, time to boot a 655KB app.bin file and run to app_main() execution. (All for rev 1 silicon, ie no 340ms spurious WDT delay.) 80MHz QIO mode: before = 300ms after = 140ms 40MHz DIO mode: before = 712ms after = 577ms 40MHz DIO mode, secure boot enabled before = 1380ms after = 934ms (Secure boot involves two ECC signature verifications (partition table, app) that take approx 300ms each with 80MHz CPU.)
This commit is contained in:
parent
caaa29c676
commit
17adb40ca8
@ -241,7 +241,7 @@ esp_err_t esp_ota_end(esp_ota_handle_t handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||||
ret = esp_secure_boot_verify_signature(it->part->address, data.image_length);
|
ret = esp_secure_boot_verify_signature(it->part->address, data.image_len);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
ret = ESP_ERR_OTA_VALIDATE_FAILED;
|
ret = ESP_ERR_OTA_VALIDATE_FAILED;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -385,7 +385,7 @@ esp_err_t esp_ota_set_boot_partition(const esp_partition_t *partition)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||||
esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_length);
|
esp_err_t ret = esp_secure_boot_verify_signature(partition->address, data.image_len);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
return ESP_ERR_OTA_VALIDATE_FAILED;
|
return ESP_ERR_OTA_VALIDATE_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -87,11 +87,15 @@ void call_start_cpu0()
|
|||||||
cpu_configure_region_protection();
|
cpu_configure_region_protection();
|
||||||
|
|
||||||
/* Sanity check that static RAM is after the stack */
|
/* Sanity check that static RAM is after the stack */
|
||||||
|
#ifndef NDEBUG
|
||||||
|
{
|
||||||
int *sp = get_sp();
|
int *sp = get_sp();
|
||||||
assert(&_bss_start <= &_bss_end);
|
assert(&_bss_start <= &_bss_end);
|
||||||
assert(&_data_start <= &_data_end);
|
assert(&_data_start <= &_data_end);
|
||||||
assert(sp < &_bss_start);
|
assert(sp < &_bss_start);
|
||||||
assert(sp < &_data_start);
|
assert(sp < &_data_start);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//Clear bss
|
//Clear bss
|
||||||
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start));
|
||||||
@ -425,24 +429,13 @@ static void unpack_load_app(const esp_partition_pos_t* partition)
|
|||||||
esp_image_metadata_t data;
|
esp_image_metadata_t data;
|
||||||
|
|
||||||
/* TODO: load the app image as part of OTA boot decision, so can fallback if loading fails */
|
/* TODO: load the app image as part of OTA boot decision, so can fallback if loading fails */
|
||||||
|
/* Loading the image here also includes secure boot verification */
|
||||||
err = esp_image_load(ESP_IMAGE_LOAD, partition, &data);
|
err = esp_image_load(ESP_IMAGE_LOAD, partition, &data);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
|
ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
|
||||||
if (esp_secure_boot_enabled()) {
|
|
||||||
ESP_LOGI(TAG, "Verifying app signature @ 0x%x (length 0x%x)", partition->offset, data.image_length);
|
|
||||||
err = esp_secure_boot_verify_signature(partition->offset, data.image_length);
|
|
||||||
if (err != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "App image @ 0x%x failed signature verification (%d)", partition->offset, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ESP_LOGD(TAG, "App signature is valid");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint32_t drom_addr = 0;
|
uint32_t drom_addr = 0;
|
||||||
uint32_t drom_load_addr = 0;
|
uint32_t drom_load_addr = 0;
|
||||||
uint32_t drom_size = 0;
|
uint32_t drom_size = 0;
|
||||||
@ -497,6 +490,14 @@ static void set_cache_and_start_app(
|
|||||||
ESP_LOGD(TAG, "configure drom and irom and start");
|
ESP_LOGD(TAG, "configure drom and irom and start");
|
||||||
Cache_Read_Disable( 0 );
|
Cache_Read_Disable( 0 );
|
||||||
Cache_Flush( 0 );
|
Cache_Flush( 0 );
|
||||||
|
|
||||||
|
/* Clear the MMU entries that are already set up,
|
||||||
|
so the new app only has the mappings it creates.
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < DPORT_FLASH_MMU_TABLE_SIZE; i++) {
|
||||||
|
DPORT_PRO_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
uint32_t drom_page_count = (drom_size + 64*1024 - 1) / (64*1024); // round up to 64k
|
||||||
ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count );
|
ESP_LOGV(TAG, "d mmu set paddr=%08x vaddr=%08x size=%d n=%d", drom_addr & 0xffff0000, drom_load_addr & 0xffff0000, drom_size, drom_page_count );
|
||||||
int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
int rc = cache_flash_mmu_set( 0, 0, drom_load_addr & 0xffff0000, drom_addr & 0xffff0000, 64, drom_page_count );
|
||||||
|
@ -59,12 +59,27 @@ typedef enum {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t magic;
|
uint8_t magic;
|
||||||
uint8_t segment_count;
|
uint8_t segment_count;
|
||||||
uint8_t spi_mode; /* flash read mode (esp_image_spi_mode_t as uint8_t) */
|
/* flash read mode (esp_image_spi_mode_t as uint8_t) */
|
||||||
uint8_t spi_speed: 4; /* flash frequency (esp_image_spi_freq_t as uint8_t) */
|
uint8_t spi_mode;
|
||||||
uint8_t spi_size: 4; /* flash chip size (esp_image_flash_size_t as uint8_t) */
|
/* flash frequency (esp_image_spi_freq_t as uint8_t) */
|
||||||
|
uint8_t spi_speed: 4;
|
||||||
|
/* flash chip size (esp_image_flash_size_t as uint8_t) */
|
||||||
|
uint8_t spi_size: 4;
|
||||||
uint32_t entry_addr;
|
uint32_t entry_addr;
|
||||||
uint8_t extra_header[16]; /* ESP32 additional header, unused by second bootloader */
|
/* WP pin when SPI pins set via efuse (read by ROM bootloader, the IDF bootloader uses software to configure the WP
|
||||||
} esp_image_header_t;
|
* pin and sets this field to 0xEE=disabled) */
|
||||||
|
uint8_t wp_pin;
|
||||||
|
/* Drive settings for the SPI flash pins (read by ROM bootloader) */
|
||||||
|
uint8_t spi_pin_drv[3];
|
||||||
|
/* Reserved bytes in ESP32 additional header space, currently unused */
|
||||||
|
uint8_t reserved[11];
|
||||||
|
/* If 1, a SHA256 digest "simple hash" (of the entire image) is appended after the checksum. Included in image length. This digest
|
||||||
|
* is separate to secure boot and only used for detecting corruption. For secure boot signed images, the signature
|
||||||
|
* is appended after this (and the simple hash is included in the signed data). */
|
||||||
|
uint8_t hash_appended;
|
||||||
|
} __attribute__((packed)) esp_image_header_t;
|
||||||
|
|
||||||
|
_Static_assert(sizeof(esp_image_header_t) == 24, "binary image header should be 24 bytes");
|
||||||
|
|
||||||
/* Header of binary image segment */
|
/* Header of binary image segment */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -97,18 +112,23 @@ typedef enum {
|
|||||||
*
|
*
|
||||||
* If encryption is enabled, data will be transparently decrypted.
|
* If encryption is enabled, data will be transparently decrypted.
|
||||||
*
|
*
|
||||||
|
* @param mode Mode of operation (verify, silent verify, or load).
|
||||||
* @param part Partition to load the app from.
|
* @param part Partition to load the app from.
|
||||||
* @param[out] data Pointer to the metadata structure to be filled in by this function. 'start_addr' member should be set (to the start address of the image.) Other fields will all be initialised by this function.
|
* @param[inout] data Pointer to the image metadata structure which is be filled in by this function. 'start_addr' member should be set (to the start address of the image.) Other fields will all be initialised by this function.
|
||||||
* @param log_errors Log errors reading the image.
|
|
||||||
*
|
*
|
||||||
* Image validation checks:
|
* Image validation checks:
|
||||||
* - Magic byte
|
* - Magic byte.
|
||||||
* - Partition smaller than 16MB
|
* - Partition smaller than 16MB.
|
||||||
* - All segments & image fit in partition
|
* - All segments & image fit in partition.
|
||||||
* - 8 bit image checksum is valid
|
* - 8 bit image checksum is valid.
|
||||||
* - (Signature) if signature verification is enabled
|
* - SHA-256 of image is valid (if image has this appended).
|
||||||
|
* - (Signature) if signature verification is enabled.
|
||||||
*
|
*
|
||||||
* @return ESP_OK if image metadata was loaded successfully, ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image appears invalid, ESP_ERR_INVALID_ARG if the data pointer is invalid.
|
* @return
|
||||||
|
* - ESP_OK if verify or load was successful
|
||||||
|
* - ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs
|
||||||
|
* - ESP_ERR_IMAGE_INVALID if the image appears invalid.
|
||||||
|
* - ESP_ERR_INVALID_ARG if the partition or data pointers are invalid.
|
||||||
*/
|
*/
|
||||||
esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data);
|
esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data);
|
||||||
|
|
||||||
|
@ -77,12 +77,22 @@ esp_err_t esp_secure_boot_permanently_enable(void);
|
|||||||
*/
|
*/
|
||||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length);
|
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length);
|
||||||
|
|
||||||
|
/** @brief Verify the secure boot signature block (deterministic ECDSA w/ SHA256) based on the SHA256 hash of some data.
|
||||||
|
*
|
||||||
|
* Similar to esp_secure_boot_verify_signature(), but can be used when the digest is precalculated.
|
||||||
|
* @param sig_block Pointer to signature block data
|
||||||
|
* @param image_digest Pointer to 32 byte buffer holding SHA-256 hash.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
/** @brief Secure boot verification block, on-flash data format. */
|
/** @brief Secure boot verification block, on-flash data format. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint8_t signature[64];
|
uint8_t signature[64];
|
||||||
} esp_secure_boot_sig_block_t;
|
} esp_secure_boot_sig_block_t;
|
||||||
|
|
||||||
|
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest);
|
||||||
|
|
||||||
#define FLASH_OFFS_SECURE_BOOT_IV_DIGEST 0
|
#define FLASH_OFFS_SECURE_BOOT_IV_DIGEST 0
|
||||||
|
|
||||||
/** @brief Secure boot IV+digest header */
|
/** @brief Secure boot IV+digest header */
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -43,8 +43,12 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
|
|||||||
{
|
{
|
||||||
assert(handle != NULL);
|
assert(handle != NULL);
|
||||||
mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)handle;
|
mbedtls_sha256_context *ctx = (mbedtls_sha256_context *)handle;
|
||||||
|
if (digest != NULL) {
|
||||||
mbedtls_sha256_finish(ctx, digest);
|
mbedtls_sha256_finish(ctx, digest);
|
||||||
}
|
}
|
||||||
|
mbedtls_sha256_free(ctx);
|
||||||
|
free(handle);
|
||||||
|
}
|
||||||
|
|
||||||
#else // Bootloader version
|
#else // Bootloader version
|
||||||
|
|
||||||
@ -58,6 +62,8 @@ static uint32_t words_hashed;
|
|||||||
|
|
||||||
// Words per SHA256 block
|
// Words per SHA256 block
|
||||||
static const size_t BLOCK_WORDS = (64/sizeof(uint32_t));
|
static const size_t BLOCK_WORDS = (64/sizeof(uint32_t));
|
||||||
|
// Words in final SHA256 digest
|
||||||
|
static const size_t DIGEST_WORDS = (32/sizeof(uint32_t));
|
||||||
|
|
||||||
bootloader_sha256_handle_t bootloader_sha256_start()
|
bootloader_sha256_handle_t bootloader_sha256_start()
|
||||||
{
|
{
|
||||||
@ -116,22 +122,28 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
|
|||||||
{
|
{
|
||||||
assert(handle != NULL);
|
assert(handle != NULL);
|
||||||
|
|
||||||
uint32_t data_words = words_hashed;
|
if (digest == NULL) {
|
||||||
ets_printf("Padding from %d bytes\n", data_words * 4);
|
return; // We'd free resources here, but there are none to free
|
||||||
|
}
|
||||||
|
|
||||||
// Pad to a 60 byte long block loaded in the engine
|
uint32_t data_words = words_hashed;
|
||||||
// (normally end of block is a 64-bit length, but we know
|
|
||||||
// the upper 32 bits will be zeroes.)
|
// Pad to a 55 byte long block loaded in the engine
|
||||||
|
// (leaving 1 byte 0x80 plus variable padding plus 8 bytes of length,
|
||||||
|
// to fill a 64 byte block.)
|
||||||
int block_bytes = (words_hashed % BLOCK_WORDS) * 4;
|
int block_bytes = (words_hashed % BLOCK_WORDS) * 4;
|
||||||
int pad_bytes = 60 - block_bytes;
|
int pad_bytes = 55 - block_bytes;
|
||||||
if (pad_bytes < 0) {
|
if (pad_bytes < 0) {
|
||||||
pad_bytes += 64;
|
pad_bytes += 64;
|
||||||
}
|
}
|
||||||
static const uint8_t padding[64] = { 0x80, 0, };
|
static const uint8_t padding[64] = { 0x80, 0, };
|
||||||
|
|
||||||
|
pad_bytes += 5; // 1 byte for 0x80 plus first 4 bytes of the 64-bit length
|
||||||
|
assert(pad_bytes % 4 == 0); // should be, as (block_bytes % 4 == 0)
|
||||||
|
|
||||||
bootloader_sha256_data(handle, padding, pad_bytes);
|
bootloader_sha256_data(handle, padding, pad_bytes);
|
||||||
|
|
||||||
assert(words_hashed % BLOCK_WORDS == 56/4);
|
assert(words_hashed % BLOCK_WORDS == 60/4); // 32-bits left in block
|
||||||
|
|
||||||
// Calculate 32-bit length for final 32 bits of data
|
// Calculate 32-bit length for final 32 bits of data
|
||||||
uint32_t bit_count = __builtin_bswap32( data_words * 32 );
|
uint32_t bit_count = __builtin_bswap32( data_words * 32 );
|
||||||
@ -139,15 +151,13 @@ void bootloader_sha256_finish(bootloader_sha256_handle_t handle, uint8_t *digest
|
|||||||
|
|
||||||
assert(words_hashed % BLOCK_WORDS == 0);
|
assert(words_hashed % BLOCK_WORDS == 0);
|
||||||
|
|
||||||
ets_printf("Padded to %d bytes\n", words_hashed * 4);
|
|
||||||
|
|
||||||
while(REG_READ(SHA_256_BUSY_REG) == 1) { }
|
while(REG_READ(SHA_256_BUSY_REG) == 1) { }
|
||||||
REG_WRITE(SHA_256_LOAD_REG, 1);
|
REG_WRITE(SHA_256_LOAD_REG, 1);
|
||||||
while(REG_READ(SHA_256_BUSY_REG) == 1) { }
|
while(REG_READ(SHA_256_BUSY_REG) == 1) { }
|
||||||
|
|
||||||
uint32_t *digest_words = (uint32_t *)digest;
|
uint32_t *digest_words = (uint32_t *)digest;
|
||||||
uint32_t *sha_text_reg = (uint32_t *)(SHA_TEXT_BASE);
|
uint32_t *sha_text_reg = (uint32_t *)(SHA_TEXT_BASE);
|
||||||
for (int i = 0; i < BLOCK_WORDS; i++) {
|
for (int i = 0; i < DIGEST_WORDS; i++) {
|
||||||
digest_words[i] = __builtin_bswap32(sha_text_reg[i]);
|
digest_words[i] = __builtin_bswap32(sha_text_reg[i]);
|
||||||
}
|
}
|
||||||
asm volatile ("memw");
|
asm volatile ("memw");
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <rom/rtc.h>
|
#include <rom/rtc.h>
|
||||||
#include <soc/cpu.h>
|
#include <soc/cpu.h>
|
||||||
#include <esp_image_format.h>
|
#include <esp_image_format.h>
|
||||||
|
#include <esp_secure_boot.h>
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
#include <bootloader_flash.h>
|
#include <bootloader_flash.h>
|
||||||
#include <bootloader_random.h>
|
#include <bootloader_random.h>
|
||||||
@ -24,11 +25,13 @@
|
|||||||
|
|
||||||
static const char *TAG = "esp_image";
|
static const char *TAG = "esp_image";
|
||||||
|
|
||||||
|
#define HASH_LEN 32 /* SHA-256 digest length */
|
||||||
|
|
||||||
#define SIXTEEN_MB 0x1000000
|
#define SIXTEEN_MB 0x1000000
|
||||||
#define ESP_ROM_CHECKSUM_INITIAL 0xEF
|
#define ESP_ROM_CHECKSUM_INITIAL 0xEF
|
||||||
|
|
||||||
/* Headroom to ensure between stack SP (at time of checking) and data loaded from flash */
|
/* Headroom to ensure between stack SP (at time of checking) and data loaded from flash */
|
||||||
#define STACK_LOAD_HEADROOM 4096
|
#define STACK_LOAD_HEADROOM 32768
|
||||||
|
|
||||||
#ifdef BOOTLOADER_BUILD
|
#ifdef BOOTLOADER_BUILD
|
||||||
/* 64 bits of random data to obfuscate loaded RAM with, until verification is complete
|
/* 64 bits of random data to obfuscate loaded RAM with, until verification is complete
|
||||||
@ -60,6 +63,11 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
|
|||||||
} \
|
} \
|
||||||
while(0)
|
while(0)
|
||||||
|
|
||||||
|
static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data);
|
||||||
|
|
||||||
|
static esp_err_t __attribute__((unused)) verify_secure_boot(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
|
||||||
|
static esp_err_t __attribute__((unused)) verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data);
|
||||||
|
|
||||||
esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
|
esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *part, esp_image_metadata_t *data)
|
||||||
{
|
{
|
||||||
#ifdef BOOTLOADER_BUILD
|
#ifdef BOOTLOADER_BUILD
|
||||||
@ -72,7 +80,6 @@ esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *
|
|||||||
// checksum the image a word at a time. This shaves 30-40ms per MB of image size
|
// checksum the image a word at a time. This shaves 30-40ms per MB of image size
|
||||||
uint32_t checksum_word = ESP_ROM_CHECKSUM_INITIAL;
|
uint32_t checksum_word = ESP_ROM_CHECKSUM_INITIAL;
|
||||||
bootloader_sha256_handle_t sha_handle = NULL;
|
bootloader_sha256_handle_t sha_handle = NULL;
|
||||||
uint8_t image_digest[32] = { 0 };
|
|
||||||
|
|
||||||
if (data == NULL || part == NULL) {
|
if (data == NULL || part == NULL) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
@ -86,17 +93,24 @@ esp_err_t esp_image_load(esp_image_load_mode_t mode, const esp_partition_pos_t *
|
|||||||
bzero(data, sizeof(esp_image_metadata_t));
|
bzero(data, sizeof(esp_image_metadata_t));
|
||||||
data->start_addr = part->offset;
|
data->start_addr = part->offset;
|
||||||
|
|
||||||
sha_handle = bootloader_sha256_start();
|
|
||||||
if (sha_handle == NULL) {
|
|
||||||
return ESP_ERR_NO_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "reading image header @ 0x%x", data->start_addr);
|
ESP_LOGD(TAG, "reading image header @ 0x%x", data->start_addr);
|
||||||
err = bootloader_flash_read(data->start_addr, &data->image, sizeof(esp_image_header_t), true);
|
err = bootloader_flash_read(data->start_addr, &data->image, sizeof(esp_image_header_t), true);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate SHA-256 of image if secure boot is on, or if image has a hash appended
|
||||||
|
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||||
|
if (1) {
|
||||||
|
#else
|
||||||
|
if (data->image.hash_appended) {
|
||||||
|
#endif
|
||||||
|
sha_handle = bootloader_sha256_start();
|
||||||
|
if (sha_handle == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
bootloader_sha256_data(sha_handle, &data->image, sizeof(esp_image_header_t));
|
bootloader_sha256_data(sha_handle, &data->image, sizeof(esp_image_header_t));
|
||||||
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, "image header: 0x%02x 0x%02x 0x%02x 0x%02x %08x",
|
ESP_LOGD(TAG, "image header: 0x%02x 0x%02x 0x%02x 0x%02x %08x",
|
||||||
data->image.magic,
|
data->image.magic,
|
||||||
@ -134,48 +148,32 @@ goto err;
|
|||||||
FAIL_LOAD("image offset has wrapped");
|
FAIL_LOAD("image offset has wrapped");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t unpadded_length = end_addr - data->start_addr;
|
data->image_len = end_addr - data->start_addr;
|
||||||
uint32_t length = unpadded_length + 1; // Add a byte for the checksum
|
ESP_LOGV(TAG, "image start 0x%08x end of last section 0x%08x", data->start_addr, end_addr);
|
||||||
length = (length + 15) & ~15; // Pad to next full 16 byte block
|
err = verify_checksum(sha_handle, checksum_word, data);
|
||||||
if (length > part->size) {
|
if (err != ESP_OK) {
|
||||||
FAIL_LOAD("Image length %d doesn't fit in partition length %d", length, part->size);
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify checksum
|
if (data->image_len > part->size) {
|
||||||
uint32_t buf[16/sizeof(uint32_t)];
|
FAIL_LOAD("Image length %d doesn't fit in partition length %d", data->image_len, part->size);
|
||||||
err = bootloader_flash_read(end_addr, buf, length - unpadded_length, true);
|
|
||||||
uint8_t calc = ((uint8_t *)buf)[length - unpadded_length - 1];
|
|
||||||
uint8_t checksum = (checksum_word >> 24)
|
|
||||||
^ (checksum_word >> 16)
|
|
||||||
^ (checksum_word >> 8)
|
|
||||||
^ (checksum_word >> 0);
|
|
||||||
if (err != ESP_OK || checksum != calc) {
|
|
||||||
FAIL_LOAD("Checksum failed. Calculated 0x%x read 0x%x",
|
|
||||||
checksum, calc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bootloader_sha256_data(sha_handle, buf, length - unpadded_length);
|
#ifdef CONFIG_SECURE_BOOT_ENABLED
|
||||||
bootloader_sha256_finish(sha_handle, image_digest);
|
err = verify_secure_boot(sha_handle, data);
|
||||||
|
sha_handle = NULL;
|
||||||
#if BOOT_LOG_LEVEL >= LOG_LEVEL_DEBUG
|
if (err != ESP_OK) {
|
||||||
char digest_print[sizeof(image_digest)*2 + 1];
|
goto err;
|
||||||
digest_print[sizeof(image_digest)*2] = 0;
|
}
|
||||||
for (int i = 0; i < sizeof(image_digest); i++) {
|
#else // No secure boot, but SHA-256 can be appended for basic corruption detection
|
||||||
for (int shift = 0; shift < 2; shift++) {
|
if (sha_handle != NULL) {
|
||||||
uint8_t nibble = (image_digest[i] >> (shift ? 0 : 4)) & 0x0F;
|
err = verify_simple_hash(sha_handle, data);
|
||||||
if (nibble < 10) {
|
sha_handle = NULL;
|
||||||
digest_print[i*2+shift] = '0' + nibble;
|
if (err != ESP_OK) {
|
||||||
} else {
|
goto err;
|
||||||
digest_print[i*2+shift] = 'a' + nibble - 10;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ESP_LOGD(TAG, "Total image length %d bytes (unpagged %d)", length, unpadded_length);
|
|
||||||
ESP_LOGD(TAG, "Image SHA256 digest: %s", digest_print);
|
|
||||||
#endif
|
#endif
|
||||||
// Verify digest here
|
|
||||||
|
|
||||||
data->image_length = length;
|
|
||||||
|
|
||||||
#ifdef BOOTLOADER_BUILD
|
#ifdef BOOTLOADER_BUILD
|
||||||
if (do_load) { // Need to deobfuscate RAM
|
if (do_load) { // Need to deobfuscate RAM
|
||||||
@ -199,8 +197,8 @@ goto err;
|
|||||||
err = ESP_ERR_IMAGE_INVALID;
|
err = ESP_ERR_IMAGE_INVALID;
|
||||||
}
|
}
|
||||||
if (sha_handle != NULL) {
|
if (sha_handle != NULL) {
|
||||||
// Need to finish the digest process to free the handle
|
// Need to finish the hash process to free the handle
|
||||||
bootloader_sha256_finish(sha_handle, image_digest);
|
bootloader_sha256_finish(sha_handle, NULL);
|
||||||
}
|
}
|
||||||
// Prevent invalid/incomplete data leaking out
|
// Prevent invalid/incomplete data leaking out
|
||||||
bzero(data, sizeof(esp_image_metadata_t));
|
bzero(data, sizeof(esp_image_metadata_t));
|
||||||
@ -238,9 +236,12 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
|||||||
/* read segment header */
|
/* read segment header */
|
||||||
err = bootloader_flash_read(flash_addr, header, sizeof(esp_image_segment_header_t), true);
|
err = bootloader_flash_read(flash_addr, header, sizeof(esp_image_segment_header_t), true);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "bootloader_flash_read failed at 0x%08x", flash_addr);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
if (sha_handle != NULL) {
|
||||||
bootloader_sha256_data(sha_handle, header, sizeof(esp_image_segment_header_t));
|
bootloader_sha256_data(sha_handle, header, sizeof(esp_image_segment_header_t));
|
||||||
|
}
|
||||||
|
|
||||||
intptr_t load_addr = header->load_addr;
|
intptr_t load_addr = header->load_addr;
|
||||||
uint32_t data_len = header->data_len;
|
uint32_t data_len = header->data_len;
|
||||||
@ -311,7 +312,7 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme
|
|||||||
// counter-intuitive, but it's ~3ms better than using the
|
// counter-intuitive, but it's ~3ms better than using the
|
||||||
// SHA256 block size.
|
// SHA256 block size.
|
||||||
const size_t SHA_CHUNK = 1024;
|
const size_t SHA_CHUNK = 1024;
|
||||||
if (i % SHA_CHUNK == 0) {
|
if (sha_handle != NULL && i % SHA_CHUNK == 0) {
|
||||||
bootloader_sha256_data(sha_handle, &src[w_i],
|
bootloader_sha256_data(sha_handle, &src[w_i],
|
||||||
MIN(SHA_CHUNK, data_len - i));
|
MIN(SHA_CHUNK, data_len - i));
|
||||||
}
|
}
|
||||||
@ -349,7 +350,7 @@ static esp_err_t verify_segment_header(int index, const esp_image_segment_header
|
|||||||
if (map_segment
|
if (map_segment
|
||||||
&& ((segment_data_offs % SPI_FLASH_MMU_PAGE_SIZE) != (load_addr % SPI_FLASH_MMU_PAGE_SIZE))) {
|
&& ((segment_data_offs % SPI_FLASH_MMU_PAGE_SIZE) != (load_addr % SPI_FLASH_MMU_PAGE_SIZE))) {
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
ESP_LOGE(TAG, "Segment %d has load address 0x%08x, doesn't match segment data at 0x%08x",
|
ESP_LOGE(TAG, "Segment %d load address 0x%08x, doesn't match data 0x%08x",
|
||||||
index, load_addr, segment_data_offs);
|
index, load_addr, segment_data_offs);
|
||||||
}
|
}
|
||||||
return ESP_ERR_IMAGE_INVALID;
|
return ESP_ERR_IMAGE_INVALID;
|
||||||
@ -411,3 +412,120 @@ esp_err_t esp_image_verify_bootloader(uint32_t *length)
|
|||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static esp_err_t verify_checksum(bootloader_sha256_handle_t sha_handle, uint32_t checksum_word, esp_image_metadata_t *data)
|
||||||
|
{
|
||||||
|
uint32_t unpadded_length = data->image_len;
|
||||||
|
uint32_t length = unpadded_length + 1; // Add a byte for the checksum
|
||||||
|
length = (length + 15) & ~15; // Pad to next full 16 byte block
|
||||||
|
|
||||||
|
// Verify checksum
|
||||||
|
uint8_t buf[16];
|
||||||
|
esp_err_t err = bootloader_flash_read(data->start_addr + unpadded_length, buf, length - unpadded_length, true);
|
||||||
|
uint8_t calc = buf[length - unpadded_length - 1];
|
||||||
|
uint8_t checksum = (checksum_word >> 24)
|
||||||
|
^ (checksum_word >> 16)
|
||||||
|
^ (checksum_word >> 8)
|
||||||
|
^ (checksum_word >> 0);
|
||||||
|
if (err != ESP_OK || checksum != calc) {
|
||||||
|
ESP_LOGE(TAG, "Checksum failed. Calculated 0x%x read 0x%x", checksum, calc);
|
||||||
|
return ESP_ERR_IMAGE_INVALID;
|
||||||
|
}
|
||||||
|
if (sha_handle != NULL) {
|
||||||
|
bootloader_sha256_data(sha_handle, buf, length - unpadded_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->image.hash_appended) {
|
||||||
|
// Account for the hash in the total image length
|
||||||
|
length += HASH_LEN;
|
||||||
|
}
|
||||||
|
data->image_len = length;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debug_log_hash(const uint8_t *image_hash, const char *caption);
|
||||||
|
|
||||||
|
static esp_err_t verify_secure_boot(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data)
|
||||||
|
{
|
||||||
|
uint8_t image_hash[HASH_LEN] = { 0 };
|
||||||
|
|
||||||
|
// For secure boot, we calculate the signature hash over the whole file, which includes any "simple" hash
|
||||||
|
// appended to the image for corruption detection
|
||||||
|
if (data->image.hash_appended) {
|
||||||
|
const void *simple_hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN);
|
||||||
|
bootloader_sha256_data(sha_handle, simple_hash, HASH_LEN);
|
||||||
|
bootloader_munmap(simple_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
bootloader_sha256_finish(sha_handle, image_hash);
|
||||||
|
|
||||||
|
// Log the hash for debugging
|
||||||
|
debug_log_hash(image_hash, "Calculated secure boot hash");
|
||||||
|
|
||||||
|
// Use hash to verify signature block
|
||||||
|
const esp_secure_boot_sig_block_t *sig_block = bootloader_mmap(data->start_addr + data->image_len, sizeof(esp_secure_boot_sig_block_t));
|
||||||
|
esp_err_t err = esp_secure_boot_verify_signature_block(sig_block, image_hash);
|
||||||
|
bootloader_munmap(sig_block);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Secure boot signature verification failed");
|
||||||
|
|
||||||
|
// Go back and check if the simple hash matches or not (we're off the fast path so we can re-hash the whole image now)
|
||||||
|
ESP_LOGI(TAG, "Calculating simple hash to check for corruption...");
|
||||||
|
const void *whole_image = bootloader_mmap(data->start_addr, data->image_len - HASH_LEN);
|
||||||
|
if (whole_image != NULL) {
|
||||||
|
sha_handle = bootloader_sha256_start();
|
||||||
|
bootloader_sha256_data(sha_handle, whole_image, data->image_len - HASH_LEN);
|
||||||
|
bootloader_munmap(whole_image);
|
||||||
|
if (verify_simple_hash(sha_handle, data) != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "image corrupted on flash");
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "image valid, signature bad");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ESP_ERR_IMAGE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t verify_simple_hash(bootloader_sha256_handle_t sha_handle, esp_image_metadata_t *data)
|
||||||
|
{
|
||||||
|
uint8_t image_hash[HASH_LEN] = { 0 };
|
||||||
|
bootloader_sha256_finish(sha_handle, image_hash);
|
||||||
|
|
||||||
|
// Log the hash for debugging
|
||||||
|
debug_log_hash(image_hash, "Calculated hash");
|
||||||
|
|
||||||
|
// Simple hash for verification only
|
||||||
|
const void *hash = bootloader_mmap(data->start_addr + data->image_len - HASH_LEN, HASH_LEN);
|
||||||
|
if (memcmp(hash, image_hash, HASH_LEN) != 0) {
|
||||||
|
ESP_LOGE(TAG, "Image hash failed - image is corrupt");
|
||||||
|
debug_log_hash(hash, "Expected hash");
|
||||||
|
bootloader_munmap(hash);
|
||||||
|
return ESP_ERR_IMAGE_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bootloader_munmap(hash);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log a hash as a hex string
|
||||||
|
static void debug_log_hash(const uint8_t *image_hash, const char *label)
|
||||||
|
{
|
||||||
|
#if BOOT_LOG_LEVEL >= LOG_LEVEL_DEBUG
|
||||||
|
char hash_print[sizeof(image_hash)*2 + 1];
|
||||||
|
hash_print[sizeof(image_hash)*2] = 0;
|
||||||
|
for (int i = 0; i < sizeof(image_hash); i++) {
|
||||||
|
for (int shift = 0; shift < 2; shift++) {
|
||||||
|
uint8_t nibble = (image_hash[i] >> (shift ? 0 : 4)) & 0x0F;
|
||||||
|
if (nibble < 10) {
|
||||||
|
hash_print[i*2+shift] = '0' + nibble;
|
||||||
|
} else {
|
||||||
|
hash_print[i*2+shift] = 'a' + nibble - 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGD(TAG, "%s: %s", label, hash_print);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#include "bootloader_flash.h"
|
#include "bootloader_flash.h"
|
||||||
|
#include "bootloader_sha.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_image_format.h"
|
#include "esp_image_format.h"
|
||||||
#include "esp_secure_boot.h"
|
#include "esp_secure_boot.h"
|
||||||
@ -34,20 +35,13 @@ extern const uint8_t signature_verification_key_end[] asm("_binary_signature_ver
|
|||||||
|
|
||||||
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
#define SIGNATURE_VERIFICATION_KEYLEN 64
|
||||||
|
|
||||||
|
#define DIGEST_LEN 32
|
||||||
|
|
||||||
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
||||||
{
|
{
|
||||||
#ifdef BOOTLOADER_BUILD
|
uint8_t digest[DIGEST_LEN];
|
||||||
SHA_CTX sha;
|
|
||||||
#endif
|
|
||||||
uint8_t digest[32];
|
|
||||||
ptrdiff_t keylen;
|
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
const esp_secure_boot_sig_block_t *sigblock;
|
const esp_secure_boot_sig_block_t *sigblock;
|
||||||
bool is_valid;
|
|
||||||
#ifdef BOOTLOADER_BUILD
|
|
||||||
const uint8_t *digest_data;
|
|
||||||
uint32_t digest_len;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
|
||||||
|
|
||||||
@ -57,46 +51,43 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
|
|||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sigblock = (const esp_secure_boot_sig_block_t *)(data + length);
|
// Calculate digest of main image
|
||||||
|
|
||||||
if (sigblock->version != 0) {
|
|
||||||
ESP_LOGE(TAG, "src 0x%x has invalid signature version field 0x%08x", src_addr, sigblock->version);
|
|
||||||
goto unmap_and_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BOOTLOADER_BUILD
|
#ifdef BOOTLOADER_BUILD
|
||||||
/* Use ROM SHA functions directly */
|
bootloader_sha256_handle_t handle = bootloader_sha256_start();
|
||||||
ets_sha_enable();
|
bootloader_sha256_data(handle, data, length);
|
||||||
ets_sha_init(&sha);
|
bootloader_sha256_finish(handle, digest);
|
||||||
digest_len = length * 8;
|
|
||||||
digest_data = data;
|
|
||||||
while (digest_len > 0) {
|
|
||||||
uint32_t chunk_len = (digest_len > 64) ? 64 : digest_len;
|
|
||||||
ets_sha_update(&sha, SHA2_256, digest_data, chunk_len);
|
|
||||||
digest_len -= chunk_len;
|
|
||||||
digest_data += chunk_len / 8;
|
|
||||||
}
|
|
||||||
ets_sha_finish(&sha, SHA2_256, digest);
|
|
||||||
ets_sha_disable();
|
|
||||||
#else
|
#else
|
||||||
/* Use thread-safe esp-idf SHA function */
|
/* Use thread-safe esp-idf SHA function */
|
||||||
esp_sha(SHA2_256, data, length, digest);
|
esp_sha(SHA2_256, data, length, digest);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Map the signature block and verify the signature
|
||||||
|
sigblock = (const esp_secure_boot_sig_block_t *)(data + length);
|
||||||
|
esp_err_t err = esp_secure_boot_verify_signature_block(sigblock, digest);
|
||||||
|
bootloader_munmap(data);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_secure_boot_verify_signature_block(const esp_secure_boot_sig_block_t *sig_block, const uint8_t *image_digest)
|
||||||
|
{
|
||||||
|
ptrdiff_t keylen;
|
||||||
|
bool is_valid;
|
||||||
|
|
||||||
keylen = signature_verification_key_end - signature_verification_key_start;
|
keylen = signature_verification_key_end - signature_verification_key_start;
|
||||||
if(keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
if(keylen != SIGNATURE_VERIFICATION_KEYLEN) {
|
||||||
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
|
||||||
goto unmap_and_fail;
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sig_block->version != 0) {
|
||||||
|
ESP_LOGE(TAG, "image has invalid signature version field 0x%08x", sig_block->version);
|
||||||
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_valid = uECC_verify(signature_verification_key_start,
|
is_valid = uECC_verify(signature_verification_key_start,
|
||||||
digest, sizeof(digest), sigblock->signature,
|
image_digest,
|
||||||
|
DIGEST_LEN,
|
||||||
|
sig_block->signature,
|
||||||
uECC_secp256r1());
|
uECC_secp256r1());
|
||||||
|
|
||||||
bootloader_munmap(data);
|
|
||||||
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
|
||||||
|
|
||||||
unmap_and_fail:
|
|
||||||
bootloader_munmap(data);
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 325f01637b667af02cc6390965b09d50e6a31dac
|
Subproject commit a4207741eca1fb8e5e3670e498ed058320bbcb5a
|
@ -4261,7 +4261,9 @@
|
|||||||
/* Flash MMU table for APP CPU */
|
/* Flash MMU table for APP CPU */
|
||||||
#define DPORT_APP_FLASH_MMU_TABLE ((volatile uint32_t*) 0x3FF12000)
|
#define DPORT_APP_FLASH_MMU_TABLE ((volatile uint32_t*) 0x3FF12000)
|
||||||
|
|
||||||
|
#define DPORT_FLASH_MMU_TABLE_SIZE 0x100
|
||||||
|
|
||||||
|
#define DPORT_FLASH_MMU_TABLE_INVALID_VAL 0x100
|
||||||
|
|
||||||
#endif /*_SOC_DPORT_REG_H_ */
|
#endif /*_SOC_DPORT_REG_H_ */
|
||||||
|
|
||||||
|
@ -83,14 +83,14 @@ static void IRAM_ATTR spi_flash_mmap_init()
|
|||||||
uint32_t entry_app = DPORT_APP_FLASH_MMU_TABLE[i];
|
uint32_t entry_app = DPORT_APP_FLASH_MMU_TABLE[i];
|
||||||
if (entry_pro != entry_app) {
|
if (entry_pro != entry_app) {
|
||||||
// clean up entries used by boot loader
|
// clean up entries used by boot loader
|
||||||
entry_pro = INVALID_ENTRY_VAL;
|
entry_pro = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
|
||||||
DPORT_PRO_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL;
|
DPORT_PRO_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
|
||||||
}
|
}
|
||||||
if ((entry_pro & INVALID_ENTRY_VAL) == 0 && (i == 0 || i == PRO_IRAM0_FIRST_USABLE_PAGE || entry_pro != 0)) {
|
if ((entry_pro & INVALID_ENTRY_VAL) == 0 && (i == 0 || i == PRO_IRAM0_FIRST_USABLE_PAGE || entry_pro != 0)) {
|
||||||
s_mmap_page_refcnt[i] = 1;
|
s_mmap_page_refcnt[i] = 1;
|
||||||
} else {
|
} else {
|
||||||
DPORT_PRO_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL;
|
DPORT_PRO_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
|
||||||
DPORT_APP_FLASH_MMU_TABLE[i] = INVALID_ENTRY_VAL;
|
DPORT_APP_FLASH_MMU_TABLE[i] = DPORT_FLASH_MMU_TABLE_INVALID_VAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y
|
|||||||
# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
|
# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
|
||||||
# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
|
# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
|
||||||
CONFIG_LOG_BOOTLOADER_LEVEL=2
|
CONFIG_LOG_BOOTLOADER_LEVEL=2
|
||||||
|
# CONFIG_BOOTLOADER_LTO is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
# Security features
|
# Security features
|
||||||
|
Loading…
x
Reference in New Issue
Block a user