From 503b008cf583e60ff4da1354fab7e1f14e709857 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Thu, 14 Feb 2019 15:08:36 +0100 Subject: [PATCH] New feature: allow swapping from external memory (e.g. SPI flash) --- Makefile | 13 ++- hal/stm32f4.c | 91 ++++++++++++++- include/hal.h | 10 ++ include/image.h | 88 ++++++++++----- include/target.h | 4 +- include/wolfboot/wolfboot.h | 3 + src/image.c | 93 +++++++++------- src/libwolfboot.c | 215 ++++++++++++++++++++++++++++++------ src/loader.c | 79 +++++++------ test-app/Makefile | 8 +- test-app/main.c | 11 ++ 11 files changed, 466 insertions(+), 149 deletions(-) diff --git a/Makefile b/Makefile index 46120f4b..487c03af 100644 --- a/Makefile +++ b/Makefile @@ -69,16 +69,17 @@ ifeq ($(FASTMATH),1) CFLAGS+=-DUSE_FAST_MATH endif -ifeq ($(EXT_FLASH),1) - CFLAGS+=-DEXT_FLASH -DPART_UPDATE_EXT -endif - CFLAGS+=-mthumb -Wall -Wextra -Wno-main -Wstack-usage=1024 -ffreestanding -Wno-unused \ -Ilib/bootutil/include -Iinclude/ -Ilib/wolfssl -nostartfiles \ -DWOLFSSL_USER_SETTINGS \ -mthumb -mlittle-endian -mthumb-interwork \ -DPLATFORM_$(TARGET) +ifeq ($(EXT_FLASH),1) + CFLAGS+=-DEXT_FLASH=1 -DPART_UPDATE_EXT=1 -DPART_SWAP_EXT=1 +endif + + ifeq ($(SIGN),ED25519) OBJS+= ./lib/wolfssl/wolfcrypt/src/sha512.o \ ./lib/wolfssl/wolfcrypt/src/ed25519.o \ @@ -131,7 +132,7 @@ wolfboot-align.bin: wolfboot.elf $(SIZE) wolfboot.elf test-app/image.bin: - make -C test-app TARGET=$(TARGET) + make -C test-app TARGET=$(TARGET) EXT_FLASH=$(EXT_FLASH) tools/ed25519/ed25519_sign: make -C tools/ed25519 @@ -165,7 +166,7 @@ src/ecc256_pub_key.c: ecc256.der keys: $(PRIVATE_KEY) clean: - rm -f *.bin *.elf $(OBJS) wolfboot.map *.bin *.hex + rm -f *.bin *.elf $(OBJS) wolfboot.map *.bin *.hex hal/*.o make -C test-app clean distclean: clean diff --git a/hal/stm32f4.c b/hal/stm32f4.c index 5d4fc2b5..09cb835d 100644 --- a/hal/stm32f4.c +++ b/hal/stm32f4.c @@ -112,9 +112,9 @@ #define FLASH_SECTOR_5 0x0020000 #define FLASH_SECTOR_6 0x0040000 #define FLASH_SECTOR_7 0x0060000 -#define FLASH_TOP 0x007FFFF +#define FLASH_TOP 0x0080000 -const uint32_t flash_sector[8] = { +const uint32_t flash_sector[9] = { FLASH_SECTOR_0, FLASH_SECTOR_1, FLASH_SECTOR_2, @@ -122,7 +122,8 @@ const uint32_t flash_sector[8] = { FLASH_SECTOR_4, FLASH_SECTOR_5, FLASH_SECTOR_6, - FLASH_SECTOR_7 + FLASH_SECTOR_7, + FLASH_TOP }; static void flash_set_waitstates(int waitstates) @@ -194,17 +195,20 @@ void hal_flash_lock(void) int hal_flash_erase(uint32_t address, int len) { int start = -1, end = -1; - uint32_t end_address = address + len; + uint32_t end_address; int i; + if (len == 0) + return -1; + end_address = address + len - 1; if (address < flash_sector[0] || end_address > FLASH_TOP) return -1; - for (i = 0; i < 7; i++) + for (i = 0; i < 8; i++) { if ((address >= flash_sector[i]) && (address < flash_sector[i + 1])) { start = i; } - if ((end_address >= flash_sector[i]) && (address < flash_sector[i + 1])) { + if ((end_address >= flash_sector[i]) && (end_address < flash_sector[i + 1])) { end = i; } if (start > 0 && end > 0) @@ -325,3 +329,78 @@ void hal_prepare_boot(void) clock_pll_off(); } + +#ifdef EXT_FLASH +#define SIM_ADDRESS (0x40000) + +int ext_flash_read(uint32_t address, uint8_t *data, int len) +{ + int i; + uint32_t val; + address += SIM_ADDRESS; + for (i = 0; i < len; i++) + data[i] = *((uint8_t *)(address + i)); + return len; +} + +int ext_flash_write(uint32_t address, const uint8_t *data, int len) +{ + int i; + uint32_t val; + address += SIM_ADDRESS; + flash_wait_complete(); + clear_errors(); + /* Set 8-bit write */ + FLASH_CR &= (~(0x03 << 8)); + for (i = 0; i < len; i++) { + FLASH_CR |= FLASH_CR_PG; + *((uint8_t *)(address + i)) = data[i]; + flash_wait_complete(); + FLASH_CR &= ~FLASH_CR_PG; + } + return 0; +} + +void ext_flash_unlock(void) +{ + FLASH_CR |= FLASH_CR_LOCK; + FLASH_KEYR = FLASH_KEY1; + FLASH_KEYR = FLASH_KEY2; +} + +void ext_flash_lock(void) +{ + FLASH_CR |= FLASH_CR_LOCK; +} + + +int ext_flash_erase(uint32_t address, int len) +{ + int start = -1, end = -1; + uint32_t end_address; + int i; + address += SIM_ADDRESS; + end_address = address + len - 1; + + if (address < flash_sector[0] || end_address > FLASH_TOP) + return -1; + for (i = 0; i < 8; i++) + { + if ((address >= flash_sector[i]) && (address < flash_sector[i + 1])) { + start = i; + } + if ((end_address >= flash_sector[i]) && (end_address < flash_sector[i + 1])) { + end = i; + } + if (start > 0 && end > 0) + break; + } + if (start < 0 || end < 0) + return -1; + for (i = start; i <= end; i++) + flash_erase_sector(i); + return 0; +} + + +#endif diff --git a/include/hal.h b/include/hal.h index e2c4fbed..825bb619 100644 --- a/include/hal.h +++ b/include/hal.h @@ -3,11 +3,21 @@ #include +#include "target.h" void hal_init(void); int hal_flash_write(uint32_t address, const uint8_t *data, int len); int hal_flash_erase(uint32_t address, int len); void hal_flash_unlock(void); void hal_flash_lock(void); void hal_prepare_boot(void); + +#ifdef EXT_FLASH +/* external flash interface */ +int ext_flash_write(uint32_t address, const uint8_t *data, int len); +int ext_flash_read(uint32_t address, uint8_t *data, int len); +int ext_flash_erase(uint32_t address, int len); +void ext_flash_lock(void); +void ext_flash_unlock(void); +#endif #endif /* H_HAL_FLASH_ */ diff --git a/include/image.h b/include/image.h index eabfa560..5fe0f229 100644 --- a/include/image.h +++ b/include/image.h @@ -3,6 +3,7 @@ #include #include #include +#include "image.h" #define SECT_FLAG_NEW 0x0F @@ -11,32 +12,6 @@ #define SECT_FLAG_UPDATED 0x00 -#ifdef EXT_FLASH -# ifndef PART_UPDATE_DRIVER -# define PART_UPDATE_DRIVER (&internal_flash_driver) -# endif -# define flash_lock(x) (x->flash_driver.lock()) -# define flash_unlock(x) (x->flash_driver.unlock()) -# define flash_erase(x, addr, len) (x->flash_driver.erase(addr, len) -# define flash_write(x, addr, data, len) (x->flash_driver.write(addr, data, len) -# define flash_read(x, addr, data, len) (x->flash_driver.read(addr, data, len) -#else -# define flash_lock(x) hal_flash_lock() -# define flash_unlock(x) hal_flash_unlock() -# define flash_erase(x, addr, len) (x->flash_driver.erase(addr, len) -# define flash_write(x, addr, data, len) (x->flash_driver.write(addr, data, len) -# define flash_read(x, addr, data, len) (memcpy(data, addr, len) - data + len) -#endif - -struct wolfBoot_flash_driver { - int (*write)(uint32_t address, const uint8_t *data, int len); - int (*read)(uint32_t address, uint8_t *data, int len); - int (*erase)(uint32_t address, int len); - void (*lock)(void); - void (*unlock)(void); -}; - -extern const struct wolfBoot_flash_driver internal_flash_driver; struct wolfBoot_image { uint8_t *hdr; @@ -47,7 +22,6 @@ struct wolfBoot_image { uint8_t *fw_base; uint32_t fw_size; uint8_t part; - struct wolfBoot_flash_driver *flash_driver; }; @@ -59,4 +33,64 @@ int wolfBoot_set_sector_flag(uint8_t part, uint8_t sector, uint8_t newflag); int wolfBoot_get_partition_state(uint8_t part, uint8_t *st); int wolfBoot_get_sector_flag(uint8_t part, uint8_t sector, uint8_t *flag); +#ifdef EXT_FLASH +# ifdef PART_UPDATE_EXT +# define UPDATE_EXT 1 +# else +# define UPDATE_EXT 0 +# endif +# ifdef PART_SWAP_EXT +# define SWAP_EXT 1 +# else +# define SWAP_EXT 0 +# endif +# define PART_IS_EXT(x) (((x)->part == PART_UPDATE)?UPDATE_EXT:(((x)->part == PART_SWAP)?SWAP_EXT:0)) +#include "hal.h" + +static inline int wb_flash_erase(struct wolfBoot_image *img, uint32_t off, uint32_t size) +{ + if (PART_IS_EXT(img)) + return ext_flash_erase((uint32_t)(img->hdr) + off, size); + else + return hal_flash_erase((uint32_t)(img->hdr) + off, size); +} + +static inline int wb_flash_write(struct wolfBoot_image *img, uint32_t off, const void *data, uint32_t size) +{ + if (PART_IS_EXT(img)) + return ext_flash_write((uint32_t)(img->hdr) + off, data, size); + else + return hal_flash_write((uint32_t)(img->hdr) + off, data, size); +} + +static inline int wb_flash_write_verify_word(struct wolfBoot_image *img, uint32_t off, uint32_t word) +{ + int ret; + volatile uint32_t copy; + if (PART_IS_EXT(img)) + { + ext_flash_read((uint32_t)(img->hdr) + off, (void *)©, sizeof(uint32_t)); + while (copy != word) { + ret = ext_flash_write((uint32_t)(img->hdr) + off, (void *)&word, sizeof(uint32_t)); + if (ret < 0) + return ret; + ext_flash_read((uint32_t)(img->hdr) + off, (void *)©, sizeof(uint32_t)); + } + } else { + volatile uint32_t *pcopy = (volatile uint32_t*)(img->hdr + off); + while(*pcopy != word) { + hal_flash_write((uint32_t)pcopy, (void *)&word, sizeof(uint32_t)); + } + } + return 0; +} + + +#else +# define PART_IS_EXT(x) (0) +# define wb_flash_erase(im, of, siz) hal_flash_erase(((uint32_t)(((im)->hdr)) + of), siz) +# define wb_flash_write(im, of, dat, siz) hal_flash_write(((uint32_t)((im)->hdr)) + of, dat, siz) +# define wb_flash_write_verify_word(im, of, x) do { hal_flash_write(((uint32_t)((im)->hdr)) + of, (void *)&x, sizeof(uint32_t)); } while (*(uint32_t *)(((im)->hdr) + of) != x) +#endif /* EXT_FLASH */ + #endif /* IMAGE_H */ diff --git a/include/target.h b/include/target.h index d6e095e4..30460a94 100644 --- a/include/target.h +++ b/include/target.h @@ -10,7 +10,7 @@ #define WOLFBOOT_PARTITION_SIZE 0x20000 #define WOLFBOOT_PARTITION_BOOT_ADDRESS 0x20000 -#define WOLFBOOT_PARTITION_UPDATE_ADDRESS 0x40000 -#define WOLFBOOT_PARTITION_SWAP_ADDRESS 0x60000 +#define WOLFBOOT_PARTITION_UPDATE_ADDRESS 0x0 +#define WOLFBOOT_PARTITION_SWAP_ADDRESS 0x20000 #endif diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index 2fcbbee9..dd682a6f 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -29,5 +29,8 @@ void wolfBoot_erase_partition(uint8_t part); void wolfBoot_update_trigger(void); void wolfBoot_success(void); +uint32_t wolfBoot_get_image_version(uint8_t part); +#define wolfBoot_current_firmware_version() wolfBoot_get_image_version(PART_BOOT) +#define wolfBoot_update_firmware_version() wolfBoot_get_image_version(PART_UPDATE) #endif /* IMAGE_H */ diff --git a/src/image.c b/src/image.c index d9f5a7df..a3a74a37 100644 --- a/src/image.c +++ b/src/image.c @@ -26,6 +26,10 @@ #ifdef WOLFBOOT_SIGN_ED25519 #include + + +extern uint8_t wolfBoot_find_header(uint8_t *haystack, uint8_t type, uint8_t **ptr); + static int wolfBoot_verify_signature(uint8_t *hash, uint8_t *sig) { int ret, res; @@ -82,6 +86,7 @@ static int wolfBoot_verify_signature(uint8_t *hash, uint8_t *sig) } #endif +#if 0 static uint8_t find_header(uint8_t *haystack, uint8_t type, uint8_t **ptr) { uint8_t *p = haystack; @@ -101,6 +106,7 @@ static uint8_t find_header(uint8_t *haystack, uint8_t type, uint8_t **ptr) *ptr = NULL; return 0; } +#endif @@ -108,16 +114,13 @@ static uint8_t get_header_ext(struct wolfBoot_image *img, uint8_t type, uint8_t static uint8_t get_header(struct wolfBoot_image *img, uint8_t type, uint8_t **ptr) { -#if defined(PART_UPDATE_EXT) && defined(EXT_FLASH) +#if defined(PART_UPDATE_EXT) if(img->part == PART_UPDATE) return get_header_ext(img, type, ptr); #endif - return find_header(img->hdr + IMAGE_HEADER_OFFSET, type, ptr); + return wolfBoot_find_header(img->hdr + IMAGE_HEADER_OFFSET, type, ptr); } - - - static uint8_t ext_hash_block[SHA256_BLOCK_SIZE]; static uint8_t *get_sha_block(struct wolfBoot_image *img, uint32_t offset) @@ -126,23 +129,55 @@ static uint8_t *get_sha_block(struct wolfBoot_image *img, uint32_t offset) return NULL; #ifdef PART_UPDATE_EXT if (img->part == PART_UPDATE) { - ext_flash_read(img->fw_base + offset, ext_hash_block, SHA256_BLOCK_SIZE); + ext_flash_read((uint32_t)(img->fw_base) + offset, ext_hash_block, SHA256_BLOCK_SIZE); return ext_hash_block; } #endif return (uint8_t *)(img->fw_base + offset); } +static uint8_t digest[SHA256_DIGEST_SIZE]; +static uint8_t verification[IMAGE_SIGNATURE_SIZE]; +#ifdef EXT_FLASH + +static uint8_t hdr_cpy[IMAGE_HEADER_SIZE]; +static int hdr_cpy_done = 0; + +static uint8_t *fetch_hdr_cpy(struct wolfBoot_image *img) +{ + if (!hdr_cpy_done) { + ext_flash_read((uint32_t)img->hdr, hdr_cpy, IMAGE_HEADER_SIZE); + hdr_cpy_done = 1; + } + return hdr_cpy; +} + +static uint8_t get_header_ext(struct wolfBoot_image *img, uint8_t type, uint8_t **ptr) +{ + return wolfBoot_find_header(fetch_hdr_cpy(img) + IMAGE_HEADER_OFFSET, type, ptr); +} + +#endif + +static uint8_t *get_img_hdr(struct wolfBoot_image *img) +{ +#ifdef PART_UPDATE_EXT + if (img->part == PART_UPDATE) { + return fetch_hdr_cpy(img); + } +#endif + return (uint8_t *)(img->hdr); +} + static int image_hash(struct wolfBoot_image *img, uint8_t *hash) { uint8_t *stored_sha, *end_sha; uint8_t stored_sha_len; - uint8_t *p = img->hdr; - uint8_t *fw_end = img->fw_base + img->fw_size; + uint8_t *p = get_img_hdr(img); int blksz; uint32_t position = 0; wc_Sha256 sha256_ctx; - if (!img || !img->hdr) + if (!img) return -1; stored_sha_len = get_header(img, HDR_SHA256, &stored_sha); if (stored_sha_len != SHA256_DIGEST_SIZE) @@ -188,39 +223,8 @@ static void key_hash(uint8_t *hash) wc_Sha256Final(&sha256_ctx, hash); } -static uint8_t digest[SHA256_DIGEST_SIZE]; -static uint8_t verification[IMAGE_SIGNATURE_SIZE]; -#ifdef EXT_FLASH - -static uint8_t hdr_cpy[IMAGE_HEADER_SIZE]; -static int hdr_cpy_done = 0; - -static uint8_t *fetch_hdr_cpy(struct wolfBoot_image *img) -{ - if (!hdr_cpy_done) { - ext_flash_read(img->hdr, hdr_cpy, IMAGE_HEADER_SIZE); - hdr_cpy_done = 1; - } - return hdr_cpy; -} - -static uint8_t get_header_ext(struct wolfBoot_image *img, uint8_t type, uint8_t **ptr) -{ - return find_header(fetch_hdr_cpy(img) + IMAGE_HEADER_OFFSET, type, ptr); -} - -#endif -static uint8_t *get_img_hdr(struct wolfBoot_image *img) -{ -#ifdef PART_UPDATE_EXT - if (img->part == PART_UPDATE) { - return fetch_hdr_cpy(img); - } -#endif - return (uint8_t *)(img->hdr); -} int wolfBoot_open_image(struct wolfBoot_image *img, uint8_t part) { @@ -230,12 +234,19 @@ int wolfBoot_open_image(struct wolfBoot_image *img, uint8_t part) if (!img) return -1; memset(img, 0, sizeof(struct wolfBoot_image)); + if (part == PART_SWAP) { + img->part = PART_SWAP; + img->hdr = (void *)WOLFBOOT_PARTITION_SWAP_ADDRESS; + img->fw_base = img->hdr; + img->fw_size = WOLFBOOT_SECTOR_SIZE; + return 0; + } if (part == PART_BOOT) { img->hdr = (void *)WOLFBOOT_PARTITION_BOOT_ADDRESS; image = (uint8_t *)img->hdr; } else if (part == PART_UPDATE) { img->hdr = (void *)WOLFBOOT_PARTITION_UPDATE_ADDRESS; -#if defined(PART_UPDATE_EXT) +#ifdef PART_UPDATE_EXT image = fetch_hdr_cpy(img); #else image = (uint8_t *)img->hdr; diff --git a/src/libwolfboot.c b/src/libwolfboot.c index 47ccfb3e..f90bc63c 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -23,83 +23,165 @@ #include #include -static uint8_t *get_trailer(uint8_t part) +#ifndef NULL +# define NULL (void *)0 +#endif + +uint32_t ext_cache; + +#ifndef TRAILER_SKIP +# define TRAILER_SKIP 0 +#endif +#define PART_BOOT_ENDFLAGS ((WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE) - TRAILER_SKIP) +#define PART_UPDATE_ENDFLAGS ((WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE) - TRAILER_SKIP) + +#if defined PART_UPDATE_EXT +static uint8_t *get_trailer_at(uint8_t part, uint32_t at) { if (part == PART_BOOT) - return (void *)(WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE); - else if (part == PART_UPDATE) - return (void *)(WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE); - else - return (void *)0; + return (void *)(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at)); + else if (part == PART_UPDATE) { + ext_flash_read(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&ext_cache, sizeof(uint32_t)); + return (uint8_t *)&ext_cache; + } else + return NULL; +} + +static void set_trailer_at(uint8_t part, uint32_t at, uint8_t val) +{ + if (part == PART_BOOT) { + hal_flash_write(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&val, 1); + } + else if (part == PART_UPDATE) { + ext_flash_write(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&val, 1); + } +} + +static void set_partition_magic(uint8_t part) +{ + uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL; + if (part == PART_BOOT) { + hal_flash_write(PART_BOOT_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + } + else if (part == PART_UPDATE) { + ext_flash_write(PART_UPDATE_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + } +} + +#else +static uint8_t *get_trailer_at(uint8_t part, uint32_t at) +{ + if (part == PART_BOOT) + return (void *)(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at)); + else if (part == PART_UPDATE) { + return (void *)(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at)); + } else + return NULL; +} + +static void set_trailer_at(uint8_t part, uint32_t at, uint8_t val) +{ + if (part == PART_BOOT) { + hal_flash_write(PART_BOOT_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&val, 1); + } + else if (part == PART_UPDATE) { + hal_flash_write(PART_UPDATE_ENDFLAGS - (sizeof(uint32_t) + at), (void *)&val, 1); + } +} + +static void set_partition_magic(uint8_t part) +{ + uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL; + if (part == PART_BOOT) { + hal_flash_write(PART_BOOT_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + } + else if (part == PART_UPDATE) { + hal_flash_write(PART_UPDATE_ENDFLAGS - sizeof(uint32_t), (void *)&wolfboot_magic_trail, sizeof(uint32_t)); + } +} +#endif /* PART_UPDATE_EXT */ + + + +static uint32_t *get_partition_magic(uint8_t part) +{ + return (uint32_t *)get_trailer_at(part, 0); +} + +static uint8_t *get_partition_state(uint8_t part) +{ + return (uint8_t *)get_trailer_at(part, 1); +} + +static uint8_t *get_sector_flags(uint8_t part, uint32_t pos) +{ + return (uint8_t *)get_trailer_at(part, 2 + pos); +} + +static void set_partition_state(uint8_t part, uint8_t val) +{ + set_trailer_at(part, 1, val); +} + +static void set_sector_flags(uint8_t part, uint32_t pos, uint8_t val) +{ + set_trailer_at(part, 2 + pos, val); } int wolfBoot_set_partition_state(uint8_t part, uint8_t newst) { - uint8_t *trailer_end = get_trailer(part); uint32_t *magic; uint8_t *state; - uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL; - if (!trailer_end) - return -1; - magic = (uint32_t *)(trailer_end - sizeof(uint32_t)); + magic = get_partition_magic(part); if (*magic != WOLFBOOT_MAGIC_TRAIL) - hal_flash_write((uint32_t)magic, (void *)&wolfboot_magic_trail, sizeof(uint32_t)); - state = (trailer_end - sizeof(uint32_t)) - 1; + set_partition_magic(part); + state = get_partition_state(part); if (*state != newst) - hal_flash_write((uint32_t)state, (void *)&newst, 1); + set_partition_state(part, newst); return 0; } int wolfBoot_set_sector_flag(uint8_t part, uint8_t sector, uint8_t newflag) { - uint8_t *trailer_end = get_trailer(part); uint32_t *magic; uint8_t *flags; uint8_t fl_value; uint32_t wolfboot_magic_trail = WOLFBOOT_MAGIC_TRAIL; uint8_t pos = sector >> 1; - if (!trailer_end) - return -1; - magic = (uint32_t *)(trailer_end - sizeof(uint32_t)); + magic = get_partition_magic(part); if (*magic != WOLFBOOT_MAGIC_TRAIL) - hal_flash_write((uint32_t)magic, (void *)&wolfboot_magic_trail, sizeof(uint32_t)); - flags = (trailer_end - sizeof(uint32_t)) - (2 + pos); + set_partition_magic(part); + flags = get_sector_flags(part, pos); if (sector == (pos << 1)) fl_value = (*flags & 0xF0) | (newflag & 0x0F); else fl_value = ((newflag & 0x0F) << 4) | (*flags & 0x0F); if (fl_value != *flags) - hal_flash_write((uint32_t)flags, &fl_value, 1); + set_sector_flags(part, pos, fl_value); return 0; } int wolfBoot_get_partition_state(uint8_t part, uint8_t *st) { - uint8_t *trailer_end = get_trailer(part); uint32_t *magic; uint8_t *state; - if (!trailer_end) - return -1; - magic = (uint32_t *)(trailer_end - sizeof(uint32_t)); + magic = get_partition_magic(part); if (*magic != WOLFBOOT_MAGIC_TRAIL) return -1; - state = (trailer_end - sizeof(uint32_t)) - 1; + state = get_partition_state(part); *st = *state; return 0; } int wolfBoot_get_sector_flag(uint8_t part, uint8_t sector, uint8_t *flag) { - uint8_t *trailer_end = get_trailer(part); uint32_t *magic; uint8_t *flags; uint8_t pos = sector >> 1; - if (!trailer_end) - return -1; - magic = (uint32_t *)(trailer_end - sizeof(uint32_t)); + magic = get_partition_magic(part); if (*magic != WOLFBOOT_MAGIC_TRAIL) return -1; - flags = (trailer_end - sizeof(uint32_t)) - (2 + pos); + flags = get_sector_flags(part, pos); if (sector == (pos << 1)) *flag = *flags & 0x0F; else @@ -111,8 +193,15 @@ void wolfBoot_erase_partition(uint8_t part) { if (part == PART_BOOT) hal_flash_erase(WOLFBOOT_PARTITION_BOOT_ADDRESS, WOLFBOOT_PARTITION_SIZE); - if (part == PART_UPDATE) + if (part == PART_UPDATE) { +#ifdef PART_UPDATE_EXT + ext_flash_unlock(); + ext_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE); + ext_flash_lock(); +#else hal_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE); +#endif + } if (part == PART_SWAP) hal_flash_erase(WOLFBOOT_PARTITION_SWAP_ADDRESS, WOLFBOOT_SECTOR_SIZE); } @@ -120,9 +209,15 @@ void wolfBoot_erase_partition(uint8_t part) void wolfBoot_update_trigger(void) { uint8_t st = IMG_STATE_UPDATING; +#ifdef PART_UPDATE_EXT + ext_flash_unlock(); + wolfBoot_set_partition_state(PART_UPDATE, st); + ext_flash_lock(); +#else hal_flash_unlock(); wolfBoot_set_partition_state(PART_UPDATE, st); hal_flash_lock(); +#endif } void wolfBoot_success(void) @@ -132,3 +227,59 @@ void wolfBoot_success(void) wolfBoot_set_partition_state(PART_BOOT, st); hal_flash_lock(); } + + +uint8_t wolfBoot_find_header(uint8_t *haystack, uint8_t type, uint8_t **ptr) +{ + uint8_t *p = haystack; + while (*p != 0) { + if (*p == HDR_PADDING) { + p++; + continue; + } + if (*p == type) { + p++; + *ptr = (p + 1); + return *p; + } + p++; + p += (*p + 1); + } + *ptr = NULL; + return 0; +} + +#ifdef EXT_FLASH +static uint8_t hdr_cpy[IMAGE_HEADER_SIZE]; +static uint32_t hdr_cpy_done = 0; +#endif + +uint32_t wolfBoot_get_image_version(uint8_t part) +{ + uint32_t *version_field = NULL; + uint32_t version = 0; + uint8_t *image = NULL; + uint32_t *magic = NULL; + if(part == PART_UPDATE) { +#ifdef PART_UPDATE_EXT + ext_flash_read((uint32_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS, hdr_cpy, IMAGE_HEADER_SIZE); + hdr_cpy_done = 1; + image = hdr_cpy; +#else + image = (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS; +#endif + } + if (part == PART_BOOT) + image = (uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS; + + if (image) { + magic = (uint32_t *)image; + if (*magic != WOLFBOOT_MAGIC) + return 0; + wolfBoot_find_header(image + IMAGE_HEADER_OFFSET, HDR_VERSION, (void *)&version_field); + if (version_field) + return *version_field; + } + return 0; +} + diff --git a/src/loader.c b/src/loader.c index c90aeaa1..ccdd551b 100644 --- a/src/loader.c +++ b/src/loader.c @@ -24,19 +24,35 @@ extern void do_boot(const uint32_t *app_offset); -static int wolfBoot_copy(uint32_t src, uint32_t dst, uint32_t size) +static int wolfBoot_copy_sector(struct wolfBoot_image *src, struct wolfBoot_image *dst, uint32_t sector) { - uint32_t *orig, *copy; + volatile uint32_t *orig, *copy; uint32_t pos = 0; + uint32_t src_sector_offset = (sector * WOLFBOOT_SECTOR_SIZE); + uint32_t dst_sector_offset = (sector * WOLFBOOT_SECTOR_SIZE); if (src == dst) return 0; - if ((src & 0x03) || (dst & 0x03)) - return -1; - while (pos < size) { - orig = (uint32_t *)(src + pos); - copy = (uint32_t *)(dst + pos); - while (*orig != *copy) - hal_flash_write(dst + pos, (void *)orig, sizeof(uint32_t)); + + if (src->part == PART_SWAP) + src_sector_offset = 0; + if (dst->part == PART_SWAP) + dst_sector_offset = 0; +#ifdef EXT_FLASH + if (PART_IS_EXT(src)) { + uint32_t word; + wb_flash_erase(dst, dst_sector_offset, WOLFBOOT_SECTOR_SIZE); + while (pos < WOLFBOOT_SECTOR_SIZE) { + ext_flash_read((uint32_t)(src->hdr) + src_sector_offset + pos, (void *)&word, sizeof(uint32_t)); + wb_flash_write_verify_word(dst, dst_sector_offset + pos, word); + pos += sizeof(uint32_t); + } + return pos; + } +#endif + wb_flash_erase(dst, dst_sector_offset, WOLFBOOT_SECTOR_SIZE); + while (pos < WOLFBOOT_SECTOR_SIZE) { + orig = (volatile uint32_t *)(src->hdr + src_sector_offset + pos); + wb_flash_write_verify_word(dst, dst_sector_offset + pos, *orig); pos += sizeof(uint32_t); } return pos; @@ -45,16 +61,20 @@ static int wolfBoot_copy(uint32_t src, uint32_t dst, uint32_t size) static int wolfBoot_update(void) { uint32_t total_size = 0; - uint32_t sector_size = WOLFBOOT_SECTOR_SIZE; + const uint32_t sector_size = WOLFBOOT_SECTOR_SIZE; uint32_t sector = 0; uint8_t flag, st; - struct wolfBoot_image boot, update; + struct wolfBoot_image boot, update, swap; + + /* No Safety check on open: we might be in the middle of a broken update */ + wolfBoot_open_image(&update, PART_UPDATE); + wolfBoot_open_image(&boot, PART_BOOT); + wolfBoot_open_image(&swap, PART_SWAP); /* Use biggest size for the swap */ - if ((wolfBoot_open_image(&update, PART_UPDATE) == 0) && (update.fw_size + IMAGE_HEADER_SIZE) > total_size) + total_size = boot.fw_size + IMAGE_HEADER_SIZE; + if ((update.fw_size + IMAGE_HEADER_SIZE) > total_size) total_size = update.fw_size + IMAGE_HEADER_SIZE; - if ((wolfBoot_open_image(&boot, PART_BOOT) == 0) && (boot.fw_size + IMAGE_HEADER_SIZE) > total_size) - total_size = boot.fw_size + IMAGE_HEADER_SIZE; if (total_size < IMAGE_HEADER_SIZE) return -1; @@ -73,6 +93,9 @@ static int wolfBoot_update(void) } hal_flash_unlock(); +#ifdef EXT_FLASH + ext_flash_unlock(); +#endif /* Interruptible swap * The status is saved in the sector flags of the update partition. @@ -81,10 +104,7 @@ static int wolfBoot_update(void) while ((sector * sector_size) < total_size) { if ((wolfBoot_get_sector_flag(PART_UPDATE, sector, &flag) != 0) || (flag == SECT_FLAG_NEW)) { flag = SECT_FLAG_SWAPPING; - hal_flash_erase(WOLFBOOT_PARTITION_SWAP_ADDRESS, WOLFBOOT_SECTOR_SIZE); - wolfBoot_copy(WOLFBOOT_PARTITION_UPDATE_ADDRESS + sector * sector_size, - WOLFBOOT_PARTITION_SWAP_ADDRESS, - WOLFBOOT_SECTOR_SIZE); + wolfBoot_copy_sector(&update, &swap, sector); wolfBoot_set_sector_flag(PART_UPDATE, sector, flag); } if (flag == SECT_FLAG_SWAPPING) { @@ -92,11 +112,7 @@ static int wolfBoot_update(void) if (size > sector_size) size = sector_size; flag = SECT_FLAG_BACKUP; - hal_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS + sector * sector_size, - WOLFBOOT_SECTOR_SIZE); - wolfBoot_copy(WOLFBOOT_PARTITION_BOOT_ADDRESS + sector * sector_size, - WOLFBOOT_PARTITION_UPDATE_ADDRESS + sector * sector_size, - WOLFBOOT_SECTOR_SIZE); + wolfBoot_copy_sector(&boot, &update, sector); wolfBoot_set_sector_flag(PART_UPDATE, sector, flag); } if (flag == SECT_FLAG_BACKUP) { @@ -104,25 +120,22 @@ static int wolfBoot_update(void) if (size > sector_size) size = sector_size; flag = SECT_FLAG_UPDATED; - hal_flash_erase(WOLFBOOT_PARTITION_BOOT_ADDRESS + sector * sector_size, - sector_size); - wolfBoot_copy(WOLFBOOT_PARTITION_SWAP_ADDRESS, - WOLFBOOT_PARTITION_BOOT_ADDRESS + sector * sector_size, - size); + wolfBoot_copy_sector(&swap, &boot, sector); wolfBoot_set_sector_flag(PART_UPDATE, sector, flag); } sector++; } while((sector * sector_size) < WOLFBOOT_PARTITION_SIZE) { - hal_flash_erase(WOLFBOOT_PARTITION_BOOT_ADDRESS + sector * sector_size, - sector_size); - hal_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS + sector * sector_size, - sector_size); + wb_flash_erase(&boot, sector * sector_size, sector_size); + wb_flash_erase(&update, sector * sector_size, sector_size); sector++; } - hal_flash_erase(WOLFBOOT_PARTITION_SWAP_ADDRESS, WOLFBOOT_SECTOR_SIZE); + wb_flash_erase(&swap, 0, WOLFBOOT_SECTOR_SIZE); st = IMG_STATE_TESTING; wolfBoot_set_partition_state(PART_BOOT, st); +#ifdef EXT_FLASH + ext_flash_lock(); +#endif hal_flash_lock(); return 0; } diff --git a/test-app/Makefile b/test-app/Makefile index f41a9ff9..c66ab3ef 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -1,13 +1,17 @@ CROSS_COMPILE:=arm-none-eabi- CC:=$(CROSS_COMPILE)gcc LD:=$(CROSS_COMPILE)gcc -OBJS:=startup.o main.o timer.o led.o system.o +OBJS:=startup.o main.o timer.o led.o system.o ../src/libwolfboot.o ../hal/$(TARGET).o TARGET?=none LSCRIPT:=app.ld OBJCOPY:=$(CROSS_COMPILE)objcopy -CFLAGS:=-mcpu=cortex-m3 -mthumb -g -ggdb -Wall -Wno-main -Wstack-usage=200 -ffreestanding -Wno-unused -nostdlib -DPLATFORM_$(TARGET) +CFLAGS:=-mcpu=cortex-m3 -mthumb -g -ggdb -Wall -Wno-main -Wstack-usage=200 -ffreestanding -Wno-unused -nostdlib -DPLATFORM_$(TARGET) -I../include LDFLAGS:=-T $(LSCRIPT) -Wl,-gc-sections -Wl,-Map=image.map -nostdlib +ifeq ($(EXT_FLASH),1) + CFLAGS+=-DEXT_FLASH=1 -DPART_UPDATE_EXT=1 +endif + image.bin: image.elf $(OBJCOPY) -O binary $^ $@ diff --git a/test-app/main.c b/test-app/main.c index 7e1b33cf..2edb14fc 100644 --- a/test-app/main.c +++ b/test-app/main.c @@ -26,10 +26,12 @@ #include "system.h" #include "timer.h" #include "led.h" +#include "wolfboot/wolfboot.h" #ifdef PLATFORM_stm32f4 void main(void) { + uint32_t version; boot_led_on(); flash_set_waitstates(); clock_config(); @@ -43,6 +45,15 @@ void main(void) { * effect. */ timer_init(CPU_FREQ, 1, 50); + version = wolfBoot_current_firmware_version(); + if (version & 0x01) { + /* Odd version: unstable, trigger update */ + if (wolfBoot_update_firmware_version() != 0) + wolfBoot_update_trigger(); + } else { + /* Even version, stabilise */ + wolfBoot_success(); + } asm volatile ("cpsie i"); while(1) WFI();