From caa1ef0cb6fa56212a10b30ec296318fb9f0f742 Mon Sep 17 00:00:00 2001 From: Vikram Dattu Date: Sat, 15 Jun 2019 15:13:51 +0530 Subject: [PATCH 1/3] Bugfix: ota fails with secure boot on for image size greater than 3.2MB When an OTA image size is larger than 50 MMU pages (approx. 3.2 MB), secure_boot_generate fails while trying to map it into memory: https://github.com/espressif/esp-idf/blob/master/components/bootloader_support/src/esp32/secure_boot.c#L72 Instead of trying to map the whole image, secure boot code should split the image into chunks and map them one by one, like it is done in esp_image_format.c: https://github.com/espressif/esp-idf/blob/master/components/bootloader_support/src/esp_image_format.c#L371 Signed-off-by: Vikram Dattu --- .../include_bootloader/bootloader_flash.h | 7 +++ .../bootloader_support/src/bootloader_flash.c | 15 +++++ .../src/secure_boot_signatures.c | 58 ++++++++++++------- 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/components/bootloader_support/include_bootloader/bootloader_flash.h b/components/bootloader_support/include_bootloader/bootloader_flash.h index ce867d757..6ac724646 100644 --- a/components/bootloader_support/include_bootloader/bootloader_flash.h +++ b/components/bootloader_support/include_bootloader/bootloader_flash.h @@ -30,6 +30,13 @@ bootloader_support components only. */ +/** + * @brief Get number of free pages + * + * @return Number of free pages + */ +uint32_t bootloader_mmap_get_free_pages(); + /** * @brief Map a region of flash to data memory * diff --git a/components/bootloader_support/src/bootloader_flash.c b/components/bootloader_support/src/bootloader_flash.c index dbdf84ee2..ea7ce2c77 100644 --- a/components/bootloader_support/src/bootloader_flash.c +++ b/components/bootloader_support/src/bootloader_flash.c @@ -25,6 +25,11 @@ static const char *TAG = "bootloader_mmap"; static spi_flash_mmap_handle_t map; +uint32_t bootloader_mmap_get_free_pages() +{ + return spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA); +} + const void *bootloader_mmap(uint32_t src_addr, uint32_t size) { if (map) { @@ -91,12 +96,22 @@ static const char *TAG = "bootloader_flash"; */ #define MMU_BLOCK0_VADDR 0x3f400000 #define MMU_BLOCK50_VADDR 0x3f720000 +#define MMU_FREE_PAGES ((MMU_BLOCK50_VADDR - MMU_BLOCK0_VADDR) / FLASH_BLOCK_SIZE) static bool mapped; // Current bootloader mapping (ab)used for bootloader_read() static uint32_t current_read_mapping = UINT32_MAX; +uint32_t bootloader_mmap_get_free_pages() +{ + /** + * Allow mapping up to 50 of the 51 available MMU blocks (last one used for reads) + * Since, bootloader_mmap function below assumes it to be 0x320000 (50 pages), we can safely do this. + */ + return MMU_FREE_PAGES; +} + const void *bootloader_mmap(uint32_t src_addr, uint32_t size) { if (mapped) { diff --git a/components/bootloader_support/src/secure_boot_signatures.c b/components/bootloader_support/src/secure_boot_signatures.c index b6681bc79..6981872f2 100644 --- a/components/bootloader_support/src/secure_boot_signatures.c +++ b/components/bootloader_support/src/secure_boot_signatures.c @@ -21,12 +21,7 @@ #include "uECC.h" -#ifdef BOOTLOADER_BUILD -#include "rom/sha.h" -typedef SHA_CTX sha_context; -#else -#include "mbedtls/sha256.h" -#endif +#include static const char* TAG = "secure_boot"; @@ -37,6 +32,9 @@ extern const uint8_t signature_verification_key_end[] asm("_binary_signature_ver #define DIGEST_LEN 32 +/* Mmap source address mask */ +#define MMAP_ALIGNED_MASK 0x0000FFFF + esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length) { uint8_t digest[DIGEST_LEN]; @@ -45,26 +43,44 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length) ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length); - data = bootloader_mmap(src_addr, length + sizeof(esp_secure_boot_sig_block_t)); - if(data == NULL) { - ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(esp_secure_boot_sig_block_t)); - return ESP_FAIL; + bootloader_sha256_handle_t handle = bootloader_sha256_start(); + + uint32_t free_page_count = bootloader_mmap_get_free_pages(); + ESP_LOGD(TAG, "free data page_count 0x%08x", free_page_count); + + int32_t data_len_remain = length; + uint32_t data_addr = src_addr; + while (data_len_remain > 0) { + uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0; + /* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */ + uint32_t data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE)); + data = (const uint8_t *) bootloader_mmap(data_addr, data_len); + if(!data) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", data_addr, data_len); + bootloader_sha256_finish(handle, NULL); + return ESP_FAIL; + } + bootloader_sha256_data(handle, data, data_len); + bootloader_munmap(data); + + data_addr += data_len; + data_len_remain -= data_len; } - // Calculate digest of main image -#ifdef BOOTLOADER_BUILD - bootloader_sha256_handle_t handle = bootloader_sha256_start(); - bootloader_sha256_data(handle, data, length); + /* Done! Get the digest */ bootloader_sha256_finish(handle, digest); -#else - /* Use thread-safe mbedTLS version */ - mbedtls_sha256_ret(data, length, digest, 0); -#endif - // Map the signature block and verify the signature - sigblock = (const esp_secure_boot_sig_block_t *)(data + length); + // Map the signature block + sigblock = (const esp_secure_boot_sig_block_t *) bootloader_mmap(src_addr + length, sizeof(esp_secure_boot_sig_block_t)); + if(!sigblock) { + ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr + length, sizeof(esp_secure_boot_sig_block_t)); + return ESP_FAIL; + } + // Verify the signature esp_err_t err = esp_secure_boot_verify_signature_block(sigblock, digest); - bootloader_munmap(data); + // Unmap + bootloader_munmap(sigblock); + return err; } From b800dfe6f1a49d20a26c1aa05be4186e8a86ae2d Mon Sep 17 00:00:00 2001 From: Vikram Dattu Date: Tue, 18 Jun 2019 14:04:32 +0530 Subject: [PATCH 2/3] Changed log level for spi_master There are lot of prints of `Allocate TX buffer for DMA` Changed these from `ESP_LOGI` to `ESP_LOGD` Signed-off-by: Vikram Dattu --- components/driver/spi_master.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/driver/spi_master.c b/components/driver/spi_master.c index 5976b008f..61376c9b3 100644 --- a/components/driver/spi_master.c +++ b/components/driver/spi_master.c @@ -1174,7 +1174,7 @@ static SPI_MASTER_ISR_ATTR esp_err_t setup_priv_desc(spi_transaction_t *trans_de } if (send_ptr && isdma && !esp_ptr_dma_capable( send_ptr )) { //if txbuf in the desc not DMA-capable, malloc a new one - ESP_LOGI( SPI_TAG, "Allocate TX buffer for DMA" ); + ESP_LOGD( SPI_TAG, "Allocate TX buffer for DMA" ); uint32_t *temp = heap_caps_malloc((trans_desc->length + 7) / 8, MALLOC_CAP_DMA); if (temp == NULL) goto clean_up; From 4c27f9ced8573cf41c36805043c9db2a8c9b6574 Mon Sep 17 00:00:00 2001 From: Vikram Dattu Date: Wed, 19 Jun 2019 17:23:44 +0530 Subject: [PATCH 3/3] Add mmu pages available check in non-secure image hash check path. Made MMU pages available check in `esp_image_format.c` This now makes it possible to map and process bootoader image as well in chunks when image doesn't fit completely into available free pages. Signed-off-by: Vikram Dattu --- .../bootloader_support/src/esp_image_format.c | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 958f3a6a9..3947b2701 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -368,24 +368,22 @@ static esp_err_t process_segment(int index, uint32_t flash_addr, esp_image_segme } #endif // BOOTLOADER_BUILD -#ifndef BOOTLOADER_BUILD - uint32_t free_page_count = spi_flash_mmap_get_free_pages(SPI_FLASH_MMAP_DATA); - ESP_LOGD(TAG, "free data page_count 0x%08x",free_page_count); - uint32_t offset_page = 0; - while (data_len >= free_page_count * SPI_FLASH_MMU_PAGE_SIZE) { - offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0)?1:0; - err = process_segment_data(load_addr, data_addr, (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE, do_load, sha_handle, checksum); + uint32_t free_page_count = bootloader_mmap_get_free_pages(); + ESP_LOGD(TAG, "free data page_count 0x%08x", free_page_count); + + int32_t data_len_remain = data_len; + while (data_len_remain > 0) { + uint32_t offset_page = ((data_addr & MMAP_ALIGNED_MASK) != 0) ? 1 : 0; + /* Data we could map in case we are not aligned to PAGE boundary is one page size lesser. */ + data_len = MIN(data_len_remain, ((free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE)); + err = process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum); if (err != ESP_OK) { return err; } - data_addr += (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE; - data_len -= (free_page_count - offset_page) * SPI_FLASH_MMU_PAGE_SIZE; - } -#endif - err = process_segment_data(load_addr, data_addr, data_len, do_load, sha_handle, checksum); - if (err != ESP_OK) { - return err; + data_addr += data_len; + data_len_remain -= data_len; } + return ESP_OK; err: