diff --git a/.gitignore b/.gitignore index 2e3f17d1..c235dd1f 100644 --- a/.gitignore +++ b/.gitignore @@ -110,3 +110,6 @@ IDE/IAR/settings IDE/IAR/*.ewt IDE/IAR/Debug IDE/IAR/Release + +# Simulated Flash files +*.dd \ No newline at end of file diff --git a/Makefile b/Makefile index b860b566..d62378a4 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,10 @@ ifeq ($(TARGET),library) MAIN_TARGET:=test-lib endif +ifeq ($(TARGET),sim) + MAIN_TARGET:=wolfboot.elf test-app/image_v1_signed.bin internal_flash.dd +endif + ASFLAGS:=$(CFLAGS) BOOTLOADER_PARTITION_SIZE?=$$(( $(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) @@ -130,10 +134,21 @@ keytools: @make -C tools/keytools clean @make -C tools/keytools -test-app/image_v1_signed.bin: test-app/image.bin +test-app/image_v1_signed.bin: $(BOOT_IMG) @echo "\t[SIGN] $(BOOT_IMG)" $(Q)$(SIGN_TOOL) $(SIGN_OPTIONS) $(BOOT_IMG) $(PRIVATE_KEY) 1 +test-app/image.elf: wolfboot.elf + $(Q)$(MAKE) -C test-app WOLFBOOT_ROOT=$(WOLFBOOT_ROOT) image.elf + $(Q)$(SIZE) test-app/image.elf + +internal_flash.dd: test-app/image_v1_signed.bin wolfboot.elf $(BINASSEMBLE) + @echo "\t[MERGE] internal_flash.dd" + $(Q)dd if=/dev/zero bs=1 count=$$(($(WOLFBOOT_SECTOR_SIZE))) > /tmp/swap + $(Q)$(BINASSEMBLE) $@ 0 test-app/image_v1_signed.bin \ + $(WOLFBOOT_PARTITION_SIZE) /tmp/swap \ + $$(($(WOLFBOOT_PARTITION_SIZE)*2)) /tmp/swap + factory.bin: $(BOOT_IMG) wolfboot.bin $(PRIVATE_KEY) test-app/image_v1_signed.bin $(BINASSEMBLE) @echo "\t[MERGE] $@" $(Q)$(BINASSEMBLE) $@ $(ARCH_FLASH_OFFSET) wolfboot.bin \ diff --git a/arch.mk b/arch.mk index d3266d4b..f412808e 100644 --- a/arch.mk +++ b/arch.mk @@ -368,6 +368,15 @@ ifeq ($(TARGET),x86_64_efi) UPDATE_OBJS:=src/update_ram.o endif +ifeq ($(TARGET),sim) + USE_GCC_HEADLESS=0 + LD = gcc + UPDATE_OBJS:=src/update_flash.o + LD_START_GROUP= + LD_END_GROUP= + BOOT_IMG=test-app/image.elf +endif + BOOT_IMG?=test-app/image.bin ## Update mechanism diff --git a/config/examples/sim.config b/config/examples/sim.config new file mode 100644 index 00000000..e27945a8 --- /dev/null +++ b/config/examples/sim.config @@ -0,0 +1,16 @@ +ARCH=sim +TARGET=sim +SIGN?=ED25519 +HASH?=SHA256 +WOLFBOOT_SMALL_STACK=1 +SPI_FLASH=0 +DEBUG=1 +# it should be multiple of system page size +WOLFBOOT_PARTITION_SIZE=0x2A000 +WOLFBOOT_SECTOR_SIZE=0x1000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x10000 +# if on external flash, it should be multiple of system page size +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x3a000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x64000 +# required for keytools +WOLFBOOT_FIXED_PARTITIONS=1 \ No newline at end of file diff --git a/docs/Targets.md b/docs/Targets.md index 1c811473..4ab2d26c 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -1136,3 +1136,31 @@ Example of flash memory layout and configuration on the nRF52: #define WOLFBOOT_PARTITION_SWAP_ADDRESS 0x57000 #define WOLFBOOT_PARTITION_UPDATE_ADDRESS 0x58000 ``` +## Simulated + +You can create a simulated target that uses files to mimic an internal and +optionally an external flash. The build will produce an executable ELF file +`wolfBoot.elf`. You can provide another executable ELF as firmware image and it +will be executed. The command-line arguments of `wolfBoot.elf` are forwarded to +the application. The example application `test-app\app_sim.c` uses the arguments +to interact with `libwolfboot.c` and automatize functional testing. You can +find an example configuration in `config/examples/sim.config`. + +An example of using the `test-app/sim.c` to test firmware update: + +``` +cp ./config/examples/sim.config .config +make + +# create the file internal_flash.dd with firmware v1 on the boot partition and +# firmware v2 on the update partition +make test-sim-internal-flash-with-update +# it should print 1 +./wolfboot.elf success get_version +# trigger an update +./wolfboot.elf update_trigger +# it should print 2 +./wolfboot.elf success get_version +# it should print 2 +./wolfboot.elf success get_version +``` diff --git a/hal/sim.c b/hal/sim.c new file mode 100644 index 00000000..d91ae4e0 --- /dev/null +++ b/hal/sim.c @@ -0,0 +1,194 @@ +/* sim.c + * + * Copyright (C) 2022 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 2 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 + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wolfboot/wolfboot.h" +#include "target.h" + +static uint8_t *ram_base; +static uint8_t *flash_base; + +#define INTERNAL_FLASH_FILE "./internal_flash.dd" +#define EXTERNAL_FLASH_FILE "./external_flash.dd" + +/* global used to store command line arguments to forward to the test + * application */ +char **main_argv; +int main_argc; + +static int mmap_file(const char *path, uint8_t *address, uint8_t** ret_address) +{ + struct stat st = { 0 }; + uint8_t *mmaped_addr; + int ret; + int fd; + + if (path == NULL) + return -1; + + ret = stat(path, &st); + if (ret == -1) + return -1; + + fd = open(path, O_RDWR); + if (fd == -1) { + printf("can't open %s\n", path); + return -1; + } + + mmaped_addr = mmap(address, st.st_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (mmaped_addr == MAP_FAILED) + return -1; + + if (address != NULL && mmaped_addr != address) { + munmap(address, st.st_size); + return -1; + } + + *ret_address = mmaped_addr; + + close(fd); + return 0; +} + +void hal_flash_unlock(void) +{ + /* no op */ +} + +void hal_flash_lock(void) +{ + /* no op */ +} + +void hal_prepare_boot(void) +{ + /* no op */ +} + +int hal_flash_write(uint32_t address, const uint8_t *data, int len) +{ + uint8_t *ptr = 0; + + /* implicit cast abide compiler warning */ + memcpy(ptr + address, data, len); + return 0; +} + +int hal_flash_erase(uint32_t address, int len) +{ + uint8_t *ptr = 0; + + /* implicit cast abide compiler warning */ + memset(ptr + address, 0xff, len); + return 0; +} + +void hal_init(void) +{ + int ret; + uint8_t *p; + ret = mmap_file(INTERNAL_FLASH_FILE, + (uint8_t*)WOLFBOOT_PARTITION_BOOT_ADDRESS, &p); + if (ret != 0) { + printf("failed to load internal flash file\n"); + exit(-1); + } + +#ifdef EXT_FLASH + ret = mmap_file(EXTERNAL_FLASH_FILE, NULL, &flash_base); + if (ret != 0) { + printf("failed to load internal flash file\n"); + exit(-1); + } +#endif /* EXT_FLASH */ +} + +void ext_flash_lock(void) +{ + /* no op */ +} + +void ext_flash_unlock(void) +{ + /* no op */ +} + +int ext_flash_write(uintptr_t address, const uint8_t *data, int len) +{ + memcpy(flash_base + address, data, len); + return 0; +} + +int ext_flash_read(uintptr_t address, uint8_t *data, int len) +{ + memcpy(data, flash_base + address, len); + return len; +} + +int ext_flash_erase(uintptr_t address, int len) +{ + memset(flash_base + address, 0xff, len); + return 0; +} + +void do_boot(const uint32_t *app_offset) +{ + char *envp[1] = {NULL}; + int ret; + int fd; + + fd = memfd_create("test_app", 0); + if (fd == -1) { + printf("memfd error\n"); + exit(-1); + } + + ret = write(fd, app_offset, WOLFBOOT_PARTITION_SIZE); + if (ret != WOLFBOOT_PARTITION_SIZE) { + printf("can't write test-app to memfd\n"); + exit(-1); + } + + ret = fexecve(fd, main_argv, envp); + printf("fexecve error\n"); + exit(1); +} + +int wolfBoot_fallback_is_possible(void) +{ + return 0; +} + +int wolfBoot_dualboot_candidate(void) +{ + return 0; +} diff --git a/hal/sim.ld b/hal/sim.ld new file mode 100644 index 00000000..dcfab641 --- /dev/null +++ b/hal/sim.ld @@ -0,0 +1 @@ +# abide Makefile diff --git a/src/loader.c b/src/loader.c index 5ce83ad6..99fb75c8 100644 --- a/src/loader.c +++ b/src/loader.c @@ -32,8 +32,22 @@ static volatile const uint32_t __attribute__((used)) wolfboot_version = WOLFBOOT extern void (** const IV_RAM)(void); #endif +#ifdef PLATFORM_sim +extern char **main_argv; +extern int main_argc; +int main(int argc, char *argv[]) +#else int main(void) +#endif { + +#ifdef PLATFORM_sim + /* to forward arguments to the test-app for testing. See + * test-app/app_sim.c */ + main_argv = argv; + main_argc = argc; +#endif + hal_init(); spi_flash_probe(); #ifdef UART_FLASH diff --git a/test-app/Makefile b/test-app/Makefile index b5d67ceb..a63ab848 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -6,6 +6,11 @@ TARGET?=none ARCH?=ARM MCUXPRESSO_CMSIS?=$(MCUXPRESSO)/CMSIS + +ifeq ($(TARGET),sim) + LDFLAGS=-Wl,-gc-sections -Wl,-Map=image.map +endif + ifeq ($(SIGN),RSA2048) IMAGE_HEADER_SIZE:=512 endif @@ -117,6 +122,11 @@ else LDFLAGS+=-T $(LSCRIPT) -Wl,-gc-sections -Wl,-Map=image.map endif +ifeq ($(TARGET),sim) + LDFLAGS=-Wl,-gc-sections -Wl,-Map=image.map + APP_OBJS=app_$(TARGET).o ../src/libwolfboot.o ../hal/$(TARGET).o +endif + ifeq ($(EXT_FLASH),1) CFLAGS+=-D"EXT_FLASH=1" -D"PART_UPDATE_EXT=1" endif diff --git a/test-app/app_sim.c b/test-app/app_sim.c new file mode 100644 index 00000000..72fad933 --- /dev/null +++ b/test-app/app_sim.c @@ -0,0 +1,75 @@ +/* app_sim.c + * + * Test bare-metal boot-led-on application + * + * Copyright (C) 2022 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 2 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 +#include +#include +#include +#include + +#include "wolfboot/wolfboot.h" + +#ifdef PLATFORM_sim + +void hal_init(void); + +int do_cmd(const char *cmd) +{ + if (strcmp(cmd, "get_version") == 0) { + printf("%d", wolfBoot_current_firmware_version()); + return 0; + } + + if (strcmp(cmd, "success") == 0) { + wolfBoot_success(); + return 0; + } + + if (strcmp(cmd, "update_trigger") == 0) { + wolfBoot_update_trigger(); + return 0; + } + + if (strcmp(cmd, "reset") == 0) { + exit(0); + } + + /* wrong command */ + return -1; +} + +int main(int argc, char *argv[]) { + + int i; + + hal_init(); + + for (i = 1; i < argc; ++i) { + if (do_cmd(argv[i]) != 0) + return -1; + } + + return 0; + +} +#endif /** PLATFROM_sim **/ diff --git a/test-app/sim.ld b/test-app/sim.ld new file mode 100644 index 00000000..dcfab641 --- /dev/null +++ b/test-app/sim.ld @@ -0,0 +1 @@ +# abide Makefile