Add support for simulator self-update test

pull/663/head
Brett Nicholas 2025-12-15 11:20:57 -07:00
parent 0462e0a198
commit d661c2afb3
5 changed files with 129 additions and 0 deletions

View File

@ -0,0 +1,67 @@
name: Simulator self-update test
on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]
jobs:
self_update_simulator_test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Workaround for sources.list
run: |
# Replace sources
set -euxo pipefail
# Peek (what repos are active now)
apt-cache policy
grep -RInE '^(deb|Types|URIs)' /etc/apt || true
# Enable nullglob so *.list/*.sources that don't exist don't break sed
shopt -s nullglob
echo "Replace sources.list (legacy)"
sudo sed -i \
-e "s|https\?://azure\.archive\.ubuntu\.com/ubuntu/?|http://mirror.arizona.edu/ubuntu/|g" \
/etc/apt/sources.list || true
echo "Replace sources.list.d/*.list (legacy)"
for f in /etc/apt/sources.list.d/*.list; do
sudo sed -i \
-e "s|https\?://azure\.archive\.ubuntu\.com/ubuntu/?|http://mirror.arizona.edu/ubuntu/|g" \
"$f"
done
echo "Replace sources.list.d/*.sources (deb822)"
for f in /etc/apt/sources.list.d/*.sources; do
sudo sed -i \
-e "s|https\?://azure\.archive\.ubuntu\.com/ubuntu/?|http://mirror.arizona.edu/ubuntu/|g" \
-e "s|https\?://azure\.archive\.ubuntu\.com|http://mirror.arizona.edu|g" \
"$f"
done
echo "Fix /etc/apt/apt-mirrors.txt (used by URIs: mirror+file:...)"
if grep -qE '^[[:space:]]*https?://azure\.archive\.ubuntu\.com/ubuntu/?' /etc/apt/apt-mirrors.txt; then
# Replace azure with our mirror (idempotent)
sudo sed -i 's|https\?://azure\.archive\.ubuntu\.com/ubuntu/|http://mirror.arizona.edu/ubuntu/|g' /etc/apt/apt-mirrors.txt
fi
# Peek (verify changes)
grep -RIn "azure.archive.ubuntu.com" /etc/apt || true
grep -RInE '^(deb|Types|URIs)' /etc/apt || true
echo "--- apt-mirrors.txt ---"
cat /etc/apt/apt-mirrors.txt || true
- name: Run self-update test
run: |
cp config/examples/sim-self-update.config .config
make test-sim-self-update

View File

@ -0,0 +1,19 @@
ARCH=sim
TARGET=sim
SIGN?=ED25519
HASH?=SHA256
WOLFBOOT_SMALL_STACK?=0
SPI_FLASH=0
DEBUG=1
RAM_CODE=1
WOLFBOOT_VERSION=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

View File

@ -596,6 +596,11 @@ int wolfBoot_dualboot_candidate(void)
}
#endif
void arch_reboot(void)
{
exit(0);
}
#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT
int hal_hsm_init_connect(void)

View File

@ -84,7 +84,13 @@ static void RAMFUNCTION wolfBoot_self_update(struct wolfBoot_image *src)
while (pos < src->fw_size) {
uint8_t buffer[FLASHBUFFER_SIZE];
if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
#ifdef ARCH_SIM
/* Use ARCH_FLASH_OFFSET for simulator: flash is mmap'd at runtime,
* so the linker symbol _start_text does not point to simulated flash */
uintptr_t opos = pos + ARCH_FLASH_OFFSET;
#else
uintptr_t opos = pos + ((uintptr_t)&_start_text);
#endif
ext_flash_check_read((uintptr_t)(src->hdr) + src_offset + pos, (void*)buffer, FLASHBUFFER_SIZE);
hal_flash_write(opos, buffer, FLASHBUFFER_SIZE);
}
@ -96,7 +102,13 @@ static void RAMFUNCTION wolfBoot_self_update(struct wolfBoot_image *src)
while (pos < src->fw_size) {
if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
uint8_t *orig = (uint8_t*)(src->hdr + src_offset + pos);
#ifdef ARCH_SIM
/* Use ARCH_FLASH_OFFSET for simulator: flash is mmap'd at runtime,
* so the linker symbol _start_text does not point to simulated flash */
hal_flash_write(pos + ARCH_FLASH_OFFSET, orig, FLASHBUFFER_SIZE);
#else
hal_flash_write(pos + (uintptr_t)&_start_text, orig, FLASHBUFFER_SIZE);
#endif
}
pos += FLASHBUFFER_SIZE;
}

View File

@ -240,6 +240,32 @@ test-sim-rollback-flash: wolfboot.elf test-sim-internal-flash-with-update FORCE
$(Q)(test `./wolfboot.elf success get_version` -eq 1)
$(Q)(test `./wolfboot.elf get_version` -eq 1)
# Test bootloader self-update mechanism using simulator. Since simulator memmaps runtime addresses
# the best we can do is ensure the self-update copies the intact self-update image to the expected location
test-sim-self-update: wolfboot.bin FORCE
@echo "=== Simulator Self-Update Test ==="
@# Create dummy payload (0xAA pattern) and sign as wolfBoot update v2
$(Q)dd if=/dev/zero bs=$$(wc -c < wolfboot.bin | awk '{print $$1}') count=1 2>/dev/null | tr '\000' '\252' > dummy_update.bin
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update dummy_update.bin $(PRIVATE_KEY) 2
@# Create update partition with signed update and "pBOOT" trailer. Necessary since there is no running
@# app to trigger an initial update
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > update_part.dd
$(Q)dd if=dummy_update_v2_signed.bin of=update_part.dd bs=1 conv=notrunc
$(Q)printf "pBOOT" | dd of=update_part.dd bs=1 seek=$$(($(WOLFBOOT_PARTITION_SIZE) - 5)) conv=notrunc
@# Create erased boot and swap partitions
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > boot_part.dd
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_SECTOR_SIZE))) count=1 2>/dev/null | tr '\000' '\377' > erased_sec.dd
@# Assemble flash: wolfboot.bin at 0, empty boot partition, update partition, swap
$(Q)$(BINASSEMBLE) internal_flash.dd \
0 wolfboot.bin \
$$(($(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) boot_part.dd \
$$(($(WOLFBOOT_PARTITION_UPDATE_ADDRESS) - $(ARCH_FLASH_OFFSET))) update_part.dd \
$$(($(WOLFBOOT_PARTITION_SWAP_ADDRESS) - $(ARCH_FLASH_OFFSET))) erased_sec.dd
@# Run simulator - self-update runs before app boot, writes dummy to offset 0, then reboots
$(Q)./wolfboot.elf get_version || true
@# Verify dummy payload was written to bootloader region, indicating the self update swapped images as expected
$(Q)cmp -n $$(wc -c < dummy_update.bin | awk '{print $$1}') dummy_update.bin internal_flash.dd && echo "=== Self-update test PASSED ==="
test-self-update: FORCE
@mv $(PRIVATE_KEY) private_key.old
@make clean factory.bin RAM_CODE=1 WOLFBOOT_VERSION=1 SIGN=$(SIGN)