Skip to content
Merged
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
34 changes: 34 additions & 0 deletions .github/workflows/dualbank-emulator-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: dualbank-emulator-tests

on:
push:
pull_request:

jobs:
stm32u5-dualbank-swap-fallback:
runs-on: ubuntu-latest
container:
image: ghcr.io/wolfssl/wolfboot-ci-m33mu:latest
steps:
- uses: actions/checkout@v4

- name: Init submodules
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git submodule update --init --single-branch

- name: Configure stm32u5 (non-secure dual-bank, hardware-assisted swap)
run: |
cp config/examples/stm32u5-nonsecure-dualbank.config .config

- name: Run dual-bank swap fallback test (stm32u5)
working-directory: test-app/emu-test-apps
run: |
./test-dualbank.sh

- name: Upload emulator log on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: dualbank-fallback-log
path: test-app/emu-test-apps/stm32u585-dualbank/dualbank_fallback.log
7 changes: 7 additions & 0 deletions hal/stm32u5.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
*cr &= ~FLASH_CR_PER ;
return 0; /* Address out of range */
}
/* BKER refers to the physical bank, whatever the SWAP_BANK setting
* (RM0456 7.5.8): invert it when the banks are swapped, so that the
* erased bank is the one currently mapped at the target address. */
if ((FLASH_OPTR & (FLASH_OPTR_DBANK | FLASH_OPTR_SWAP_BANK)) ==
(FLASH_OPTR_DBANK | FLASH_OPTR_SWAP_BANK)) {
bker ^= FLASH_CR_BKER;
}
reg = *cr & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_BKER));
reg |= ((((p - base) >> 13) << FLASH_CR_PNB_SHIFT) | FLASH_CR_PER | bker );
*cr = reg;
Expand Down
55 changes: 55 additions & 0 deletions test-app/emu-test-apps/stm32u585-dualbank/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Makefile
#
# Copyright (C) 2026 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 3 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 ../../../.config

WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08010000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08110000
WOLFBOOT_PARTITION_SIZE?=0x30000
IMAGE_HEADER_SIZE?=1024

APP_ORIGIN=$(shell printf '0x%08x' $$(( $(WOLFBOOT_PARTITION_BOOT_ADDRESS) + $(IMAGE_HEADER_SIZE) )))
APP_SIZE=$(shell printf '0x%08x' $$(( $(WOLFBOOT_PARTITION_SIZE) - $(IMAGE_HEADER_SIZE) )))
MARKER_ADDR=$(shell printf '0x%08x' $$(( $(WOLFBOOT_PARTITION_BOOT_ADDRESS) + $(WOLFBOOT_PARTITION_SIZE) )))

CC=arm-none-eabi-gcc
OBJCOPY?=arm-none-eabi-objcopy

CFLAGS:=-mcpu=cortex-m33 -mthumb -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb
CFLAGS+=-DUPDATE_BASE=$(WOLFBOOT_PARTITION_UPDATE_ADDRESS)u
CFLAGS+=-DMARKER_ADDR=$(MARKER_ADDR)u
LDFLAGS:=-nostdlib -T target.ld -Wl,-gc-sections

all: app.bin

target.ld: target.ld.in
sed -e "s/@FLASH_ORIGIN@/$(APP_ORIGIN)/g" \
-e "s/@FLASH_SIZE@/$(APP_SIZE)/g" $< > $@

app.elf: staging_app.c target.ld
$(CC) $(CFLAGS) staging_app.c $(LDFLAGS) -o $@

app.bin: app.elf
$(OBJCOPY) -O binary $< $@

clean:
rm -f app.elf app.bin image.bin image_v*_signed.bin target.ld

.PHONY: all clean
132 changes: 132 additions & 0 deletions test-app/emu-test-apps/stm32u585-dualbank/staging_app.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* staging_app.c
*
* Test application for the STM32U585 DUALBANK_SWAP fallback scenario.
*
* Copyright (C) 2026 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 3 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
*/

/* This image is signed as version 2 and pre-loaded into the UPDATE
* partition, with the BOOT partition empty. The test then exercises the
* hardware-assisted bank swap and the fallback path in a single
* emulator session:
*
* boot 1: wolfBoot selects the update (v2 vs empty), verifies it and
* activates SWAP_BANK, then reboots. This app now sits in the
* logical BOOT partition, mapped to physical bank 2.
* boot 2: wolfBoot boots this app. First run (marker empty): program a
* fake v3 image header (valid magic/size/version, no integrity
* TLVs) into the logical UPDATE partition, set the marker and
* reboot. This simulates staging a corrupted update while
* running from bank 2.
* boot 3: wolfBoot picks the fake v3 update, verification fails, and it
* must erase the CORRUPT UPDATE image (physical bank 1) and
* fall back to this image (physical bank 2). Second run of this
* app (marker set): report success with bkpt 0x7f.
*
* With the pre-fix hal_flash_erase (BKER derived from the logical
* address only), boot 3 erases the healthy image instead and the device
* bricks: bkpt 0x7f is never reached.
*/

#include <stdint.h>

/* Defaults match config/examples/stm32u5-nonsecure-dualbank.config; the
* Makefile overrides them from the current .config. */
#ifndef UPDATE_BASE
#define UPDATE_BASE 0x08110000u /* WOLFBOOT_PARTITION_UPDATE_ADDRESS */
#endif
#ifndef MARKER_ADDR
#define MARKER_ADDR 0x08040000u /* BOOT partition end: unused flash */
#endif

#define FLASH_REGS 0x40022000u
#define FLASH_NSKEYR (*(volatile uint32_t *)(FLASH_REGS + 0x008u))
#define FLASH_NSCR (*(volatile uint32_t *)(FLASH_REGS + 0x028u))

#define FLASH_KEY1 0x45670123u
#define FLASH_KEY2 0xCDEF89ABu
#define FLASH_CR_PG (1u << 0)

#define AIRCR (*(volatile uint32_t *)0xE000ED0Cu)
#define AIRCR_RESET 0x05FA0004u

#define MARKER_VALUE 0xDEADC0DEu

extern uint32_t _estack;

static void bkpt_ok(void)
{
__asm volatile("bkpt #0x7f");
while (1) { }
}

static void flash_program_word(uint32_t addr, uint32_t val)
{
*(volatile uint32_t *)addr = val;
}

void app_main(void)
{
if (*(volatile uint32_t *)MARKER_ADDR == MARKER_VALUE) {
/* Second run: wolfBoot erased the corrupt update and fell back
* to this image. */
bkpt_ok();
}

/* First run: stage a fake v3 image in the UPDATE partition. The
* target area is empty flash, so plain programming is enough.
* Header: magic 'WOLF', size 0x400, version TLV (tag 0x0001, len 4,
* value 3). No SHA/signature TLVs, so verification must fail. */
FLASH_NSKEYR = FLASH_KEY1;
FLASH_NSKEYR = FLASH_KEY2;
FLASH_NSCR |= FLASH_CR_PG;

flash_program_word(UPDATE_BASE + 0u, 0x464C4F57u);
flash_program_word(UPDATE_BASE + 4u, 0x00000400u);
flash_program_word(UPDATE_BASE + 8u, 0x00040001u);
flash_program_word(UPDATE_BASE + 12u, 0x00000003u);

flash_program_word(MARKER_ADDR, MARKER_VALUE);

FLASH_NSCR &= ~FLASH_CR_PG;

AIRCR = AIRCR_RESET;
while (1) { }
}

void Reset_Handler(void)
{
app_main();
while (1) { }
}

static void spin(void)
{
while (1) { }
}

__attribute__((section(".isr_vector"), used))
const void * const vector_table[16] = {
(void *)&_estack,
(void *)Reset_Handler,
(void *)spin, (void *)spin, (void *)spin, (void *)spin,
(void *)spin, (void *)spin, (void *)spin, (void *)spin,
(void *)spin, (void *)spin, (void *)spin, (void *)spin,
(void *)spin, (void *)spin,
};
20 changes: 20 additions & 0 deletions test-app/emu-test-apps/stm32u585-dualbank/target.ld.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* Linker template for the STM32U585 dual-bank staging app.
* @FLASH_ORIGIN@ is WOLFBOOT_PARTITION_BOOT_ADDRESS + IMAGE_HEADER_SIZE,
* @FLASH_SIZE@ is WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE. */
MEMORY
{
FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = @FLASH_SIZE@
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000
}

_estack = ORIGIN(RAM) + LENGTH(RAM) - 16;

SECTIONS
{
.text :
{
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
} > FLASH
}
Loading
Loading