Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions .github/workflows/test-compressed-simulator.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
name: Compressed images - test with simulator target

on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

jobs:
compressed_simulator_tests:
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfboot-ci-sim:v1.0
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
# GZIP_SMALL selects a different Huffman decoder in src/gzip.c, so
# both have to be exercised and not merely built.
sign: [ ED25519, ECC256 ]
gzip_small: [ 0, 1 ]

steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Trust workspace
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: make clean
run: |
make distclean
- name: Select config
run: |
cp config/examples/sim-compressed-ram.config .config
sed -i "s/^SIGN?=.*/SIGN?=${{ matrix.sign }}/" .config
sed -i "s/^GZIP_SMALL=.*//" .config
echo "GZIP_SMALL=${{ matrix.gzip_small }}" >> .config
- name: Build tools
run: |
make -C tools/keytools && make -C tools/bin-assemble
- name: Build wolfboot.elf and test-app/image.elf
run: |
make clean && make
- name: Assemble the compressed A/B slots
run: |
make test-sim-compressed-ram-with-update
- name: Run the compressed image simulator test
run: |
./tools/scripts/sim-compressed-ram.sh
compressed_encrypted_simulator_tests:
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfboot-ci-sim:v1.0
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
# Each cipher has its own block size, which the per-slot keystream
# stride is derived from, so all three have to run.
cipher: [ chacha, aes128, aes256 ]

steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Trust workspace
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: make clean
run: |
make distclean
- name: Select config
run: |
cp config/examples/sim-compressed-ram-enc.config .config
case "${{ matrix.cipher }}" in
aes128) echo "ENCRYPT_WITH_AES128=1" >> .config ;;
aes256) echo "ENCRYPT_WITH_AES256=1" >> .config ;;
esac
- name: Build tools
run: |
make -C tools/keytools && make -C tools/bin-assemble
- name: Build wolfboot.elf and test-app/image.elf
run: |
make clean && make
- name: Assemble the encrypted compressed A/B slots
run: |
make test-sim-compressed-ram-enc-with-update
- name: Run the encrypted compressed image simulator test
run: |
./tools/scripts/sim-compressed-ram-enc.sh
compressed_cross_build:
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfboot-ci-arm:v1.0
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
config: [ stm32h7-compressed-ram, stm32f407-compressed-ram ]

steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Trust workspace
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"

- name: Select config
run: |
cp config/examples/${{ matrix.config }}.config .config
- name: Build
run: |
make clean && make keysclean && make
# A link that succeeds but places the vector table somewhere other
# than the load address boots into garbage, and nothing catches that
# without hardware. Assert the layout from the ELF instead.
- name: Check the application is linked for the load address
run: |
LOAD=$(grep -E '^WOLFBOOT_LOAD_ADDRESS\??=' .config | tail -1 | cut -d= -f2)
SIZE=$(grep -E '^WOLFBOOT_RAMBOOT_MAX_SIZE\??=' .config | tail -1 | cut -d= -f2)
echo "load address $LOAD, region size $SIZE"
# .text must start exactly at the load address, with LMA == VMA
arm-none-eabi-objdump -h test-app/image.elf | \
awk -v want=$(printf "%08x" $((LOAD))) '
$2==".text" { if ($4!=want || $5!=want) {
printf "`.text` at vma %s lma %s, expected %s\n",$4,$5,want; exit 1 }
print "ok: .text at " $4 " (lma " $5 ")" }'
# word 0 of the image is the initial stack pointer and must be the
# top of the load region
SP=$(od -An -t x4 -N 4 test-app/image.bin | tr -d ' ')
WANT_SP=$(printf "%08x" $((LOAD + SIZE)))
if [ "$SP" != "$WANT_SP" ]; then
echo "initial SP is 0x$SP, expected 0x$WANT_SP"; exit 1
fi
echo "ok: initial SP 0x$SP"
- name: Check wolfBoot does not overlap the load region
run: |
LOAD=$(grep -E '^WOLFBOOT_LOAD_ADDRESS\??=' .config | tail -1 | cut -d= -f2)
END=$(arm-none-eabi-nm wolfboot.elf | awk '$3=="_end" {print $1}')
# Only meaningful when wolfBoot's RAM and the load region share an
# address space (STM32F4); on the H7 they are different SRAMs.
if [ $((0x$END)) -ge $((LOAD)) ] && \
[ $((0x$END)) -lt $((LOAD + 0x100000)) ]; then
echo "wolfBoot _end 0x$END is inside the load region at $LOAD"; exit 1
fi
echo "ok: wolfBoot _end 0x$END clear of the load region at $LOAD"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ bootmode1/

# Emulator test: generated linker scripts
test-app/emu-test-apps/*/target.ld
test-app/*.gz

# AMD/Xilinx Versal test artifacts
uart_log*.txt
Expand Down
17 changes: 15 additions & 2 deletions arch.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3177,9 +3177,22 @@ else
endif
endif
else
ifeq ($(DUALBANK_SWAP),1)
ifeq ($(COMPRESSED_RAM_SLOTS),1)
# Compressed A/B slots, execute from RAM. Both slots hold a signed,
# gzip-compressed image; the RAM loader picks the highest valid version,
# verifies the signature over the compressed bytes and inflates to
# WOLFBOOT_LOAD_ADDRESS. There is no swap or install step, so the slot
# roles are decided per boot by version, as for the hardware bank swap.
ifeq ($(DUALBANK_SWAP),1)
$(error COMPRESSED_RAM_SLOTS=1 is incompatible with DUALBANK_SWAP=1)
endif
CFLAGS+=-DWOLFBOOT_DUALBOOT
UPDATE_OBJS:=src/update_flash_hwswap.o
UPDATE_OBJS:=src/update_ram.o
else
ifeq ($(DUALBANK_SWAP),1)
CFLAGS+=-DWOLFBOOT_DUALBOOT
UPDATE_OBJS:=src/update_flash_hwswap.o
endif
endif
endif

Expand Down
31 changes: 31 additions & 0 deletions config/examples/sim-compressed-ram-enc.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
ARCH=sim
TARGET=sim
SIGN?=ED25519
HASH?=SHA256
WOLFBOOT_SMALL_STACK?=0
SPI_FLASH=0
DEBUG=1

# Compressed A/B slots, executed from RAM, encrypted at rest.
COMPRESSED_RAM_SLOTS=1
COMPRESSED_ENCRYPT=1
GZIP=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

# See sim-compressed-ram.config for why the load region sits above wolfboot.elf.
WOLFBOOT_LOAD_ADDRESS=0x1000000
WOLFBOOT_RAMBOOT_MAX_SIZE=0x40000

# An encrypted slot cannot be verified in place, so it is decrypted into a
# staging region first. Must be disjoint from the load region, or the
# decompressor would overwrite its own input.
WOLFBOOT_COMPRESSED_STAGE_ADDRESS=0x1100000

# required for keytools
WOLFBOOT_FIXED_PARTITIONS=1
34 changes: 34 additions & 0 deletions config/examples/sim-compressed-ram.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
ARCH=sim
TARGET=sim
SIGN?=ED25519
HASH?=SHA256
WOLFBOOT_SMALL_STACK?=0
SPI_FLASH=0
DEBUG=1

# Compressed A/B slots, executed from RAM. Both slots hold a signed gzip
# stream; wolfBoot verifies the compressed bytes in place, inflates to
# WOLFBOOT_LOAD_ADDRESS and boots there.
COMPRESSED_RAM_SLOTS=1
GZIP=1

# sizes should be multiple of system page size
WOLFBOOT_PARTITION_SIZE=0x40000
WOLFBOOT_SECTOR_SIZE=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80000
# if on external flash, it should be multiple of system page size
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x100000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x180000

# The simulator's do_boot() writes a whole partition from the load address,
# so the load region must be at least WOLFBOOT_PARTITION_SIZE.
#
# WOLFBOOT_ORIGIN is 0 here (simulator flash lives at the runtime
# sim_ram_base), so the loader's bootloader-overlap guard degenerates to
# "below _end is suspect". wolfboot.elf is a non-PIE host binary loaded at
# 0x400000, so keep the load region above it.
WOLFBOOT_LOAD_ADDRESS=0x1000000
WOLFBOOT_RAMBOOT_MAX_SIZE=0x40000

# required for keytools
WOLFBOOT_FIXED_PARTITIONS=1
44 changes: 44 additions & 0 deletions config/examples/stm32f407-compressed-ram.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# STM32F407-DISCOVERY with compressed A/B images executed from RAM.
#
# The F407 has one contiguous 128KB SRAM shared between wolfBoot and the
# inflated application, so hal/stm32f4_ramboot.ld caps wolfBoot at the
# bottom 16KB and the application occupies the remaining 112KB. That is the
# ceiling on this part: the CCM RAM at 0x10000000 cannot be used, because
# on the F4 it is reachable only by the data bus and instruction fetch from
# it faults.
#
# GZIP_SMALL=1 selects the bit-serial Huffman decoder: a few KB less code
# and no static tables, which matters more than throughput on a 1MB part.
#
# Note that hal/stm32f4.c has no debug UART, so DEBUG=1 only buys symbols
# here: there is no console for the "Inflating ... done" progress line.
# Inspect the load region over SWD instead, or add a UART to the HAL.
ARCH?=ARM
TARGET?=stm32f4
SIGN?=ED25519
HASH?=SHA256
DEBUG?=1
VTOR?=1
SPMATH?=1

COMPRESSED_RAM_SLOTS?=1
GZIP?=1
GZIP_SMALL?=1

WOLFBOOT_PARTITION_SIZE?=0x20000
WOLFBOOT_SECTOR_SIZE?=0x20000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08020000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08040000
# Unused in this mode (there is no swap or install step), but still
# required by the keytools and the partition trailer layout.
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x08060000

# SRAM above wolfBoot's 16KB region. 0x400-aligned for the SCB->VTOR write.
WOLFBOOT_LOAD_ADDRESS?=0x20004000
WOLFBOOT_RAMBOOT_MAX_SIZE?=0x1C000

CLOCK_SPEED?=160000000
STM32_PLLM?=8
STM32_PLLN?=336
STM32_PLLP?=2
STM32_PLLQ?=7
66 changes: 66 additions & 0 deletions config/examples/stm32f439zi-compressed-ram.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# NUCLEO-F439ZI with compressed A/B images executed from RAM.
#
# The F439ZI has 2MB of flash and 256KB of SRAM, of which 192KB is
# contiguous at 0x20000000 (SRAM1 112KB + SRAM2 16KB + SRAM3 64KB).
# hal/stm32f4_ramboot.ld caps wolfBoot at the bottom 16KB, leaving 176KB
# for the inflated application. The 64KB CCM at 0x10000000 cannot be used:
# on the F4 it is reachable only by the data bus, so an instruction fetch
# from it faults.
#
# Console is USART3 on PD8/PD9, the ST-LINK virtual COM port on the
# NUCLEO-144 boards, via hal/uart/uart_drv_stm32f4.c.
ARCH?=ARM
TARGET?=stm32f4
SIGN?=ED25519
HASH?=SHA256
DEBUG?=1
DEBUG_UART?=1
CFLAGS_EXTRA+=-DUSE_UART3
VTOR?=1
SPMATH?=1

COMPRESSED_RAM_SLOTS?=1
GZIP?=1
# Required at a 16KB bootloader RAM region: the table-driven decoder needs
# about 19KB of .bss for its Huffman tables and fails to link.
GZIP_SMALL?=1

WOLFBOOT_PARTITION_SIZE?=0x20000
WOLFBOOT_SECTOR_SIZE?=0x20000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08020000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08040000
# Unused in this mode (there is no swap or install step), but still
# required by the keytools and the partition trailer layout.
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x08060000

# SRAM above wolfBoot's 16KB region. 0x400-aligned for the SCB->VTOR write.
# This uses all the remaining SRAM, which is the right choice when the slots
# are not encrypted; the encrypted variant below has to give some back.
WOLFBOOT_LOAD_ADDRESS?=0x20004000
WOLFBOOT_RAMBOOT_MAX_SIZE?=0x2C000

# Encryption of both slots at rest. Commented out because it needs a key
# provisioned on the device first: hal_get_image_encrypt_key() reads
# WOLFBOOT_COMPRESSED_KEY_ADDRESS, expecting the key followed by the nonce,
# and rejects an erased or all-zero region. Override that hook in the HAL to
# take the key from OTP or a secure element rather than flash.
#
# An encrypted slot cannot be verified in place, so it is decrypted into a
# staging region first, and that region must be disjoint from the load
# region. On this part the 176KB above wolfBoot therefore has to be split:
# 112KB of load region and a 64KB staging region at the top of SRAM, which
# bounds the compressed image to 64KB.
#
# Sign slot B with --encrypt-iv-offset $((WOLFBOOT_PARTITION_SIZE / 64)) for
# ChaCha20, or / 16 for AES-CTR, so the two slots never share a keystream.
#COMPRESSED_ENCRYPT?=1
#WOLFBOOT_RAMBOOT_MAX_SIZE?=0x1C000
#WOLFBOOT_COMPRESSED_STAGE_ADDRESS?=0x20020000
#WOLFBOOT_COMPRESSED_KEY_ADDRESS?=0x080E0000

# HSE 8MHz from the ST-LINK MCO -> 168MHz SYSCLK, PCLK1 42MHz
CLOCK_SPEED?=168000000
STM32_PLLM?=8
STM32_PLLN?=336
STM32_PLLP?=2
STM32_PLLQ?=7
Loading
Loading