diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index dc2b3fc168..2b282fe8e6 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -220,6 +220,18 @@ jobs: config-file: ./config/examples/sim.config make-args: CFLAGS_EXTRA=-DWOLFBOOT_FLASH_MULTI_SECTOR_ERASE + sim_elf_scattered: + uses: ./.github/workflows/test-build.yml + with: + arch: host + config-file: ./config/examples/sim-elf-scattered.config + + sim_elf_scattered_nobackup: + uses: ./.github/workflows/test-build.yml + with: + arch: host + config-file: ./config/examples/sim-elf-scattered.config + make-args: DISABLE_BACKUP=1 # TODO: SP math with small stack has issues diff --git a/.github/workflows/test-elf-scattered.yml b/.github/workflows/test-elf-scattered.yml new file mode 100644 index 0000000000..d8f432fed5 --- /dev/null +++ b/.github/workflows/test-elf-scattered.yml @@ -0,0 +1,36 @@ +name: Test for scattered elf validation + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +jobs: + elf_scattered_test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: make clean + run: | + make keysclean + + - name: Select config + run: | + cp config/examples/sim.config .config + + - name: Build tools + run: | + make -C tools/keytools && make -C tools/bin-assemble + + - name: Build wolfboot.elf + run: | + make clean && make test-sim-internal-flash-with-update ELF=1 ELF_SCATTERED=1 + + - name: Run bootloader with no arguments + run: | + ./wolfboot.elf diff --git a/.github/workflows/test-renode-fastmath-smallstack.yml b/.github/workflows/test-renode-fastmath-smallstack.yml index bf4e11a48b..3a94cf60ef 100644 --- a/.github/workflows/test-renode-fastmath-smallstack.yml +++ b/.github/workflows/test-renode-fastmath-smallstack.yml @@ -8,7 +8,7 @@ on: jobs: renode_automated_fastmath_smallstack: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test-renode-fastmath.yml b/.github/workflows/test-renode-fastmath.yml index 838a457295..60e034dc6f 100644 --- a/.github/workflows/test-renode-fastmath.yml +++ b/.github/workflows/test-renode-fastmath.yml @@ -8,7 +8,7 @@ on: jobs: renode_automated_fastmath: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/test-renode-noasm-smallstack.yml b/.github/workflows/test-renode-noasm-smallstack.yml index 66d796db66..f72515071a 100644 --- a/.github/workflows/test-renode-noasm-smallstack.yml +++ b/.github/workflows/test-renode-noasm-smallstack.yml @@ -8,7 +8,7 @@ on: jobs: renode_automated_noasm_smallstack: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test-renode-noasm.yml b/.github/workflows/test-renode-noasm.yml index 40b385bd6c..547b311ca0 100644 --- a/.github/workflows/test-renode-noasm.yml +++ b/.github/workflows/test-renode-noasm.yml @@ -8,7 +8,7 @@ on: jobs: renode_automated_noasm: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test-renode-nrf52.yml b/.github/workflows/test-renode-nrf52.yml index a447eb6b71..276bbfe366 100644 --- a/.github/workflows/test-renode-nrf52.yml +++ b/.github/workflows/test-renode-nrf52.yml @@ -8,7 +8,7 @@ on: jobs: renode_automated_base: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test-renode-sha3.yml b/.github/workflows/test-renode-sha3.yml index 2ceb2b1e11..9b0dbe5fb4 100644 --- a/.github/workflows/test-renode-sha3.yml +++ b/.github/workflows/test-renode-sha3.yml @@ -8,7 +8,7 @@ on: jobs: renode_automated_multi_sha: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test-renode-sha384.yml b/.github/workflows/test-renode-sha384.yml index 2caab8057d..cd581b06e4 100644 --- a/.github/workflows/test-renode-sha384.yml +++ b/.github/workflows/test-renode-sha384.yml @@ -8,7 +8,7 @@ on: jobs: renode_automated_multi_sha: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/test-renode-smallstack.yml b/.github/workflows/test-renode-smallstack.yml index ce25254a9a..b32b0c007e 100644 --- a/.github/workflows/test-renode-smallstack.yml +++ b/.github/workflows/test-renode-smallstack.yml @@ -8,7 +8,7 @@ on: jobs: renode_automated_smallstack: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/CMakeLists.txt b/CMakeLists.txt index 13272bd7f7..4190bb990b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,9 @@ project(wolfBoot) include(cmake/utils.cmake) include(cmake/functions.cmake) +include_directories(include) +include_directories(lib/wolfssl) + if(NOT DEFINED WOLFBOOT_TARGET) message(FATAL_ERROR "WOLFBOOT_TARGET must be defined") else() @@ -620,6 +623,8 @@ if(NOT SPMATH AND NOT SPMATHALL) list(APPEND USER_SETTINGS USE_FAST_MATH) endif() +list(APPEND WOLFBOOT_DEFS WOLFSSL_USER_SETTINGS) + add_library(user_settings INTERFACE) target_compile_definitions(user_settings INTERFACE ${USER_SETTINGS} ${SIGN_OPTIONS}) @@ -699,7 +704,7 @@ configure_file(include/target.h.in ${CMAKE_CURRENT_BINARY_DIR}/target.h @ONLY) add_library(target INTERFACE) target_compile_definitions(target INTERFACE ${WOLFBOOT_DEFS}) -target_include_directories(target BEFORE INTERFACE ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(target BEFORE INTERFACE ${CMAKE_CURRENT_BINARY_DIR} lib/wolfssl) set(KEYSTORE ${CMAKE_CURRENT_BINARY_DIR}/keystore.c) diff --git a/arch.mk b/arch.mk index 0e74a91744..54d0d513bd 100644 --- a/arch.mk +++ b/arch.mk @@ -253,7 +253,7 @@ ifeq ($(ARCH),ARM) CORTEX_A5=1 UPDATE_OBJS:=src/update_ram.o CFLAGS+=-DWOLFBOOT_DUALBOOT -DEXT_FLASH -DNAND_FLASH -fno-builtin -ffreestanding - #CFLAGS+=-DWOLFBOOT_USE_STDLIBC + CFLAGS+=-DWOLFBOOT_USE_STDLIBC endif ## Cortex CPU @@ -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/config/examples/sim-elf-scattered.config b/config/examples/sim-elf-scattered.config new file mode 100644 index 0000000000..ed12b52a4f --- /dev/null +++ b/config/examples/sim-elf-scattered.config @@ -0,0 +1,28 @@ +ARCH=sim +TARGET=sim +SIGN?=ED25519 +HASH?=SHA256 +WOLFBOOT_SMALL_STACK?=0 +SPI_FLASH=0 +DEBUG=1 +ELF_SCATTERED=1 +ELF=1 + + +# sizes should be multiple of system page size +WOLFBOOT_PARTITION_SIZE=0x40000 +WOLFBOOT_SECTOR_SIZE=0x1000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80000 +# if on external flash, it should be multiple of system page size + +# Address from 0x100000 to 0x1FFFFF is reserved for ELF_SCATTERED + +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x200000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x280000 + + +# required for keytools +WOLFBOOT_FIXED_PARTITIONS=1 + +# For debugging XMALLOC/XFREE +#CFLAGS_EXTRA+=-DWOLFBOOT_DEBUG_MALLOC diff --git a/config/examples/sim32-elf-scattered.config b/config/examples/sim32-elf-scattered.config new file mode 100644 index 0000000000..c546976231 --- /dev/null +++ b/config/examples/sim32-elf-scattered.config @@ -0,0 +1,24 @@ +ARCH=sim +TARGET=sim +SIGN?=ECC256 +HASH?=SHA256 +WOLFBOOT_SMALL_STACK?=0 +SPI_FLASH=0 +DEBUG=1 +FORCE_32BIT=1 +ELF=1 +ELF_SCATTERED=1 + +# sizes should be multiple of system page size +WOLFBOOT_PARTITION_SIZE=0x40000 +WOLFBOOT_SECTOR_SIZE=0x1000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80000 +# if on external flash, it should be multiple of system page size +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x100000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x180000 + +# required for keytools +WOLFBOOT_FIXED_PARTITIONS=1 + +# For debugging XMALLOC/XFREE +#CFLAGS_EXTRA+=-DWOLFBOOT_DEBUG_MALLOC diff --git a/hal/sama5d3.c b/hal/sama5d3.c index 8c79916a57..104c363dee 100644 --- a/hal/sama5d3.c +++ b/hal/sama5d3.c @@ -78,7 +78,7 @@ static int division(uint32_t dividend, return 0; } -static uint32_t div(uint32_t dividend, uint32_t divisor) +static uint32_t div_u(uint32_t dividend, uint32_t divisor) { uint32_t quotient = 0; uint32_t remainder = 0; @@ -504,7 +504,7 @@ static void nand_read_info(void) nand_flash.bad_block_pos = (*(uint16_t *)(onfi_data + PARAMS_POS_FEATURES)) & 1; nand_flash.ext_page_len = *(uint16_t *)(onfi_data + PARAMS_POS_EXT_PARAM_PAGE_LEN); nand_flash.parameter_page = *(uint16_t *)(onfi_data + PARAMS_POS_PARAMETER_PAGE); - nand_flash.pages_per_block = div(nand_flash.block_size, nand_flash.page_size); + nand_flash.pages_per_block = div_u(nand_flash.block_size, nand_flash.page_size); nand_flash.pages_per_device = nand_flash.pages_per_block * nand_flash.block_count; nand_flash.oob_size = *(uint16_t *)(onfi_data + PARAMS_POS_OOBSIZE); nand_flash.revision = *(uint16_t *)(onfi_data + PARAMS_POS_REVISION); @@ -605,8 +605,8 @@ static int nand_check_bad_block(uint32_t block) int ext_flash_read(uintptr_t address, uint8_t *data, int len) { uint8_t buffer_page[NAND_FLASH_PAGE_SIZE]; - uint32_t block = div(address, nand_flash.block_size); /* The block where the address falls in */ - uint32_t page = div(address, nand_flash.page_size); /* The page where the address falls in */ + uint32_t block = div_u(address, nand_flash.block_size); /* The block where the address falls in */ + uint32_t page = div_u(address, nand_flash.page_size); /* The page where the address falls in */ uint32_t start_page_in_block = mod(page, nand_flash.pages_per_block); /* The start page within this block */ uint32_t in_block_offset = mod(address, nand_flash.block_size); /* The offset of the address within the block */ uint32_t remaining = nand_flash.block_size - in_block_offset; /* How many bytes remaining to read in the first block */ @@ -637,7 +637,7 @@ int ext_flash_read(uintptr_t address, uint8_t *data, int len) } while (ret < 0); /* Amount of pages to be read from this block */ - pages_to_read = div((sz + nand_flash.page_size - 1), nand_flash.page_size); + pages_to_read = div_u((sz + nand_flash.page_size - 1), nand_flash.page_size); if (pages_to_read * nand_flash.page_size > remaining) pages_to_read--; diff --git a/hal/sim.c b/hal/sim.c index 1816374d21..9473a41d5a 100644 --- a/hal/sim.c +++ b/hal/sim.c @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef __APPLE__ #include @@ -42,6 +43,10 @@ #include "target.h" #include "printf.h" +#ifdef WOLFBOOT_ELF_SCATTERED +#include "elf.h" +#endif + #ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT #include "wolfhsm/wh_error.h" #include "wolfhsm/wh_client.h" @@ -304,6 +309,7 @@ void do_boot(const uint32_t *app_offset) { int ret; size_t app_size = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE; + wolfBoot_printf("Simulator do_boot app_offset = %p\n", app_offset); if (flashLocked == 0) { wolfBoot_printf("WARNING FLASH IS UNLOCKED AT BOOT"); @@ -348,18 +354,34 @@ 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 (WOLFBOOT_ELF_SCATTERED) + uint8_t *entry_point = (sim_ram_base + (unsigned long)app_offset); + printf("entry point: %p\n", entry_point); + printf("app offset: %p\n", app_offset); + typedef int (*main_entry)(int, char**); + main_entry main; + main = (main_entry)(entry_point); + + /* TODO: call main ! */ + /* main(main_argc, main_argv); */ + wolfBoot_printf("Simulator for ELF_SCATTERED image not implemented yet. Exiting...\n"); + exit(0); #else char *envp[1] = {NULL}; int fd = memfd_create("test_app", 0); + size_t wret; if (fd == -1) { wolfBoot_printf( "memfd error\n"); exit(-1); } - if ((size_t)write(fd, app_offset, app_size) != app_size) { - wolfBoot_printf( "can't write test-app to memfd\n"); + wret = write(fd, app_offset, app_size); + if (wret != app_size) { + wolfBoot_printf( "can't write test-app to memfd, address %p\n", app_offset); exit(-1); } + wolfBoot_printf("Stored test-app to memfd, address %p (%zu bytes)\n", app_offset, wret); ret = fexecve(fd, main_argv, envp); wolfBoot_printf( "fexecve error\n"); diff --git a/include/elf.h b/include/elf.h index 419ed2e365..d459ec895f 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) @@ -111,6 +112,11 @@ typedef struct elf64_header { uint16_t sh_str_index; } elf64_header; +union elf_header { + elf32_header *h32; + elf64_header *h64; +}; + typedef struct elf64_section_header { uint32_t name; uint32_t type; @@ -136,9 +142,36 @@ typedef struct elf64_program_header { } elf64_program_header; +/* support byte swapping if testing/reading an elf with different endianess */ +#if defined(ELF_PARSER) || defined(ELF_ENDIAN_SUPPORT) + #ifdef BIG_ENDIAN_ORDER + #define GET16(x) (( is_le) ? __builtin_bswap16(x) : (x)) + #define GET32(x) (( is_le) ? __builtin_bswap32(x) : (x)) + #define GET64(x) (( is_le) ? __builtin_bswap64(x) : (x)) + #else + #define GET16(x) ((!is_le) ? __builtin_bswap16(x) : (x)) + #define GET32(x) ((!is_le) ? __builtin_bswap32(x) : (x)) + #define GET64(x) ((!is_le) ? __builtin_bswap64(x) : (x)) + #endif +#else + #define GET16(x) (x) + #define GET32(x) (x) + #define GET64(x) (x) +#endif + +#define GET_H64(name) (is_elf32 ? GET32(h32->name) : GET64(h64->name)) +#define GET_H32(name) (is_elf32 ? GET32(h32->name) : GET32(h64->name)) +#define GET_H16(name) (is_elf32 ? GET16(h32->name) : GET16(h64->name)) +#define GET_E64(name) (is_elf32 ? GET32(e32->name) : GET64(e64->name)) +#define GET_E32(name) (is_elf32 ? GET32(e32->name) : GET32(e64->name)) + 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); +int elf_check_image_scattered(uint8_t part, unsigned long *entry_out); +int elf_hdr_size(const unsigned char *ehdr); +int elf_open(const unsigned char *ehdr, int *is_elf32); #ifdef __cplusplus diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index faa7bb3a12..ddb539598b 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -79,6 +79,7 @@ extern "C" { #define HDR_SIGNATURE 0x20 #define HDR_POLICY_SIGNATURE 0x21 #define HDR_SECONDARY_SIGNATURE 0x22 +#define HDR_ELF_SCATTERED_HASH 0x23 #define HDR_PADDING 0xFF /* Auth Key types */ @@ -163,31 +164,49 @@ extern "C" { /* Hashing configuration */ #if defined(WOLFBOOT_HASH_SHA256) +# include "wolfssl/wolfcrypt/sha256.h" # ifndef WOLFBOOT_SHA_BLOCK_SIZE # define WOLFBOOT_SHA_BLOCK_SIZE (256) # endif # define WOLFBOOT_SHA_HDR HDR_SHA256 # define WOLFBOOT_SHA_DIGEST_SIZE (32) # define image_hash image_sha256 +# define header_hash header_sha256 +# define update_hash wc_Sha256Update # define key_hash key_sha256 # define self_hash self_sha256 +# define final_hash wc_Sha256Final + typedef wc_Sha256 wolfBoot_hash_t; +# define HDR_HASH HDR_SHA256 #elif defined(WOLFBOOT_HASH_SHA384) +# include "wolfssl/wolfcrypt/sha512.h" # ifndef WOLFBOOT_SHA_BLOCK_SIZE # define WOLFBOOT_SHA_BLOCK_SIZE (256) # endif # define WOLFBOOT_SHA_HDR HDR_SHA384 # define WOLFBOOT_SHA_DIGEST_SIZE (48) # define image_hash image_sha384 +# define header_hash header_sha384 +# define update_hash wc_Sha384Update # define key_hash key_sha384 # define self_hash self_sha384 +# define final_hash wc_Sha384Final + typedef wc_Sha384 wolfBoot_hash_t; +# define HDR_HASH HDR_SHA384 #elif defined(WOLFBOOT_HASH_SHA3_384) +# include "wolfssl/wolfcrypt/sha3.h" # ifndef WOLFBOOT_SHA_BLOCK_SIZE # define WOLFBOOT_SHA_BLOCK_SIZE (128) # endif # define WOLFBOOT_SHA_HDR HDR_SHA3_384 # define WOLFBOOT_SHA_DIGEST_SIZE (48) # define image_hash image_sha3_384 +# define header_hash header_sha3_384 +# define update_hash wc_Sha3Update +# define final_hash wc_Sha3Final # define key_hash key_sha3_384 + typedef wc_Sha3 wolfBoot_hash_t; +# define HDR_HASH HDR_SHA3_384 #else # error "No valid hash algorithm defined!" #endif @@ -291,6 +310,8 @@ extern "C" { /* now just an intermediary state, update state will always be either new or * updating before the application boots*/ #define IMG_STATE_FINAL_FLAGS 0x30 +/* ELF loading state - only valid on boot partition so doesn't conflict with + * IMAGE_STATE_UPDATING */ #define IMG_STATE_TESTING 0x10 #define IMG_STATE_SUCCESS 0x00 #define FLASH_BYTE_ERASED 0xFF diff --git a/options.mk b/options.mk index b346f57c01..5b7238cab3 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"WOLFBOOT_ELF_SCATTERED=1" + endif + endif ifeq ($(MULTIBOOT2),1) diff --git a/src/elf.c b/src/elf.c index 6ef625272d..474d7b6d63 100644 --- a/src/elf.c +++ b/src/elf.c @@ -27,11 +27,16 @@ #include "printf.h" #include "string.h" #include "elf.h" +#include "hal.h" #ifdef ARCH_PPC #include "hal/nxp_ppc.h" #endif +#ifdef WOLFBOOT_ELF_SCATTERED +#include "image.h" +#endif + /* support for elf parsing debug printf */ #if defined(DEBUG) || defined(ELF_PARSER) #if defined(DEBUG_ELF) && DEBUG_ELF == 0 @@ -42,29 +47,8 @@ #endif #endif -/* support byte swapping if testing/reading an elf with different endianess */ -#if defined(ELF_PARSER) || defined(ELF_ENDIAN_SUPPORT) - #ifdef BIG_ENDIAN_ORDER - #define GET16(x) (( is_le) ? __builtin_bswap16(x) : (x)) - #define GET32(x) (( is_le) ? __builtin_bswap32(x) : (x)) - #define GET64(x) (( is_le) ? __builtin_bswap64(x) : (x)) - #else - #define GET16(x) ((!is_le) ? __builtin_bswap16(x) : (x)) - #define GET32(x) ((!is_le) ? __builtin_bswap32(x) : (x)) - #define GET64(x) ((!is_le) ? __builtin_bswap64(x) : (x)) - #endif -#else - #define GET16(x) (x) - #define GET32(x) (x) - #define GET64(x) (x) -#endif - -#define GET_H64(name) (is_elf32 ? GET32(h32->name) : GET64(h64->name)) -#define GET_H32(name) (is_elf32 ? GET32(h32->name) : GET32(h64->name)) -#define GET_H16(name) (is_elf32 ? GET16(h32->name) : GET16(h64->name)) -#define GET_E64(name) (is_elf32 ? GET32(e32->name) : GET64(e64->name)) -#define GET_E32(name) (is_elf32 ? GET32(e32->name) : GET32(e64->name)) +#if defined(MMU) || defined (WOLFBOOT_FSP) || defined (ARCH_PPC) /* Loader for elf32 or elf64 format program headers * Returns the entry point function */ @@ -165,11 +149,145 @@ int elf_load_image_mmu(uint8_t *image, uintptr_t *entry, elf_mmu_map_cb mmu_cb) return 0; } +#endif /* MMU || WOLFBOOT_FSP || ARCH_PPC */ -int elf_load_image(uint8_t *image, uintptr_t *entry) +int elf_open(const unsigned char *ehdr, int *is_elf32) { + const unsigned char *ident = ehdr; + /* Verify ELF header */ + if (memcmp(ident, ELF_IDENT_STR, 4) != 0) { + return -1; /* not valid header identifier */ + } + wolfBoot_printf("ELF image found\n"); + *is_elf32 = !!(ident[ELF_CLASS_OFF] == ELF_CLASS_32); + return 0; + +} + +int elf_hdr_size(const unsigned char *ehdr) +{ + int sz = 0; + int is_elf32; + if (elf_open(ehdr, &is_elf32) != 0) + return -1; + if (is_elf32) { + const elf32_header *elf32_hdr = (const elf32_header *)ehdr; + sz = sizeof(elf32_header); + sz += elf32_hdr->ph_entry_count * sizeof(elf32_program_header); + } else { + const elf64_header *elf64_hdr = (const elf64_header *)ehdr; + sz = sizeof(elf64_header); + sz += elf64_hdr->ph_entry_count * sizeof(elf64_program_header); + } + return sz; +} +#if !defined(MMU) && !defined(WOLFBOOT_FSP) && !defined(ARCH_PPC) && defined (WOLFBOOT_ELF_SCATTERED) + +#ifdef ARCH_SIM +# define BASE_OFF ARCH_FLASH_OFFSET +#else +# define BASE_OFF 0 +#endif + +int elf_store_image_scattered(const unsigned char *hdr, unsigned long *entry_out, int ext_flash) { + const unsigned char *image; + int is_elf32; + unsigned short entry_count; + unsigned long entry_off; + int i; + image = hdr + IMAGE_HEADER_SIZE; + if (elf_open(image, &is_elf32) != 0) { + return -1; + } + if (is_elf32) { + const elf32_header *eh; + const elf32_program_header *ph; + wolfBoot_printf("ELF image is 32 bit\n"); + + eh = (const elf32_header *)image; + entry_count = eh->ph_entry_count; + 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; + wolfBoot_printf("Writing section at address %lx offset %lx\n", paddr, offset); +#ifdef EXT_FLASH + if (ext_flash) { + ext_flash_unlock(); + ext_flash_erase(paddr + BASE_OFF, filesz); + ext_flash_write(paddr + BASE_OFF, image + offset, filesz); + ext_flash_lock(); + } + else +#endif + { + hal_flash_unlock(); + hal_flash_erase(paddr + BASE_OFF, filesz); + hal_flash_write(paddr + BASE_OFF, image + offset, filesz); + hal_flash_lock(); + } + } + } else { /* 64 bit ELF */ + const elf64_header *eh; + const elf64_program_header *ph; + wolfBoot_printf("ELF image is 64 bit\n"); + + eh = (const elf64_header *)image; + entry_count = eh->ph_entry_count; + 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; + wolfBoot_printf("Writing section at address %lx offset %lx\n", paddr, offset); +#ifdef EXT_FLASH + if (ext_flash) { + ext_flash_unlock(); + ext_flash_erase(paddr + BASE_OFF, filesz); + ext_flash_write(paddr + BASE_OFF, image + offset, filesz); + ext_flash_lock(); + } + else +#endif + { + hal_flash_unlock(); + hal_flash_erase(paddr + BASE_OFF, filesz); + hal_flash_write(paddr + BASE_OFF, image + offset, filesz); + hal_flash_lock(); + } + } + } + return 0; +} +#endif /* !defined(MMU) && !defined(WOLFBOOT_FSP) && !defined(ARCH_PPC) && defined (WOLFBOOT_ELF_SCATTERED) */ + + +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, (unsigned long *)entry, ext_flash); +#endif } #endif /* WOLFBOOT_ELF */ diff --git a/src/image.c b/src/image.c index 6d950d714b..a9dbf820f9 100644 --- a/src/image.c +++ b/src/image.c @@ -818,22 +818,13 @@ static uint8_t *get_img_hdr(struct wolfBoot_image *img) #if defined(WOLFBOOT_HASH_SHA256) #include -/** - * @brief Calculate the SHA256 hash of the image. - * - * @param img The image to calculate the hash for. - * @param hash A pointer to store the resulting SHA256 hash. - * @return 0 on success, -1 on failure. - */ -static int image_sha256(struct wolfBoot_image *img, uint8_t *hash) +/* Initialize and hash the header part */ +static int header_sha256(wc_Sha256 *sha256_ctx, struct wolfBoot_image *img) { uint8_t *stored_sha, *end_sha; uint16_t stored_sha_len; uint8_t *p; int blksz; - uint32_t position = 0; - wc_Sha256 sha256_ctx; - if (!img) return -1; @@ -842,18 +833,37 @@ static int image_sha256(struct wolfBoot_image *img, uint8_t *hash) if (stored_sha_len != WOLFBOOT_SHA_DIGEST_SIZE) return -1; #ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT - (void)wc_InitSha256_ex(&sha256_ctx, NULL, hsmClientDevIdHash); + (void)wc_InitSha256_ex(sha256_ctx, NULL, hsmClientDevIdHash); #else - wc_InitSha256(&sha256_ctx); + wc_InitSha256(sha256_ctx); #endif end_sha = stored_sha - (2 * sizeof(uint16_t)); /* Subtract 2 Type + 2 Len */ while (p < end_sha) { blksz = WOLFBOOT_SHA_BLOCK_SIZE; if (end_sha - p < blksz) blksz = end_sha - p; - wc_Sha256Update(&sha256_ctx, p, blksz); + wc_Sha256Update(sha256_ctx, p, blksz); p += blksz; } + return 0; +} + +/** + * @brief Calculate the SHA256 hash of the image. + * + * @param img The image to calculate the hash for. + * @param hash A pointer to store the resulting SHA256 hash. + * @return 0 on success, -1 on failure. + */ +static int image_sha256(struct wolfBoot_image *img, uint8_t *hash) +{ + uint32_t position = 0; + uint8_t *p; + int blksz; + wc_Sha256 sha256_ctx; + + if (header_sha256(&sha256_ctx, img) != 0) + return -1; do { p = get_sha_block(img, position); if (p == NULL) @@ -899,24 +909,13 @@ static void key_sha256(uint8_t key_slot, uint8_t *hash) #if defined(WOLFBOOT_HASH_SHA384) #include -/** - * @brief Calculate SHA-384 hash of the image. - * - * This function calculates the SHA-384 hash of the given image. - * - * @param img The pointer to the wolfBoot_image structure representing the image. - * @param hash The buffer to store the SHA-384 hash (48 bytes). - * @return 0 on success, -1 on error. - */ -static int image_sha384(struct wolfBoot_image *img, uint8_t *hash) +/* Initialize and hash the header part */ +static int header_sha384(wc_Sha384 *sha384_ctx, struct wolfBoot_image *img) { - uint8_t *stored_sha, *end_sha; uint16_t stored_sha_len; + uint8_t *stored_sha, *end_sha; uint8_t *p; int blksz; - uint32_t position = 0; - wc_Sha384 sha384_ctx; - if (!img) return -1; @@ -924,15 +923,41 @@ static int image_sha384(struct wolfBoot_image *img, uint8_t *hash) stored_sha_len = get_header(img, HDR_SHA384, &stored_sha); if (stored_sha_len != WOLFBOOT_SHA_DIGEST_SIZE) return -1; - wc_InitSha384(&sha384_ctx); +#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT + (void)wc_InitSha384_ex(sha384_ctx, NULL, hsmClientDevIdHash); +#else + wc_InitSha384(sha384_ctx); +#endif end_sha = stored_sha - (2 * sizeof(uint16_t)); /* Subtract 2 Type + 2 Len */ while (p < end_sha) { blksz = WOLFBOOT_SHA_BLOCK_SIZE; if (end_sha - p < blksz) blksz = end_sha - p; - wc_Sha384Update(&sha384_ctx, p, blksz); + wc_Sha384Update(sha384_ctx, p, blksz); p += blksz; } + return 0; +} + + +/** + * @brief Calculate SHA-384 hash of the image. + * + * This function calculates the SHA-384 hash of the given image. + * + * @param img The pointer to the wolfBoot_image structure representing the image. + * @param hash The buffer to store the SHA-384 hash (48 bytes). + * @return 0 on success, -1 on error. + */ +static int image_sha384(struct wolfBoot_image *img, uint8_t *hash) +{ + uint32_t position = 0; + uint8_t *p; + int blksz; + wc_Sha384 sha384_ctx; + + if (header_sha384(&sha384_ctx, img) != 0) + return -1; do { p = get_sha_block(img, position); if (p == NULL) @@ -983,23 +1008,13 @@ static void key_sha384(uint8_t key_slot, uint8_t *hash) #include -/** - * @brief Calculate SHA3-384 hash of the image. - * - * This function calculates the SHA3-384 hash of the given image. - * - * @param img The pointer to the wolfBoot_image structure representing the image. - * @param hash The buffer to store the SHA3-384 hash (48 bytes). - * @return 0 on success, -1 on error. - */ -static int image_sha3_384(struct wolfBoot_image *img, uint8_t *hash) +/* Initialize and hash the header part */ +static int header_sha3_384(wc_Sha3 *sha3_ctx, struct wolfBoot_image *img) { - uint8_t *stored_sha, *end_sha; uint16_t stored_sha_len; + uint8_t *stored_sha, *end_sha; uint8_t *p; int blksz; - uint32_t position = 0; - wc_Sha3 sha3_ctx; if (!img) return -1; @@ -1008,15 +1023,36 @@ static int image_sha3_384(struct wolfBoot_image *img, uint8_t *hash) stored_sha_len = get_header(img, HDR_SHA3_384, &stored_sha); if (stored_sha_len != WOLFBOOT_SHA_DIGEST_SIZE) return -1; - wc_InitSha3_384(&sha3_ctx, NULL, INVALID_DEVID); + wc_InitSha3_384(sha3_ctx, NULL, INVALID_DEVID); end_sha = stored_sha - (2 * sizeof(uint16_t)); /* Subtract 2 Type + 2 Len */ while (p < end_sha) { blksz = WOLFBOOT_SHA_BLOCK_SIZE; if (end_sha - p < blksz) blksz = end_sha - p; - wc_Sha3_384_Update(&sha3_ctx, p, blksz); + wc_Sha3_384_Update(sha3_ctx, p, blksz); p += blksz; } + return 0; +} + +/** + * @brief Calculate SHA3-384 hash of the image. + * + * This function calculates the SHA3-384 hash of the given image. + * + * @param img The pointer to the wolfBoot_image structure representing the image. + * @param hash The buffer to store the SHA3-384 hash (48 bytes). + * @return 0 on success, -1 on error. + */ +static int image_sha3_384(struct wolfBoot_image *img, uint8_t *hash) +{ + uint8_t *p; + int blksz; + uint32_t position = 0; + wc_Sha3 sha3_ctx; + + if (header_sha3_384(&sha3_ctx, img) != 0) + return -1; do { p = get_sha_block(img, position); if (p == NULL) @@ -1291,6 +1327,287 @@ int wolfBoot_verify_integrity(struct wolfBoot_image *img) return 0; } +#ifdef WOLFBOOT_ELF_SCATTERED +#include "elf.h" + +#define PADDING_BLOCK_SIZE 64 + +#ifdef ARCH_SIM +#define BASE_OFF ARCH_FLASH_OFFSET +#else +#define BASE_OFF 0 +#endif + +int elf_check_image_scattered(uint8_t part, unsigned long *entry_out) +{ + /* Open the partition containing the image */ + struct wolfBoot_image boot; + uint8_t *elf_h, *p; + int elf_hdr_sz = 0; + int len; + int is_elf32; + unsigned short entry_count; + unsigned short entry_size; + unsigned long entry_off; + long final_offset = -1; + uint8_t calc_digest[WOLFBOOT_SHA_DIGEST_SIZE]; + uint8_t *exp_digest; + int stored_sha_len; + int i; + uint8_t padding_block[PADDING_BLOCK_SIZE]; + int entry_out_set = 0; + + + wolfBoot_hash_t ctx; + if (wolfBoot_open_image(&boot, part) < 0) + return -1; + p = get_img_hdr(&boot); + + /* Initialize hash, feed the manifest header to it */ + if (header_hash(&ctx, &boot) < 0) + return -1; + + stored_sha_len = get_header(&boot, HDR_HASH, &exp_digest); + if (stored_sha_len != WOLFBOOT_SHA_DIGEST_SIZE) + return -1; + + /* Get the elf header size */ + elf_h = p + IMAGE_HEADER_SIZE; + + if (elf_open(elf_h, &is_elf32) < 0) + return -1; + + elf_hdr_sz = elf_hdr_size(elf_h); + wolfBoot_printf("Elf header size: %d\n", elf_hdr_sz); + + memset(padding_block, 0, PADDING_BLOCK_SIZE); + + /* Feed the elf header to the hash function */ + len = elf_hdr_sz; + p = elf_h; + while (len > 0) { + if (len > WOLFBOOT_SHA_BLOCK_SIZE) { + update_hash(&ctx, p, WOLFBOOT_SHA_BLOCK_SIZE); + len -= WOLFBOOT_SHA_BLOCK_SIZE; + } else { + update_hash(&ctx, p, len); + break; + } + p += WOLFBOOT_SHA_BLOCK_SIZE; + } + wolfBoot_printf("Hashed ELF header.\n"); + + /* Feed the program headers to the hash function */ + if (is_elf32) { + elf32_header *eh = (elf32_header *)elf_h; + elf32_program_header *ph; + entry_count = eh->ph_entry_count; + entry_size = eh->ph_entry_size; + entry_off = eh->ph_offset; + if (!entry_out_set) { + *entry_out = eh->entry; + entry_out_set = 1; + } + + wolfBoot_printf("EH entry offset: %d\n", (int)entry_off); + ph = (elf32_program_header *)(elf_h + entry_off); + /* Add padding until the first program header into hash function */ + len = ph[0].offset - elf_hdr_sz; + wolfBoot_printf("Adding %d bytes padding\n", (int)len); + while (len > 0) { + if (len > PADDING_BLOCK_SIZE) { + update_hash(&ctx, padding_block, PADDING_BLOCK_SIZE); + len -= PADDING_BLOCK_SIZE; + } else { + update_hash(&ctx, padding_block, len); + break; + } + } + for (i = 0; i < entry_count; i++) { + unsigned long paddr; + unsigned long filesz; + unsigned long offset; + paddr = (unsigned long)ph[i].paddr; + offset = (unsigned long)ph[i].offset; + filesz = (unsigned long)ph[i].file_size; + wolfBoot_printf("Paddr: 0x%lx offset: %lu, size: %lu\n", paddr, + offset, filesz); + + /* Feed any non-loaded parts to the hash function */ + if (ph[i].type != ELF_PT_LOAD) { + len = filesz; + //wolfBoot_printf("Feeding ghost segment, len %d\n", len); + continue; + while (len > 0) { + if (len > WOLFBOOT_SHA_BLOCK_SIZE) { + update_hash(&ctx, elf_h + offset, WOLFBOOT_SHA_BLOCK_SIZE); + len -= WOLFBOOT_SHA_BLOCK_SIZE; + paddr += WOLFBOOT_SHA_BLOCK_SIZE; + } else { + update_hash(&ctx, elf_h + offset, len); + break; + } + } + } else { + /* Feed the loaded parts to the hash function */ + len = filesz; + wolfBoot_printf("Feeding stored segment, len %d\n", len); + while (len > 0) { + if (len > WOLFBOOT_SHA_BLOCK_SIZE) { + update_hash(&ctx, (void *)(paddr + BASE_OFF), + WOLFBOOT_SHA_BLOCK_SIZE); + len -= WOLFBOOT_SHA_BLOCK_SIZE; + paddr += WOLFBOOT_SHA_BLOCK_SIZE; + } else { + update_hash(&ctx, (void *)(paddr + BASE_OFF), + len); + break; + } + } + } + /* Add padding until next program header, if any. */ + if ((i < entry_count - 1) && (ph[i+1].offset > (offset + filesz))) { + unsigned long padding = ph[i+1].offset - (offset + filesz); + wolfBoot_printf("Adding padding: %lu (from %lx to %lx)\n", padding, (unsigned long)offset + filesz, (unsigned long)ph[i+1].offset); + while (padding > 0) { + if (padding > PADDING_BLOCK_SIZE) { + update_hash(&ctx, padding_block, PADDING_BLOCK_SIZE); + padding -= PADDING_BLOCK_SIZE; + } else { + update_hash(&ctx, padding_block, padding); + break; + } + } + } else { + final_offset = offset + filesz; + } + } + } else { /* 64-bit ELF */ + elf64_header *eh = (elf64_header *)elf_h; + elf64_program_header *ph; + entry_count = eh->ph_entry_count; + entry_size = eh->ph_entry_size; + entry_off = eh->ph_offset; + if (!entry_out_set) { + *entry_out = eh->entry; + entry_out_set = 1; + } + + wolfBoot_printf("EH entry offset: %d\n", (int)entry_off); + ph = (elf64_program_header *)(elf_h + entry_off); + /* Add padding until the first program header into hash function */ + len = ph[0].offset - elf_hdr_sz; + wolfBoot_printf("Adding %d bytes padding\n", len); + while (len > 0) { + if (len > PADDING_BLOCK_SIZE) { + update_hash(&ctx, padding_block, PADDING_BLOCK_SIZE); + len -= PADDING_BLOCK_SIZE; + } else { + update_hash(&ctx, padding_block, len); + break; + } + } + for (i = 0; i < entry_count; i++) { + unsigned long paddr; + unsigned long filesz; + unsigned long offset; + paddr = (unsigned long)ph[i].paddr; + offset = (unsigned long)ph[i].offset; + filesz = (unsigned long)ph[i].file_size; + wolfBoot_printf("Paddr: 0x%lx offset: %lu, size: %lu\n", paddr, + offset, filesz); + + /* Feed any non-loaded parts to the hash function */ + if (ph[i].type != ELF_PT_LOAD) { + len = filesz; + //wolfBoot_printf("Feeding ghost segment, len %d\n", len); + continue; + while (len > 0) { + if (len > WOLFBOOT_SHA_BLOCK_SIZE) { + update_hash(&ctx, elf_h + offset, WOLFBOOT_SHA_BLOCK_SIZE); + len -= WOLFBOOT_SHA_BLOCK_SIZE; + paddr += WOLFBOOT_SHA_BLOCK_SIZE; + } else { + update_hash(&ctx, elf_h + offset, len); + break; + } + } + } else { + /* Feed the loaded parts to the hash function */ + len = filesz; + wolfBoot_printf("Feeding stored segment, len %d\n", len); + while (len > 0) { + if (len > WOLFBOOT_SHA_BLOCK_SIZE) { + update_hash(&ctx, (void *)(paddr + BASE_OFF), + WOLFBOOT_SHA_BLOCK_SIZE); + len -= WOLFBOOT_SHA_BLOCK_SIZE; + paddr += WOLFBOOT_SHA_BLOCK_SIZE; + } else { + update_hash(&ctx, (void *)(paddr + BASE_OFF), + len); + break; + } + } + } + /* Add padding until next program header, if any. */ + if ((i < entry_count - 1) && (ph[i+1].offset > (offset + filesz))) { + unsigned long padding = ph[i+1].offset - (offset + filesz); + wolfBoot_printf("Adding padding: %lu\n", padding); + while (padding > 0) { + if (padding > PADDING_BLOCK_SIZE) { + update_hash(&ctx, padding_block, PADDING_BLOCK_SIZE); + padding -= PADDING_BLOCK_SIZE; + } else { + update_hash(&ctx, padding_block, padding); + break; + } + } + } else { + final_offset = offset + filesz; + } + } + } + if (final_offset < 0) + return -1; + if (final_offset + IMAGE_HEADER_SIZE > (long)boot.fw_size) + return -1; + + len = boot.fw_size - final_offset; + p = boot.hdr + IMAGE_HEADER_SIZE + final_offset; + p = get_img_hdr(&boot) + IMAGE_HEADER_SIZE + final_offset; + + wolfBoot_printf("Appending %d bytes of data from image, from position %lu...(0x%p)\n", len, IMAGE_HEADER_SIZE + final_offset, p); + + while (len > 0) { + if (len > WOLFBOOT_SHA_BLOCK_SIZE) { + update_hash(&ctx, p, WOLFBOOT_SHA_BLOCK_SIZE); + len -= WOLFBOOT_SHA_BLOCK_SIZE; + p += WOLFBOOT_SHA_BLOCK_SIZE; + } else { + update_hash(&ctx, p, len); + break; + } + } + + /* Finalize SHA calculation */ + final_hash(&ctx, calc_digest); + if (memcmp(calc_digest, exp_digest, WOLFBOOT_SHA_DIGEST_SIZE) != 0) { + wolfBoot_printf("SHA failed for scattered ELF!\n"); + wolfBoot_printf("Expected %02x%02x%02x%02x%02x%02x%02x%02x\n", + exp_digest[0], exp_digest[1], exp_digest[2], exp_digest[3], + exp_digest[4], exp_digest[5], exp_digest[6], exp_digest[7]); + wolfBoot_printf("Calculated %02x%02x%02x%02x%02x%02x%02x%02x\n", + calc_digest[0], calc_digest[1], calc_digest[2], calc_digest[3], + calc_digest[4], calc_digest[5], calc_digest[6], calc_digest[7]); + return -2; + } + wolfBoot_printf("Scattered ELF verified.\n"); + return 0; +} +#undef BASE_OFF + +#endif + #ifdef WOLFBOOT_NO_SIGN /** * @brief Verify the authenticity of the image using a digital signature. diff --git a/src/update_flash.c b/src/update_flash.c index 18f3c8ea92..327751e6ca 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -38,6 +38,11 @@ int WP11_Library_Init(void); #endif +/* Support for ELF scatter/gather format */ +#ifdef WOLFBOOT_ELF_SCATTERED +#include "elf.h" +#endif + #ifdef RAM_CODE #ifndef TARGET_rp2350 extern unsigned int _start_text; @@ -211,12 +216,34 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src, # define TRAILER_OFFSET_WORDS 0 #endif +/** + * @brief Performs the final swap and erase operations during a secure update, + * ensuring that if power is lost during the update, the process can be resumed + * on next boot. + * + * This function handles the final phase of the three-way swap update process. + * It ensures that the update is atomic and power-fail safe by: + * 1. Saving the last sector of the boot partition to the swap area + * 2. Setting a magic trailer value to mark the swap as in progress + * 3. Erasing the last sector(s) of the boot partition + * 4. Restoring the saved sector from swap back to boot + * 5. Setting the boot partition state to TESTING + * 6. Erasing the last sector(s) of the update partition + * + * The function can be called in two modes: + * - Normal mode (resume=0): Initiates the swap and erase process + * - Resume mode (resume=1): Checks if a swap was interrupted and completes it + * + * @param resume If 1, checks for interrupted swap and resumes it; if 0, starts + * new swap + * @return 0 on success, negative value if no swap needed or on error + */ static int wolfBoot_swap_and_final_erase(int resume) { struct wolfBoot_image boot[1]; struct wolfBoot_image update[1]; struct wolfBoot_image swap[1]; - uint8_t st; + uint8_t updateState; int eraseLen = (WOLFBOOT_SECTOR_SIZE #ifdef NVM_FLASH_WRITEONCE /* need to erase the redundant sector too */ * 2 @@ -231,7 +258,7 @@ static int wolfBoot_swap_and_final_erase(int resume) wolfBoot_open_image(boot, PART_BOOT); wolfBoot_open_image(update, PART_UPDATE); wolfBoot_open_image(swap, PART_SWAP); - wolfBoot_get_partition_state(PART_UPDATE, &st); + wolfBoot_get_partition_state(PART_UPDATE, &updateState); /* read trailer */ #if defined(EXT_FLASH) && PARTN_IS_EXT(PART_BOOT) @@ -247,7 +274,9 @@ static int wolfBoot_swap_and_final_erase(int resume) swapDone = 1; } /* if resuming, quit if swap isn't done */ - if ((resume == 1) && (swapDone == 0) && (st != IMG_STATE_FINAL_FLAGS)) { + if ((resume == 1) && (swapDone == 0) && + (updateState != IMG_STATE_FINAL_FLAGS) + ) { return -1; } @@ -257,7 +286,7 @@ static int wolfBoot_swap_and_final_erase(int resume) #endif /* IMG_STATE_FINAL_FLAGS allows re-entry without blowing away swap */ - if (st != IMG_STATE_FINAL_FLAGS) { + if (updateState != IMG_STATE_FINAL_FLAGS) { /* store the sector at tmpBootPos into swap */ wolfBoot_copy_sector(boot, swap, tmpBootPos / WOLFBOOT_SECTOR_SIZE); /* set FINAL_SWAP for re-entry */ @@ -291,9 +320,11 @@ static int wolfBoot_swap_and_final_erase(int resume) else { wb_flash_erase(boot, tmpBootPos, WOLFBOOT_SECTOR_SIZE); } + /* mark boot as TESTING */ wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_TESTING); - /* erase the last sector(s) of update */ + /* 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); #ifdef EXT_FLASH @@ -784,6 +815,21 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed) wolfBoot_swap_and_final_erase(0); #else /* DISABLE_BACKUP */ +#ifdef WOLFBOOT_ELF_SCATTERED + unsigned long entry; + void *base = (void *)WOLFBOOT_PARTITION_BOOT_ADDRESS; + wolfBoot_printf("ELF Scattered image digest check\n"); + if (elf_check_image_scattered(PART_BOOT, &entry) < 0) { + wolfBoot_printf("ELF Scattered image digest check: failed. Restoring scattered image...\n"); + elf_store_image_scattered(base, &entry, PART_IS_EXT(boot)); + if (elf_check_image_scattered(PART_BOOT, &entry) < 0) { + wolfBoot_printf("Fatal: Could not verify digest after scattering. Panic().\n"); + wolfBoot_panic(); + } + } + wolfBoot_printf("Scattered image correctly verified. Setting entry point to %lx\n", entry); + boot.fw_base = (void *)entry; +#endif /* Direct Swap without power fail safety */ hal_flash_unlock(); @@ -811,6 +857,8 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed) wb_flash_erase(&boot, sector * sector_size, sector_size); sector++; } + + wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_SUCCESS); #ifdef EXT_FLASH @@ -1017,7 +1065,8 @@ void RAMFUNCTION wolfBoot_start(void) /* Emergency update successful, try to re-open boot image */ if (likely(((wolfBoot_open_image(&boot, PART_BOOT) < 0) || (wolfBoot_verify_integrity(&boot) < 0) || - (wolfBoot_verify_authenticity(&boot) < 0)))) { + (wolfBoot_verify_authenticity(&boot) < 0) + ))) { wolfBoot_printf("Boot (try 2) failed: Hdr %d, Hash %d, Sig %d\n", boot.hdr_ok, boot.sha_ok, boot.signature_ok); /* panic: something went wrong after the emergency update */ @@ -1029,6 +1078,24 @@ void RAMFUNCTION wolfBoot_start(void) } } PART_SANITY_CHECK(&boot); + +#ifdef WOLFBOOT_ELF_SCATTERED + unsigned long entry; + void *base = (void *)WOLFBOOT_PARTITION_BOOT_ADDRESS; + wolfBoot_printf("ELF Scattered image digest check\n"); + if (elf_check_image_scattered(PART_BOOT, &entry) < 0) { + wolfBoot_printf("ELF Scattered image digest check: failed. Restoring scattered image...\n"); + elf_store_image_scattered(base, &entry, PART_IS_EXT(boot)); + if (elf_check_image_scattered(PART_BOOT, &entry) < 0) { + wolfBoot_printf("Fatal: Could not verify digest after scattering. Panic().\n"); + wolfBoot_panic(); + } + } + wolfBoot_printf("Scattered image correctly verified. Setting entry point to %lx\n", entry); + boot.fw_base = (void *)entry; +#endif + + #ifdef WOLFBOOT_TPM wolfBoot_tpm2_deinit(); #endif diff --git a/src/update_ram.c b/src/update_ram.c index d7a6a4d96e..b5cef82cf8 100644 --- a/src/update_ram.c +++ b/src/update_ram.c @@ -271,7 +271,7 @@ void RAMFUNCTION wolfBoot_start(void) #ifdef WOLFBOOT_ELF /* Load elf */ - if (elf_load_image((uint8_t*)load_address, (uintptr_t*)&load_address) != 0){ + if (elf_load_image_mmu((uint8_t*)load_address, (uintptr_t*)&load_address, NULL) != 0){ wolfBoot_printf("Invalid elf, falling back to raw binary\n"); } #endif diff --git a/test-app/Makefile b/test-app/Makefile index f25c91b469..b2975669c8 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -227,7 +227,6 @@ ifeq ($(TARGET),ti_hercules) endif ifeq ($(TARGET),sim) - APP_OBJS=app_$(TARGET).o ../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 +238,15 @@ 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/string.o + CFLAGS+=-D"WOLFBOOT_ELF_SCATTERED=1" -nostartfiles -ffreestanding -static -nostdlib + LDFLAGS+=-ffreestanding -nostartfiles -static -T$(LSCRIPT) -nostdlib + else + APP_OBJS=app_sim.o + APP_OBJS+=../test-app/libwolfboot.o ../hal/$(TARGET).o + endif endif ifeq ($(EXT_FLASH),1) diff --git a/test-app/app_sim_scattered.c b/test-app/app_sim_scattered.c new file mode 100644 index 0000000000..4316c8738b --- /dev/null +++ b/test-app/app_sim_scattered.c @@ -0,0 +1,49 @@ +/* app_sim_scattered.c + * + * Test bare-metal boot-led-on application + * + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include "target.h" + +#include "wolfboot/wolfboot.h" + +#ifdef TARGET_sim + + +__attribute__((section(".r3text"))) +int do_cmd(const char *cmd) +{ + /* Do nothing */ + return 0; +} + +__attribute__((section(".r2text"))) +int do_exec_cmd(char *name) +{ + return do_cmd(name); +} + +__attribute__((section(".r1text"))) +int main(int argc, char *argv[]) { + do_exec_cmd((void *)0); + return 0; +} +#endif /** TARGET_sim **/ diff --git a/test-app/sim_scattered.ld b/test-app/sim_scattered.ld new file mode 100644 index 0000000000..42cb595c5c --- /dev/null +++ b/test-app/sim_scattered.ld @@ -0,0 +1,28 @@ +ENTRY(main) + +SECTIONS +{ + . = 0x100000; + __r1_start = .; + .r1text : { *(.r1text) } + .r1data : { *(.r1data) } + __r1_end = .; + + . = 0x140000; + __r2_start = .; + .r2text : { *(.r2text) } + .r2data : { *(.r2data) } + __r2_end = .; + + . = 0x180000; + __r3_start = .; + .r3text : { *(.r3text) } + .r3data : { *(.r3data) } + + .text : { *(.text*) } + .rodata : { *(.rodata*) } + __r3_end = .; + + PROVIDE(__image_start = 0x100000); + PROVIDE(__image_end = .); +} diff --git a/tools/elf-parser/Makefile b/tools/elf-parser/Makefile index fd89e343c5..dc67c3895e 100644 --- a/tools/elf-parser/Makefile +++ b/tools/elf-parser/Makefile @@ -4,7 +4,7 @@ CC=gcc CFLAGS=-Wall -g -ggdb -CFLAGS+=-I../../include -DWOLFBOOT_ELF -DELF_PARSER -DPRINTF_ENABLED +CFLAGS+=-I../../include -DWOLFBOOT_ELF -DELF_PARSER -DPRINTF_ENABLED -DMMU -DARCH_FLASH_OFFSET=0 EXE=elf-parser LIBS= diff --git a/tools/elf-parser/elf-parser.c b/tools/elf-parser/elf-parser.c index a618b72e7f..cfa6f6bde9 100644 --- a/tools/elf-parser/elf-parser.c +++ b/tools/elf-parser/elf-parser.c @@ -70,7 +70,7 @@ int main(int argc, char *argv[]) fclose(f); if (ret == 0) { - ret = elf_load_image(image, &entry); + ret = elf_load_image_mmu(image, &entry, NULL); } printf("Return %d, Load %p\n", ret, (void*)entry);