From 10a0c0bfa06ccf5039a9571a914891fd635d2321 Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 3 Nov 2025 11:15:21 +0100 Subject: [PATCH 1/2] Add simulator support for DUALBANK, test bank swap --- .github/workflows/test-sunnyday-simulator.yml | 14 +++ config/examples/sim-dualbank.config | 18 +++ hal/sim.c | 106 ++++++++++++++++++ test-app/app_sim.c | 10 ++ tools/scripts/sim-dualbank-swap-update.sh | 42 +++++++ 5 files changed, 190 insertions(+) create mode 100644 config/examples/sim-dualbank.config create mode 100755 tools/scripts/sim-dualbank-swap-update.sh diff --git a/.github/workflows/test-sunnyday-simulator.yml b/.github/workflows/test-sunnyday-simulator.yml index 9f5a38b6eb..f59a5c3d99 100644 --- a/.github/workflows/test-sunnyday-simulator.yml +++ b/.github/workflows/test-sunnyday-simulator.yml @@ -90,6 +90,20 @@ jobs: run: | tools/scripts/sim-sunnyday-update.sh + - name: Cleanup before dualbank simulator test + run: | + make keysclean + + - name: Build wolfboot.elf (dualbank simulator) + run: | + make clean + cp config/examples/sim-dualbank.config .config + make test-sim-internal-flash-with-update + + - name: Run dualbank swap simulation + run: | + tools/scripts/sim-dualbank-swap-update.sh + - name: Build wolfboot.elf (ECC256, WOLFBOOT_SMALL_STACK) run: | make clean && make test-sim-internal-flash-with-update SIGN=ECC256 WOLFBOOT_SMALL_STACK=1 SPMATH=1 diff --git a/config/examples/sim-dualbank.config b/config/examples/sim-dualbank.config new file mode 100644 index 0000000000..805ba4b634 --- /dev/null +++ b/config/examples/sim-dualbank.config @@ -0,0 +1,18 @@ +ARCH=sim +TARGET=sim +SIGN?=ED25519 +HASH?=SHA256 +WOLFBOOT_SMALL_STACK?=0 +SPI_FLASH=0 +DEBUG=1 +DUALBANK_SWAP=1 + +# sizes should be multiple of system page size +WOLFBOOT_PARTITION_SIZE=0x40000 +WOLFBOOT_SECTOR_SIZE=0x1000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x100000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x180000 + +# required for keytools +WOLFBOOT_FIXED_PARTITIONS=1 diff --git a/hal/sim.c b/hal/sim.c index bc312c96f6..4df7f8d524 100644 --- a/hal/sim.c +++ b/hal/sim.c @@ -73,6 +73,15 @@ int extFlashLocked = 1; #define INTERNAL_FLASH_FILE "./internal_flash.dd" #define EXTERNAL_FLASH_FILE "./external_flash.dd" +#ifdef DUALBANK_SWAP +#define SIM_REGISTER_FILE "./sim_registers.dd" +#define SIM_FLASH_OPTR_SWAP_BANK (1U << 20) +static uint32_t sim_flash_optr; +static void sim_dualbank_register_load(void); +static void sim_dualbank_register_store(void); +uint32_t hal_sim_get_dualbank_state(void); +#endif + /* global used to store command line arguments to forward to the test * application */ char **main_argv; @@ -224,6 +233,57 @@ static int mmap_file(const char *path, uint8_t *address, uint8_t** ret_address) return 0; } +#ifdef DUALBANK_SWAP +static void sim_dualbank_register_store(void) +{ + int fd = open(SIM_REGISTER_FILE, O_RDWR | O_CREAT, 0644); + if (fd == -1) { + wolfBoot_printf("Failed to open %s: %s\n", SIM_REGISTER_FILE, strerror(errno)); + return; + } + + if (pwrite(fd, &sim_flash_optr, sizeof(sim_flash_optr), 0) != + (ssize_t)sizeof(sim_flash_optr)) { + wolfBoot_printf("Failed to store dualbank swap state: %s\n", + strerror(errno)); + } + + close(fd); +} + +static void sim_dualbank_register_load(void) +{ + int fd = open(SIM_REGISTER_FILE, O_RDWR | O_CREAT, 0644); + uint32_t value = 0; + int rd; + if (fd == -1) { + wolfBoot_printf("Failed to open %s: %s\n", SIM_REGISTER_FILE, + strerror(errno)); + exit(-1); + } + + rd = pread(fd, &value, sizeof(value), 0); + + if (rd == (int)sizeof(value)) { + sim_flash_optr = value; + } else { + sim_flash_optr = 0; + if (pwrite(fd, &sim_flash_optr, sizeof(sim_flash_optr), 0) != + sizeof(sim_flash_optr)) { + wolfBoot_printf("Failed to initialize dualbank swap state: %s\n", + strerror(errno)); + } + } + + close(fd); +} + +uint32_t hal_sim_get_dualbank_state(void) +{ + return (sim_flash_optr & SIM_FLASH_OPTR_SWAP_BANK) ? 1U : 0U; +} +#endif + void hal_flash_unlock(void) { flashLocked = 0; @@ -234,6 +294,46 @@ void hal_flash_lock(void) flashLocked = 1; } +#ifdef DUALBANK_SWAP +void hal_flash_dualbank_swap(void) +{ + uint8_t *boot = (uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS; + uint8_t *update = (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS; + uint8_t *buffer; + int was_locked = flashLocked; + + buffer = (uint8_t *)malloc(WOLFBOOT_PARTITION_SIZE); + if (buffer == NULL) { + wolfBoot_printf("Simulator dualbank swap failed: out of memory\n"); + exit(-1); + } + + if (was_locked) + hal_flash_unlock(); + + memcpy(buffer, boot, WOLFBOOT_PARTITION_SIZE); + memcpy(boot, update, WOLFBOOT_PARTITION_SIZE); + memcpy(update, buffer, WOLFBOOT_PARTITION_SIZE); + + if (msync(boot, WOLFBOOT_PARTITION_SIZE, MS_SYNC) != 0) { + wolfBoot_printf("msync boot partition failed: %s\n", strerror(errno)); + } + if (msync(update, WOLFBOOT_PARTITION_SIZE, MS_SYNC) != 0) { + wolfBoot_printf("msync update partition failed: %s\n", strerror(errno)); + } + + free(buffer); + + sim_flash_optr ^= SIM_FLASH_OPTR_SWAP_BANK; + sim_dualbank_register_store(); + wolfBoot_printf("Simulator dualbank swap complete, register=%u\n", + hal_sim_get_dualbank_state()); + + if (was_locked) + hal_flash_lock(); +} +#endif + void hal_prepare_boot(void) { /* no op */ @@ -312,6 +412,10 @@ void hal_init(void) } #endif /* EXT_FLASH */ +#ifdef DUALBANK_SWAP + sim_dualbank_register_load(); +#endif + for (i = 1; i < main_argc; i++) { if (strcmp(main_argv[i], "powerfail") == 0) { erasefail_address = strtol(main_argv[++i], NULL, 16); @@ -480,6 +584,7 @@ void do_boot(const uint32_t *app_offset) #endif #endif +#if !defined(WOLFBOOT_DUALBOOT) int wolfBoot_fallback_is_possible(void) { return 0; @@ -489,6 +594,7 @@ int wolfBoot_dualboot_candidate(void) { return 0; } +#endif #ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT diff --git a/test-app/app_sim.c b/test-app/app_sim.c index 5565857d79..ae8ae7dbbd 100644 --- a/test-app/app_sim.c +++ b/test-app/app_sim.c @@ -30,6 +30,10 @@ #include "wolfboot/wolfboot.h" +#ifdef DUALBANK_SWAP +uint32_t hal_sim_get_dualbank_state(void); +#endif + #ifdef TARGET_sim /* Matches all keys: @@ -72,6 +76,12 @@ int do_cmd(const char *cmd) wolfBoot_success(); return 0; } +#ifdef DUALBANK_SWAP + if (strcmp(cmd, "get_swap_state") == 0) { + printf("%u\n", hal_sim_get_dualbank_state()); + return 0; + } +#endif if (strcmp(cmd, "update_trigger") == 0) { #if EXT_ENCRYPTED wolfBoot_set_encrypt_key((uint8_t *)enc_key,(uint8_t *)(enc_key + 32)); diff --git a/tools/scripts/sim-dualbank-swap-update.sh b/tools/scripts/sim-dualbank-swap-update.sh new file mode 100755 index 0000000000..eba1ac23f6 --- /dev/null +++ b/tools/scripts/sim-dualbank-swap-update.sh @@ -0,0 +1,42 @@ +#!/bin/bash +set -euo pipefail + +if [ ! -f ".config" ]; then + echo "Missing .config. Run make config first." >&2 + exit 1 +fi + +if ! grep -Eq '^(DUALBANK_SWAP(\?|)=1)' .config; then + echo "DUALBANK_SWAP=1 is required for this simulation." >&2 + exit 1 +fi + +if [ ! -x "./wolfboot.elf" ]; then + echo "wolfboot.elf not found. Build the simulator first." >&2 + exit 1 +fi + +rm -f sim_registers.dd + +mapfile -t lines < <(./wolfboot.elf get_swap_state get_version 2>/dev/null) +if [ "${#lines[@]}" -ne 2 ] || [ "${lines[0]}" != "1" ] || [ "${lines[1]}" != "2" ]; then + echo "Unexpected output on first boot (got: ${lines[*]-})" >&2 + exit 1 +fi +echo "dualbank: first boot reports swap=${lines[0]} active_version=${lines[1]}" + +mapfile -t lines < <(./wolfboot.elf success get_swap_state get_version 2>/dev/null) +if [ "${#lines[@]}" -ne 2 ] || [ "${lines[0]}" != "1" ] || [ "${lines[1]}" != "2" ]; then + echo "Unexpected output while confirming update (got: ${lines[*]-})" >&2 + exit 1 +fi +echo "dualbank: after wolfBoot_success swap=${lines[0]} active_version=${lines[1]}" + +mapfile -t lines < <(./wolfboot.elf get_swap_state get_version 2>/dev/null) +if [ "${#lines[@]}" -ne 2 ] || [ "${lines[0]}" != "1" ] || [ "${lines[1]}" != "2" ]; then + echo "Unexpected output after confirmation (got: ${lines[*]-})" >&2 + exit 1 +fi +echo "dualbank: persistent swap state confirmed swap=${lines[0]} active_version=${lines[1]}" + +echo "Dualbank swap simulation successful." From a6d029552b495ca39b327cf712fd228e2727089b Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Mon, 3 Nov 2025 11:24:47 +0100 Subject: [PATCH 2/2] Restore .config after dualbank test --- .github/workflows/test-sunnyday-simulator.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-sunnyday-simulator.yml b/.github/workflows/test-sunnyday-simulator.yml index f59a5c3d99..04091e6e7e 100644 --- a/.github/workflows/test-sunnyday-simulator.yml +++ b/.github/workflows/test-sunnyday-simulator.yml @@ -97,13 +97,19 @@ jobs: - name: Build wolfboot.elf (dualbank simulator) run: | make clean + mv .config .config.orig cp config/examples/sim-dualbank.config .config make test-sim-internal-flash-with-update - name: Run dualbank swap simulation run: | tools/scripts/sim-dualbank-swap-update.sh - + + - name: Cleanup before WOLFBOOT_SMALL_STACK test + run: | + make keysclean + mv .config.orig .config + - name: Build wolfboot.elf (ECC256, WOLFBOOT_SMALL_STACK) run: | make clean && make test-sim-internal-flash-with-update SIGN=ECC256 WOLFBOOT_SMALL_STACK=1 SPMATH=1