Moved elf parsing/scattering to elf.c, WIP sim

pull/562/head
Daniele Lacamera 2025-04-03 17:12:42 +02:00
parent fb6ca4378f
commit e7cd340ebf
8 changed files with 290 additions and 586 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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)

255
src/elf.c
View File

@ -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 */

View File

@ -51,9 +51,6 @@
#ifdef WOLFBOOT_HASH_SHA3_384
#include <wolfssl/wolfcrypt/sha3.h>
#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.
*

View File

@ -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);

View File

@ -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)