From e7cd340ebf2bdd5d4e2f0706a549fb166c035238 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Thu, 3 Apr 2025 17:12:42 +0200 Subject: [PATCH] Moved elf parsing/scattering to elf.c, WIP sim --- arch.mk | 4 +- hal/sim.c | 17 ++ include/elf.h | 4 +- options.mk | 4 + src/elf.c | 255 +++++++++++++++++++++++++++- src/image.c | 177 -------------------- src/update_flash.c | 405 --------------------------------------------- test-app/Makefile | 10 +- 8 files changed, 290 insertions(+), 586 deletions(-) diff --git a/arch.mk b/arch.mk index 0e74a917..666276e8 100644 --- a/arch.mk +++ b/arch.mk @@ -1125,7 +1125,9 @@ ifeq ($(TARGET),sim) LD_END_GROUP= BOOT_IMG=test-app/image.elf CFLAGS+=-DARCH_SIM - CFLAGS+=-DWOLFBOOT_USE_STDLIBC + ifneq ($(ELF_SCATTERED),1) + CFLAGS+=-DWOLFBOOT_USE_STDLIBC + endif ifeq ($(FORCE_32BIT),1) CFLAGS+=-m32 LDFLAGS+=-m32 diff --git a/hal/sim.c b/hal/sim.c index 1816374d..57e3dc31 100644 --- a/hal/sim.c +++ b/hal/sim.c @@ -42,6 +42,10 @@ #include "target.h" #include "printf.h" +#ifdef ELF_SCATTERED +#include "elf.h" +#endif + #ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT #include "wolfhsm/wh_error.h" #include "wolfhsm/wh_client.h" @@ -348,6 +352,19 @@ void do_boot(const uint32_t *app_offset) main = (main_entry)((uint8_t*)pSymbolAddress + epc->entryoff); main(main_argc, main_argv, NULL, NULL); +#elif defined ELF_SCATTERED + unsigned long *entry_point = (unsigned long *)sim_ram_base; + typedef int (*main_entry)(int, char**); + main_entry main; + + wolfBoot_printf("Loading ELF image with scattered segments...\n"); + ret = elf_store_image_scattered((void*)app_offset, entry_point, 0); + if (ret != 0) { + wolfBoot_printf( "Error loading ELF image!\n"); + exit(-1); + } + main = (main_entry)(entry_point); + main(main_argc, main_argv); #else char *envp[1] = {NULL}; int fd = memfd_create("test_app", 0); diff --git a/include/elf.h b/include/elf.h index e29c58ab..be19c31b 100644 --- a/include/elf.h +++ b/include/elf.h @@ -32,6 +32,7 @@ extern "C" { #define ELF_IDENT_STR "\x7F""ELF" /* header ident[4] */ +#define ELF_CLASS_OFF (4) #define ELF_CLASS_32 (1) #define ELF_CLASS_64 (2) @@ -161,7 +162,8 @@ typedef struct elf64_program_header { typedef int (*elf_mmu_map_cb)(uint64_t, uint64_t, uint32_t); int elf_load_image_mmu(uint8_t *image, uintptr_t *entry, elf_mmu_map_cb mmu_cb); -int elf_load_image(uint8_t *image, uintptr_t *entry); +int elf_load_image(uint8_t *image, uintptr_t *entry, int is_ext); +int elf_store_image_scattered(const unsigned char *image, unsigned long *entry_out, int ext_flash); #ifdef __cplusplus diff --git a/options.mk b/options.mk index b346f57c..52ac384e 100644 --- a/options.mk +++ b/options.mk @@ -786,6 +786,10 @@ ifeq ($(ELF),1) ifneq ($(DEBUG_ELF),) CFLAGS+=-DDEBUG_ELF=$(DEBUG_ELF) endif + ifeq ($(ELF_SCATTERED),1) + CFLAGS+=-D"ELF_SCATTERED=1" + endif + endif ifeq ($(MULTIBOOT2),1) diff --git a/src/elf.c b/src/elf.c index fc4dc6e1..d7dd7fae 100644 --- a/src/elf.c +++ b/src/elf.c @@ -27,6 +27,7 @@ #include "printf.h" #include "string.h" #include "elf.h" +#include "hal.h" #ifdef ARCH_PPC #include "hal/nxp_ppc.h" @@ -43,6 +44,7 @@ #endif +#ifdef MMU /* Loader for elf32 or elf64 format program headers * Returns the entry point function */ @@ -143,11 +145,262 @@ int elf_load_image_mmu(uint8_t *image, uintptr_t *entry, elf_mmu_map_cb mmu_cb) return 0; } +#endif /* MMU */ -int elf_load_image(uint8_t *image, uintptr_t *entry) +#if 0 +/** + * @brief Compute the scattered hash by hashing PT_LOAD segments at their XIP + * addresses. Note: This function assumes that the destination addresses for elf + * loading have the same access patterns as the memory represented by img. + * (e.g. if BOOT partition is external, then reads/writes to the load address + * will use ext_flash_read/ext_flash_write. + * + * @param img Pointer to the wolfBoot image + * @param hash Buffer to store the computed hash (must be at least + * WOLFBOOT_SHA_DIGEST_SIZE bytes) + * @return 0 on success, negative value on error + */ +static int wolfBoot_compute_scattered_hash(struct wolfBoot_image *img, uint8_t *hash) { + uint8_t elf_header_buf[sizeof(elf64_header)]; + uint8_t program_header_buf[sizeof(elf64_program_header)]; + elf32_header* h32; + elf64_header* h64; + uint16_t entry_count, entry_size; + uint32_t ph_offset; + int is_elf32, is_le, i; +#if defined(WOLFBOOT_HASH_SHA256) + wc_Sha256 sha256_ctx; +#elif defined(WOLFBOOT_HASH_SHA384) + wc_Sha384 sha384_ctx; +#elif defined(WOLFBOOT_HASH_SHA3_384) + wc_Sha3 sha3_384_ctx; +#endif +#ifdef EXT_FLASH + if (PART_IS_EXT(img)) { + /* Read ELF header from external flash */ + ext_flash_check_read((uintptr_t)(img->fw_base), elf_header_buf, sizeof(elf64_header)); + } else +#endif + { + memcpy(elf_header_buf, (void*)(img->fw_base), sizeof(elf64_header)); + } + + h32 = (elf32_header*)elf_header_buf; + h64 = (elf64_header*)elf_header_buf; + + /* Verify ELF header */ + if (memcmp(h32->ident, ELF_IDENT_STR, 4) != 0) { + return -1; /* not valid header identifier */ + } + + /* Load class and endianess */ + is_elf32 = (h32->ident[4] == ELF_CLASS_32); + is_le = (h32->ident[5] == ELF_ENDIAN_LITTLE); + (void)is_le; + + /* Initialize hash context */ +#if defined(WOLFBOOT_HASH_SHA256) + wc_InitSha256(&sha256_ctx); +#elif defined(WOLFBOOT_HASH_SHA384) + wc_InitSha384(&sha384_ctx); +#elif defined(WOLFBOOT_HASH_SHA3_384) + wc_Sha3_384_Init(&sha3_384_ctx, NULL, INVALID_DEVID); +#endif + + /* Get program headers info */ + ph_offset = is_elf32 ? GET32(h32->ph_offset) : GET32(h64->ph_offset); + entry_size = is_elf32 ? GET16(h32->ph_entry_size) : GET16(h64->ph_entry_size); + entry_count = is_elf32 ? GET16(h32->ph_entry_count) : GET16(h64->ph_entry_count); + + /* Hash each loadable segment directly from its physical address */ + for (i = 0; i < entry_count; i++) { + elf32_program_header* phdr32; + elf64_program_header* phdr64; + uint32_t type; + uintptr_t paddr; + uintptr_t file_size; + + /* Read program header into buffer */ +#ifdef EXT_FLASH + if (PART_IS_EXT(img)) { + ext_flash_check_read((uintptr_t)(img->fw_base) + ph_offset + (i * entry_size), + program_header_buf, entry_size); + } else +#endif + { + memcpy(program_header_buf, + (uint8_t*)(img->fw_base) + ph_offset + (i * entry_size), + entry_size); + } + + + phdr32 = (elf32_program_header*)program_header_buf; + phdr64 = (elf64_program_header*)program_header_buf; + type = (is_elf32 ? GET32(phdr32->type) : GET32(phdr64->type)); + paddr = (is_elf32 ? GET32(phdr32->paddr) : GET64(phdr64->paddr)); + file_size = (is_elf32 ? GET32(phdr32->file_size) : GET64(phdr64->file_size)); + + /* Only hash PT_LOAD segments with non-zero size */ + if (type == ELF_PT_LOAD && file_size > 0) { +#ifdef DEBUG_ELF + wolfBoot_printf("Hashing segment at %p (%d bytes)\r\n", (void*)paddr, (uint32_t)file_size); +#endif + /* Hash the segment data from physical address in blocks */ + uint32_t pos = 0; + while (pos < file_size) { + uint8_t *block; + uint32_t blksz = WOLFBOOT_SHA_BLOCK_SIZE; + + if (pos + blksz > file_size) { + blksz = file_size - pos; + } + + block = get_sha_block_ptr(img, (const uint8_t *)(paddr + pos)); + if (block == NULL) { + return -1; + } + +#if defined(WOLFBOOT_HASH_SHA256) + wc_Sha256Update(&sha256_ctx, block, blksz); +#elif defined(WOLFBOOT_HASH_SHA384) + wc_Sha384Update(&sha384_ctx, block, blksz); +#elif defined(WOLFBOOT_HASH_SHA3_384) + wc_Sha3_384_Update(&sha3_384_ctx, block, blksz); +#endif + pos += blksz; + } + } + } + + /* Finalize hash */ +#if defined(WOLFBOOT_HASH_SHA256) + wc_Sha256Final(&sha256_ctx, hash); +#elif defined(WOLFBOOT_HASH_SHA384) + wc_Sha384Final(&sha384_ctx, hash); +#elif defined(WOLFBOOT_HASH_SHA3_384) + wc_Sha3_384_Final(&sha3_384_ctx, hash); +#endif + + return 0; +} +#endif + +int elf_store_image_scattered(const unsigned char *image, unsigned long *entry_out, int ext_flash) { + const unsigned char *ident; + int is_elf32; + unsigned short entry_count; + unsigned short entry_size; + unsigned long entry_off; + int i; + + ident = image; + + + /* Verify ELF header */ + if (memcmp(ident, ELF_IDENT_STR, 4) != 0) { + return -1; /* not valid header identifier */ + } + + is_elf32 = (ident[ELF_CLASS_OFF] == ELF_CLASS_32); + + if (is_elf32) { + const elf32_header *eh; + const elf32_program_header *ph; + + eh = (const elf32_header *)image; + entry_count = eh->ph_entry_count; + entry_size = eh->ph_entry_size; + entry_off = eh->ph_offset; + *entry_out = (unsigned long)eh->entry; + + ph = (const elf32_program_header *)(image + entry_off); + for (i = 0; i < entry_count; ++i) { + unsigned long paddr; + unsigned long filesz; + unsigned long offset; + + if (ph[i].type != ELF_PT_LOAD) + continue; + + paddr = (unsigned long)ph[i].paddr; + offset = (unsigned long)ph[i].offset; + filesz = (unsigned long)ph[i].file_size; +#if 0 +#ifdef EXT_FLASH + if (ext_flash) { + ext_flash_unlock(); + ext_flash_erase(paddr, filesz); + ext_flash_write(paddr, image + offset, filesz); + ext_flash_lock(); + } + else +#endif + { + hal_flash_unlock(); + hal_flash_erase(paddr, filesz); + hal_flash_write(paddr, image + offset, filesz); + hal_flash_lock(); + } +#endif + } + } else if (ident[ELF_CLASS_OFF] == ELF_CLASS_64) { + const elf64_header *eh; + const elf64_program_header *ph; + + eh = (const elf64_header *)image; + entry_count = eh->ph_entry_count; + entry_size = eh->ph_entry_size; + entry_off = eh->ph_offset; + *entry_out = (unsigned long)eh->entry; + + ph = (const elf64_program_header *)(image + entry_off); + for (i = 0; i < entry_count; ++i) { + unsigned long paddr; + unsigned long filesz; + unsigned long offset; + + if (ph[i].type != ELF_PT_LOAD) + continue; + + paddr = (unsigned long)ph[i].paddr; + offset = (unsigned long)ph[i].offset; + filesz = (unsigned long)ph[i].file_size; +#if 0 +#ifdef EXT_FLASH + if (ext_flash) { + ext_flash_unlock(); + ext_flash_erase(paddr, filesz); + ext_flash_write(paddr, image + offset, filesz); + ext_flash_lock(); + } + else +#endif + { + hal_flash_unlock(); + hal_flash_erase(paddr, filesz); + hal_flash_write(paddr, image + offset, filesz); + hal_flash_lock(); + } +#endif + } + } else { + /* Invalid elf header. */ + return -1; + } + + return 0; +} + + +int elf_load_image(uint8_t *image, uintptr_t *entry, int ext_flash) +{ +#ifdef MMU return elf_load_image_mmu(image, entry, NULL); +#else + return elf_store_image_scattered(image, entry, ext_flash); +#endif } #endif /* WOLFBOOT_ELF */ diff --git a/src/image.c b/src/image.c index fcb2e72c..6d950d71 100644 --- a/src/image.c +++ b/src/image.c @@ -51,9 +51,6 @@ #ifdef WOLFBOOT_HASH_SHA3_384 #include #endif -#ifdef WOLFBOOT_ELF -#include "elf.h" -#endif /* Globals */ static uint8_t digest[WOLFBOOT_SHA_DIGEST_SIZE]; @@ -773,39 +770,6 @@ static uint8_t *get_sha_block(struct wolfBoot_image *img, uint32_t offset) #endif return (uint8_t *)(img->fw_base + offset); } -/** - * @brief Get a block of data to be hashed from a specific memory address. - * - * This function retrieves a block of data to be hashed from a specific memory address. - * It behaves similarly to get_sha_block but takes a direct pointer instead of an offset. - * - * @param img The image to retrieve the data from. - * @param addr The memory address to read the data from. - * @return A pointer to the data block. - */ -static uint8_t *get_sha_block_ptr(struct wolfBoot_image *img, const uint8_t *addr) -{ - uint32_t offset; - - /* Calculate offset from base address */ - if ((uintptr_t)addr < (uintptr_t)img->fw_base) { - return NULL; - } - - offset = (uint32_t)((uintptr_t)addr - (uintptr_t)img->fw_base); - - if (offset > img->fw_size) { - return NULL; - } - -#ifdef EXT_FLASH - if (PART_IS_EXT(img)) { - ext_flash_check_read((uintptr_t)addr, ext_hash_block, WOLFBOOT_SHA_BLOCK_SIZE); - return ext_hash_block; - } else -#endif - return (uint8_t *)addr; -} #ifdef EXT_FLASH static uint8_t hdr_cpy[IMAGE_HEADER_SIZE]; @@ -1097,147 +1061,6 @@ static void key_sha3_384(uint8_t key_slot, uint8_t *hash) #endif /* WOLFBOOT_NO_SIGN */ #endif /* SHA3-384 */ - -#ifdef WOLFBOOT_ELF -/** - * @brief Compute the scattered hash by hashing PT_LOAD segments at their XIP - * addresses. Note: This function assumes that the destination addresses for elf - * loading have the same access patterns as the memory represented by img. - * (e.g. if BOOT partition is external, then reads/writes to the load address - * will use ext_flash_read/ext_flash_write. - * - * @param img Pointer to the wolfBoot image - * @param hash Buffer to store the computed hash (must be at least - * WOLFBOOT_SHA_DIGEST_SIZE bytes) - * @return 0 on success, negative value on error - */ -static int wolfBoot_compute_scattered_hash(struct wolfBoot_image *img, uint8_t *hash) -{ - uint8_t elf_header_buf[sizeof(elf64_header)]; - uint8_t program_header_buf[sizeof(elf64_program_header)]; - elf32_header* h32; - elf64_header* h64; - uint16_t entry_count, entry_size; - uint32_t ph_offset; - int is_elf32, is_le, i; -#if defined(WOLFBOOT_HASH_SHA256) - wc_Sha256 sha256_ctx; -#elif defined(WOLFBOOT_HASH_SHA384) - wc_Sha384 sha384_ctx; -#elif defined(WOLFBOOT_HASH_SHA3_384) - wc_Sha3 sha3_384_ctx; -#endif - -#ifdef EXT_FLASH - if (PART_IS_EXT(img)) { - /* Read ELF header from external flash */ - ext_flash_check_read((uintptr_t)(img->fw_base), elf_header_buf, sizeof(elf64_header)); - } else -#endif - { - memcpy(elf_header_buf, (void*)(img->fw_base), sizeof(elf64_header)); - } - - h32 = (elf32_header*)elf_header_buf; - h64 = (elf64_header*)elf_header_buf; - - /* Verify ELF header */ - if (memcmp(h32->ident, ELF_IDENT_STR, 4) != 0) { - return -1; /* not valid header identifier */ - } - - /* Load class and endianess */ - is_elf32 = (h32->ident[4] == ELF_CLASS_32); - is_le = (h32->ident[5] == ELF_ENDIAN_LITTLE); - (void)is_le; - - /* Initialize hash context */ -#if defined(WOLFBOOT_HASH_SHA256) - wc_InitSha256(&sha256_ctx); -#elif defined(WOLFBOOT_HASH_SHA384) - wc_InitSha384(&sha384_ctx); -#elif defined(WOLFBOOT_HASH_SHA3_384) - wc_Sha3_384_Init(&sha3_384_ctx, NULL, INVALID_DEVID); -#endif - - /* Get program headers info */ - ph_offset = is_elf32 ? GET32(h32->ph_offset) : GET32(h64->ph_offset); - entry_size = is_elf32 ? GET16(h32->ph_entry_size) : GET16(h64->ph_entry_size); - entry_count = is_elf32 ? GET16(h32->ph_entry_count) : GET16(h64->ph_entry_count); - - /* Hash each loadable segment directly from its physical address */ - for (i = 0; i < entry_count; i++) { - elf32_program_header* phdr32; - elf64_program_header* phdr64; - uint32_t type; - uintptr_t paddr; - uintptr_t file_size; - - /* Read program header into buffer */ -#ifdef EXT_FLASH - if (PART_IS_EXT(img)) { - ext_flash_check_read((uintptr_t)(img->fw_base) + ph_offset + (i * entry_size), - program_header_buf, entry_size); - } else -#endif - { - memcpy(program_header_buf, - (uint8_t*)(img->fw_base) + ph_offset + (i * entry_size), - entry_size); - } - - - phdr32 = (elf32_program_header*)program_header_buf; - phdr64 = (elf64_program_header*)program_header_buf; - type = (is_elf32 ? GET32(phdr32->type) : GET32(phdr64->type)); - paddr = (is_elf32 ? GET32(phdr32->paddr) : GET64(phdr64->paddr)); - file_size = (is_elf32 ? GET32(phdr32->file_size) : GET64(phdr64->file_size)); - - /* Only hash PT_LOAD segments with non-zero size */ - if (type == ELF_PT_LOAD && file_size > 0) { -#ifdef DEBUG_ELF - wolfBoot_printf("Hashing segment at %p (%d bytes)\r\n", (void*)paddr, (uint32_t)file_size); -#endif - /* Hash the segment data from physical address in blocks */ - uint32_t pos = 0; - while (pos < file_size) { - uint8_t *block; - uint32_t blksz = WOLFBOOT_SHA_BLOCK_SIZE; - - if (pos + blksz > file_size) { - blksz = file_size - pos; - } - - block = get_sha_block_ptr(img, (const uint8_t *)(paddr + pos)); - if (block == NULL) { - return -1; - } - -#if defined(WOLFBOOT_HASH_SHA256) - wc_Sha256Update(&sha256_ctx, block, blksz); -#elif defined(WOLFBOOT_HASH_SHA384) - wc_Sha384Update(&sha384_ctx, block, blksz); -#elif defined(WOLFBOOT_HASH_SHA3_384) - wc_Sha3_384_Update(&sha3_384_ctx, block, blksz); -#endif - pos += blksz; - } - } - } - - /* Finalize hash */ -#if defined(WOLFBOOT_HASH_SHA256) - wc_Sha256Final(&sha256_ctx, hash); -#elif defined(WOLFBOOT_HASH_SHA384) - wc_Sha384Final(&sha384_ctx, hash); -#elif defined(WOLFBOOT_HASH_SHA3_384) - wc_Sha3_384_Final(&sha3_384_ctx, hash); -#endif - - return 0; -} -#endif /* WOLFBOOT_ELF */ - /** * @brief Convert a 32-bit integer from little-endian to native byte order. * diff --git a/src/update_flash.c b/src/update_flash.c index 44ea69b2..7df4033c 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -38,350 +38,6 @@ int WP11_Library_Init(void); #endif -#ifdef WOLFBOOT_ELF -#include "elf.h" -#ifdef WOLFBOOT_HASH_SHA256 -#include "wolfssl/wolfcrypt/sha256.h" -#endif -#ifdef WOLFBOOT_HASH_SHA384 -#include "wolfssl/wolfcrypt/sha384.h" -#endif -#ifdef WOLFBOOT_HASH_SHA3_384 -#include "wolfssl/wolfcrypt/sha3_384.h" -#endif -#endif /* WOLFBOOT_ELF */ - -#ifdef WOLFBOOT_ELF -/** - * -------------------------------------------------------------------------------- - * ELF XIP Update Scheme Overview - * -------------------------------------------------------------------------------- - * This module implements a secure update mechanism for ELF files that can be - * executed in place (XIP) from flash. The implementation uses standard wolfBoot - * signature verification plus an additional scattered hash verification: - * - * 1. Standard wolfBoot Signature: Used to verify the authenticity and integrity - * of the entire ELF image as stored in the partition - * - Leverages existing wolfBoot signature verification mechanism - * - Verifies the entire image during update and at boot time - * - * 2. Scattered Hash: A hash of all PT_LOAD segments in their XIP memory locations - * - Computed by hashing loadable segments in ascending physical address order - * - Stored in a custom TLV in the wolfBoot image header, which is covered by - * the image signature, thus guaranteeing its authenticity - * - Verifies that segments loaded to their XIP addresses match the original - * contents of the ELF file - * - * Update Process: - * 1. Standard wolfBoot verification of the stored elf file in the update partition - * 2. Perform the standard three-way interruptible partition swap (update -> boot) - * 3. Set boot partition state to IMG_STATE_ELF_LOADING - * 4. Parse ELF headers from the boot partition and load each PT_LOAD segment to its XIP address - * 5. Compute scattered hash of loaded segments and verify against the authenticated - * scattered hash TLV from the image header - * 6. If process is interrupted during scatter loading/verification, the scatter load from the - * boot partition is restarted - * 7. If verification succeeds, set boot partition to IMG_STATE_TESTING, extract entry point from - * ELF header and boot - * 8. If verification fails, the boot partition is rolled back to the previous state (update) - * and the update process is restarted - * - * Boot Process: - * 1. Standard wolfBoot verification of the boot image signature - * 2. Additionally verify the scattered hash by hashing PT_LOAD - * segments in their XIP locations and comparing with the authenticated hash - * from the image header - * 3. If verification succeeds, extract entry point from ELF header and boot - * 4. If verification fails, the boot partition is rolled back to the previous state (update) - * and the new boot partition is scatter loaded and verified - * - * The update process is failsafe and interruptible. If power is lost during - * ELF loading, the system can resume from where it left off (or close to it) on next boot. - */ - -/** - * @brief Load ELF segments to their runtime memory addresses in flash - * - * @param img Pointer to the wolfBoot image - * @return 0 on success, negative value on error - */ -static int wolfBoot_elf_load_segments(struct wolfBoot_image* img) -{ - uint8_t elf_header_buf[sizeof(elf64_header)]; - uint8_t program_header_buf[sizeof(elf64_program_header)]; - elf32_header* h32; - elf64_header* h64; - uint16_t entry_count, entry_size; - uint32_t ph_offset; - int is_elf32, is_le, i; - int ret = 0; - -#ifdef DEBUG_ELF - wolfBoot_printf("Loading ELF segments to XIP flash from %p\r\n", - (void*)(img->fw_base)); -#endif - -#ifdef EXT_FLASH - if (PART_IS_EXT(img)) { - /* Read ELF header from external flash */ - ext_flash_check_read((uintptr_t)(img->fw_base), elf_header_buf, sizeof(elf64_header)); - } else { - memcpy(elf_header_buf, (void*)(img->fw_base), sizeof(elf64_header)); - } -#else - memcpy(elf_header_buf, (void*)(img->fw_base), sizeof(elf64_header)); -#endif - - h32 = (elf32_header*)elf_header_buf; - h64 = (elf64_header*)elf_header_buf; - - /* Verify ELF header */ - if (memcmp(h32->ident, ELF_IDENT_STR, 4) != 0) { - return -1; /* not valid header identifier */ - } - - /* Load class and endianess */ - is_elf32 = (h32->ident[4] == ELF_CLASS_32); - is_le = (h32->ident[5] == ELF_ENDIAN_LITTLE); - (void)is_le; - - /* Verify this is an executable */ - if ((is_elf32 ? GET16(h32->type) : GET16(h64->type)) != ELF_HET_EXEC) { - return -2; /* not executable */ - } - -#ifdef DEBUG_ELF - wolfBoot_printf("Found valid elf%d (%s endian) for XIP loading\r\n", - is_elf32 ? 32 : 64, is_le ? "little" : "big"); -#endif - - /* Get program headers info */ - ph_offset = is_elf32 ? GET32(h32->ph_offset) : GET32(h64->ph_offset); - entry_size = is_elf32 ? GET16(h32->ph_entry_size) : GET16(h64->ph_entry_size); - entry_count = is_elf32 ? GET16(h32->ph_entry_count) : GET16(h64->ph_entry_count); - -#ifdef DEBUG_ELF - wolfBoot_printf("Program Headers %d (size %d)\r\n", entry_count, - entry_size); -#endif - - /* We need to unlock flash before writing */ - hal_flash_unlock(); -#ifdef EXT_FLASH - ext_flash_unlock(); -#endif - - for (i = 0; i < entry_count; i++) { - uint32_t type; - uintptr_t paddr, vaddr, mem_size, offset, file_size; - - /* Read program header */ -#ifdef EXT_FLASH - if (PART_IS_EXT(img)) { - ext_flash_check_read((uintptr_t)(img->fw_base + ph_offset + (i * entry_size)), - program_header_buf, entry_size); - } else -#endif - { - memcpy(program_header_buf, (void*)(img->fw_base + ph_offset + (i * entry_size)), entry_size); - } - - if (is_elf32) { - elf32_program_header* e32 = (elf32_program_header*)program_header_buf; - type = GET32(e32->type); - paddr = GET32(e32->paddr); - vaddr = GET32(e32->vaddr); - mem_size = GET32(e32->mem_size); - offset = GET32(e32->offset); - file_size = GET32(e32->file_size); - } else { - elf64_program_header* e64 = (elf64_program_header*)program_header_buf; - type = GET32(e64->type); - paddr = GET64(e64->paddr); - vaddr = GET64(e64->vaddr); - mem_size = GET64(e64->mem_size); - offset = GET64(e64->offset); - file_size = GET64(e64->file_size); - } - - if (type != ELF_PT_LOAD || mem_size == 0) { - continue; - } - -#ifdef DEBUG_ELF - if (file_size > 0) { - wolfBoot_printf("Load %u bytes (offset %p) to %p (p %p)\r\n", - (uint32_t)mem_size, (void*)offset, (void*)vaddr, - (void*)paddr); - } - if (mem_size > file_size) { - wolfBoot_printf("Clear %u bytes at %p (p %p)\r\n", - (uint32_t)(mem_size - file_size), (void*)vaddr, - (void*)paddr); - } -#endif - - /* Use physical address for XIP */ - if (file_size > 0) { - uint8_t buffer[WOLFBOOT_SECTOR_SIZE]; - uint32_t pos = 0; - uint32_t chunk_size; - - /* Erase the target flash area before writing */ - /* TODO: THis could erase data outside the region we want to program - * - AURIX HAL handles read/modify/erase/write but not sure all HALs - * do...need to do this manually here and do erases before writes */ - /* wb_flash_erase(img, paddr, mem_size); */ - - /* Copy the segment data to flash in chunks */ - while (pos < file_size) { - chunk_size = (file_size - pos > sizeof(buffer)) ? - sizeof(buffer) : (file_size - pos); - -#ifdef EXT_FLASH - if (PART_IS_EXT(img)) { - ext_flash_check_read((uintptr_t)(img->fw_base + offset + pos), - buffer, chunk_size); - } else -#endif - { - memcpy(buffer, (void*)(img->fw_base + offset + pos), chunk_size); - } - - if (wb_flash_write(img, paddr + pos, buffer, chunk_size) < 0) { - ret = -3; - break; - } - - pos += chunk_size; - } - - /* If mem_size > file_size, we need to zero out the rest */ - if (mem_size > file_size && ret == 0) { - uint8_t zero_buf[64]; - uint32_t to_clear = mem_size - file_size; - uint32_t chunk, zero_pos = 0; - - /* Initialize zero buffer */ - memset(zero_buf, 0, sizeof(zero_buf)); - - /* Zero out remainder in chunks */ - while (to_clear > 0) { - chunk = (to_clear > sizeof(zero_buf)) ? sizeof(zero_buf) : to_clear; - - if (wb_flash_write(img, paddr + file_size + zero_pos, zero_buf, chunk) < 0) { - ret = -5; - break; - } - - zero_pos += chunk; - to_clear -= chunk; - } - } - - if (ret != 0) { - break; - } - } - -#ifdef ARCH_PPC - flush_cache(paddr, mem_size); -#endif - } - - /* Lock flash after writing */ -#ifdef EXT_FLASH - ext_flash_lock(); -#endif - hal_flash_lock(); - - return ret; -} - -/** - * @brief Verify that the scattered hash matches the one stored in the image - * header - * - * @param img Pointer to the wolfBoot image - * @return 0 on success, negative value on error - */ -static int wolfBoot_verify_scattered_hash(struct wolfBoot_image* img) -{ - int ret; - uint8_t computed_hash[WOLFBOOT_SHA_DIGEST_SIZE]; - uint8_t* stored_hash; - uint16_t stored_hash_len; - - /* Compute scattered hash */ - ret = wolfBoot_compute_scattered_hash(img, computed_hash); - if (ret != 0) { - return ret; - } - - /* Get stored scattered hash from header */ - stored_hash_len = - wolfBoot_get_header(img, HDR_ELF_SCATTERED_HASH, &stored_hash); - if (stored_hash_len != WOLFBOOT_SHA_DIGEST_SIZE) { - return -1; /* Scattered hash not found or invalid size */ - } - - /* Compare hashes */ - if (memcmp(computed_hash, stored_hash, WOLFBOOT_SHA_DIGEST_SIZE) != 0) { - return -2; /* Hash mismatch */ - } - - return 0; /* Success */ -} - -/** - * @brief Check if an image is an ELF file - * - * @param img Pointer to the wolfBoot image - * @return 1 if ELF, 0 if not - */ -static int is_elf_image(struct wolfBoot_image* img) -{ - elf32_header h32; - -#ifdef EXT_FLASH - if (PART_IS_EXT(img)) { - /* Read ELF header from external flash */ - ext_flash_check_read((uintptr_t)(img->fw_base), (uint8_t*)&h32, sizeof(elf32_header)); - } else { - memcpy(&h32, (void*)(img->fw_base), sizeof(elf32_header)); - } -#else - memcpy(&h32, (void*)(img->fw_base), sizeof(elf32_header)); -#endif - - if (memcmp(h32.ident, ELF_IDENT_STR, 4) == 0) { - return 1; - } - return 0; -} - - -/* Scatter loads an ELF image from boot partition if it is an ELF image */ -static void check_and_load_boot_elf(struct wolfBoot_image* boot) -{ - /* Check if this is an ELF image */ - if (is_elf_image(&boot)) { - /* Set state to ELF_LOADING before starting scatter load */ - wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_ELF_LOADING); - - /* Load ELF segments to their XIP addresses */ - if (wolfBoot_elf_load_segments(&boot) != 0) { - wolfBoot_printf("Failed to load ELF segments\n"); - wolfBoot_panic(); - } - - /* If we get here, ELF loading and verification succeeded */ - wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_TESTING); - } -} - -#endif /* WOLFBOOT_ELF */ - #ifdef RAM_CODE #ifndef TARGET_rp2350 extern unsigned int _start_text; @@ -583,9 +239,6 @@ static int wolfBoot_swap_and_final_erase(int resume) struct wolfBoot_image update[1]; struct wolfBoot_image swap[1]; uint8_t updateState; -#ifdef WOLFBOOT_ELF - uint8_t bootState; -#endif int eraseLen = (WOLFBOOT_SECTOR_SIZE #ifdef NVM_FLASH_WRITEONCE /* need to erase the redundant sector too */ * 2 @@ -601,45 +254,6 @@ static int wolfBoot_swap_and_final_erase(int resume) wolfBoot_open_image(update, PART_UPDATE); wolfBoot_open_image(swap, PART_SWAP); wolfBoot_get_partition_state(PART_UPDATE, &updateState); -#ifdef WOLFBOOT_ELF - wolfBoot_get_partition_state(PART_BOOT, &bootState); -#endif - - -#ifdef WOLFBOOT_ELF - if ((resume == 1) && (is_elf_image(boot))) { - /* If we're resuming an interrupted elf load, we can skip the image swap - * since we know it was already completed */ - if (bootState == IMG_STATE_ELF_LOADING) { - hal_flash_unlock(); -#ifdef EXT_FLASH - ext_flash_unlock(); -#endif - - /* Load ELF segments to their XIP addresses */ - if (wolfBoot_elf_load_segments(&boot) != 0) { - wolfBoot_printf("Failed to load ELF segments\n"); - wolfBoot_panic(); - } - - wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_TESTING); - - /* Only after successful ELF loading, erase update partition state - */ - if (updateState == IMG_STATE_FINAL_FLAGS) { - wb_flash_erase(update, WOLFBOOT_PARTITION_SIZE - eraseLen, - eraseLen); - } - -#ifdef EXT_FLASH - ext_flash_lock(); -#endif - hal_flash_lock(); - return 0; - } - } -#endif - /* read trailer */ #if defined(EXT_FLASH) && PARTN_IS_EXT(PART_BOOT) @@ -657,9 +271,6 @@ static int wolfBoot_swap_and_final_erase(int resume) /* if resuming, quit if swap isn't done */ if ((resume == 1) && (swapDone == 0) && (updateState != IMG_STATE_FINAL_FLAGS) -#ifdef WOLFBOOT_ELF - && (bootState != IMG_STATE_ELF_LOADING) -#endif ) { return -1; } @@ -705,15 +316,8 @@ static int wolfBoot_swap_and_final_erase(int resume) wb_flash_erase(boot, tmpBootPos, WOLFBOOT_SECTOR_SIZE); } -#ifdef WOLFBOOT_ELF - /* load elf file from boot partition if applicable. This sets the boot - * partition state to loading during the load and then to testing on success - */ - check_and_load_boot_elf(boot); -#else /* mark boot as TESTING */ wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_TESTING); -#endif /* erase the last sector(s) of update. This resets the update partition state * to IMG_STATE_NEW */ wb_flash_erase(update, WOLFBOOT_PARTITION_SIZE - eraseLen, eraseLen); @@ -1238,9 +842,6 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed) sector++; } -#ifdef WOLFBOOT_ELF - check_and_load_boot_elf(&boot); -#endif wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_SUCCESS); @@ -1433,9 +1034,6 @@ void RAMFUNCTION wolfBoot_start(void) if (bootRet < 0 || (wolfBoot_verify_integrity(&boot) < 0) || (wolfBoot_verify_authenticity(&boot) < 0) -#ifdef WOLFBOOT_ELF - || (is_elf_image(&boot) && wolfBoot_verify_scattered_elf(&boot) < 0) -#endif ) { wolfBoot_printf("Boot failed: Hdr %d, Hash %d, Sig %d\n", boot.hdr_ok, boot.sha_ok, boot.signature_ok); @@ -1452,9 +1050,6 @@ void RAMFUNCTION wolfBoot_start(void) if (likely(((wolfBoot_open_image(&boot, PART_BOOT) < 0) || (wolfBoot_verify_integrity(&boot) < 0) || (wolfBoot_verify_authenticity(&boot) < 0) -#ifdef WOLFBOOT_ELF - || (is_elf_image(&boot) && wolfBoot_verify_scattered_elf(&boot) < 0) -#endif ))) { wolfBoot_printf("Boot (try 2) failed: Hdr %d, Hash %d, Sig %d\n", boot.hdr_ok, boot.sha_ok, boot.signature_ok); diff --git a/test-app/Makefile b/test-app/Makefile index f25c91b4..f66cd20d 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -227,7 +227,7 @@ ifeq ($(TARGET),ti_hercules) endif ifeq ($(TARGET),sim) - APP_OBJS=app_$(TARGET).o ../test-app/libwolfboot.o ../hal/$(TARGET).o + APP_OBJS+=../test-app/libwolfboot.o ../hal/$(TARGET).o # LD on MacOS does not support "-Map=" LDMAPSUPPORTED=$(shell $(CC) -Wl,-Map=image.map 2>&1 | grep 'unknown option') LDFLAGS= @@ -239,6 +239,14 @@ ifeq ($(TARGET),sim) # Override linker flags LDFLAGS+=-Wl,-Map=image.map endif + ifeq ($(ELF_SCATTERED),1) + LSCRIPT_TEMPLATE=sim_scattered.ld + APP_OBJS=app_sim_scattered.o ../src/elf.o ../src/string.o + CFLAGS+=-D"ELF_SCATTERED=1" -nostartfiles -ffreestanding -static -nostdlib + LDFLAGS+=-ffreestanding -nostartfiles -static -T$(LSCRIPT) -nostdlib + else + APP_OBJS=app_sim.o + endif endif ifeq ($(EXT_FLASH),1)