diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml new file mode 100644 index 0000000000..75ff20e945 --- /dev/null +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -0,0 +1,50 @@ +name: trustzone-emulator-tests + +on: + push: + pull_request: + +jobs: + trustzone-emulator-tests: + runs-on: ubuntu-latest + container: + image: ghcr.io/danielinux/m33mu-ci:1.2 + 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 stm32h5 (TZ) and build wolfboot + run: | + cp config/examples/stm32h5-tz.config .config + make wolfboot.bin + + - name: Run emu test (stm32h5) + working-directory: test-app/emu-test-apps + run: | + ./test.sh + + - name: Clean and build stm32u5 (TZ + wolfcrypt) + run: | + make clean distclean + cp config/examples/stm32u5-wolfcrypt-tz.config .config + make wolfboot.bin + + - name: Run emu test (stm32u5) + working-directory: test-app/emu-test-apps + run: | + TARGET=stm32u5 ./test.sh + + - name: Clean and build stm32l5 (TZ + wolfcrypt) + run: | + make clean distclean + cp config/examples/stm32l5-wolfcrypt-tz.config .config + make wolfboot.bin + + - name: Run emu test (stm32u5) + working-directory: test-app/emu-test-apps + run: | + TARGET=stm32l5 ./test.sh diff --git a/.gitignore b/.gitignore index 61451464e0..42556e40b6 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ *.idb *.pdb *.gdb +*.log # automatically generated keys *.der @@ -91,6 +92,9 @@ tools/delta/bmpatch # otp-keystore-gen binary tools/keytools/otp/otp-keystore-gen +# test-server binary +test-app/emu-test-apps/*/test-update-server + # Vim swap files .*.swp diff --git a/.gitmodules b/.gitmodules index e528d9353a..6cd81662fe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,4 +12,4 @@ url = https://github.com/wolfssl/wolfhsm.git [submodule "lib/wolfPSA"] path = lib/wolfPSA - url = git@github.com:wolfSSL/wolfPSA.git + url = https://github.com/wolfSSL/wolfPSA.git diff --git a/Makefile b/Makefile index bb62d3d320..e604bc8f08 100644 --- a/Makefile +++ b/Makefile @@ -340,6 +340,9 @@ hal/$(TARGET).o: keytools_check: keytools +test-emu: + $(MAKE) -C test-app/emu-test-apps WOLFBOOT_ROOT="$(CURDIR)" test-emu + # Generate the initial signing key (only if not using user-provided keys) # - Creates wolfboot_signing_private_key.der when USER_PRIVATE_KEY is not set # - If CERT_CHAIN_VERIFY is enabled and USER_CERT_CHAIN not provided, also generates cert chain with leaf key diff --git a/config/examples/stm32u5-wolfcrypt-tz.config b/config/examples/stm32u5-wolfcrypt-tz.config index 207f8a415e..5cd81fef6f 100644 --- a/config/examples/stm32u5-wolfcrypt-tz.config +++ b/config/examples/stm32u5-wolfcrypt-tz.config @@ -18,15 +18,15 @@ V?=0 SPMATH?=1 RAM_CODE?=0 DUALBANK_SWAP?=0 -WOLFBOOT_PARTITION_SIZE?=0x1F800 -WOLFBOOT_SECTOR_SIZE?=0x800 +WOLFBOOT_PARTITION_SIZE?=0x20000 +WOLFBOOT_SECTOR_SIZE?=0x2000 WOLFBOOT_KEYVAULT_ADDRESS?=0x0C020000 WOLFBOOT_KEYVAULT_SIZE?=0x18000 WOLFBOOT_NSC_ADDRESS?=0x0C038000 WOLFBOOT_NSC_SIZE?=0x8000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08040000 -WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x805F800 -WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0807F000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x08060000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x08080000 FLAGS_HOME=0 DISABLE_BACKUP=0 WOLFCRYPT_TZ=1 diff --git a/config/examples/stm32u5.config b/config/examples/stm32u5.config index fdf0eaa08c..b8be273f0f 100644 --- a/config/examples/stm32u5.config +++ b/config/examples/stm32u5.config @@ -21,7 +21,7 @@ SPMATH?=1 RAM_CODE?=0 DUALBANK_SWAP?=0 WOLFBOOT_PARTITION_SIZE?=0x1F800 -WOLFBOOT_SECTOR_SIZE?=0x800 +WOLFBOOT_SECTOR_SIZE?=0x2000 WOLFBOOT_KEYVAULT_ADDRESS?=0x0C020000 WOLFBOOT_KEYVAULT_SIZE?=0x18000 WOLFBOOT_NSC_ADDRESS?=0x0C038000 diff --git a/hal/stm32_tz.c b/hal/stm32_tz.c index ae6f05c240..d7b67d58a5 100644 --- a/hal/stm32_tz.c +++ b/hal/stm32_tz.c @@ -29,7 +29,7 @@ #include "hal/stm32u5.h" #endif -#ifdef TARGET_stm32h5 +#if defined(TARGET_stm32h5) #include "hal/stm32h5.h" #endif @@ -225,6 +225,38 @@ void hal_gtzc_init(void) } } +#elif defined(TARGET_stm32u5) + +#define GTZC_MPCBB1_S_BASE (0x50032C00) +#define GTZC_MPCBB1_S_VCTR_BASE (GTZC_MPCBB1_S_BASE + 0x100) + +#define GTZC_MPCBB2_S_BASE (0x50033000) +#define GTZC_MPCBB2_S_VCTR_BASE (GTZC_MPCBB2_S_BASE + 0x100) + +#define SET_GTZC_MPCBBx_S_VCTR(bank,n,val) \ + (*((volatile uint32_t *)(GTZC_MPCBB##bank##_S_VCTR_BASE ) + n ))= val + +void hal_gtzc_init(void) +{ + int i; + /* One bit in the bitmask: 512B (STM32U5) */ + + /* Configure SRAM1 lower 128 KB as secure (0x20000000 - 0x2001FFFF). */ + for (i = 0; i < 8; i++) { + SET_GTZC_MPCBBx_S_VCTR(1, i, 0xFFFFFFFF); + } + + /* Configure SRAM1 upper 128 KB as non-secure (0x20020000 - 0x2003FFFF). */ + for (i = 8; i < 16; i++) { + SET_GTZC_MPCBBx_S_VCTR(1, i, 0x0); + } + + /* Configure SRAM2 as non-secure (0x20030000 - 0x2003FFFF). */ + for (i = 0; i < 4; i++) { + SET_GTZC_MPCBBx_S_VCTR(2, i, 0x0); + } +} + #else #define GTZC_MPCBB1_S_BASE (0x50032C00) diff --git a/hal/stm32l5.c b/hal/stm32l5.c index dc43031d08..e9bbba8808 100644 --- a/hal/stm32l5.c +++ b/hal/stm32l5.c @@ -25,7 +25,6 @@ #include "hal.h" #include "hal/stm32l5.h" -#include "printf.h" static void RAMFUNCTION flash_set_waitstates(unsigned int waitstates) @@ -152,13 +151,6 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) uint32_t end_address; uint32_t p; - if (address < WOLFBOOT_PARTITION_BOOT_ADDRESS) { - wolfBoot_printf("hal_flash_erase: addr=0x%08x len=%d (below boot)\n", - address, len); - } else { - wolfBoot_printf("hal_flash_erase: addr=0x%08x len=%d\n", address, len); - } - hal_flash_clear_errors(0); if (len == 0) return -1; diff --git a/hal/stm32u5.c b/hal/stm32u5.c index a160ef85f9..683e120f2e 100644 --- a/hal/stm32u5.c +++ b/hal/stm32u5.c @@ -489,6 +489,35 @@ static void led_unsecure() #endif } +#if TZ_SECURE() +#define TZSC1_BASE 0x50032400u +#define TZSC_SECCFGR1 (*(volatile uint32_t *)(TZSC1_BASE + 0x10u)) +#define TZSC_SECCFGR1_USART3SEC (1u << 10) + +static void periph_unsecure(void) +{ + volatile uint32_t reg; + + /* Enable clock for GPIO D (USART3 pins PD8/PD9) */ + RCC_AHB2ENR1_CLOCK_ER |= GPIOD_AHB2ENR1_CLOCK_ER; + + /* Enable clock for USART3 */ + RCC_APB1LENR |= (1u << 18); + + /* Unsecure USART3 pins (PD8 TX, PD9 RX) */ + GPIOD_SECCFGR &= ~(1u << 8); + GPIOD_SECCFGR &= ~(1u << 9); + + /* Unsecure USART3 peripheral in GTZC TZSC */ + reg = TZSC_SECCFGR1; + if (reg & TZSC_SECCFGR1_USART3SEC) { + reg &= ~TZSC_SECCFGR1_USART3SEC; + DMB(); + TZSC_SECCFGR1 = reg; + } +} +#endif + #if defined(DUALBANK_SWAP) && defined(__WOLFBOOT) static uint8_t bootloader_copy_mem[BOOTLOADER_SIZE]; static void RAMFUNCTION fork_bootloader(void) @@ -530,6 +559,7 @@ void hal_prepare_boot(void) clock_pll_off(); #endif #if TZ_SECURE() + periph_unsecure(); led_unsecure(); #endif } diff --git a/hal/stm32u5.h b/hal/stm32u5.h index cf58f4621c..eb45e6b85e 100644 --- a/hal/stm32u5.h +++ b/hal/stm32u5.h @@ -119,6 +119,8 @@ #define RCC_AHB3ENR (*(volatile uint32_t *)(RCC_BASE + 0x94)) /* RM0456 - Table 108 */ #define RCC_AHB3ENR_GTZC2EN (1 << 12) + +#define RCC_APB1LENR (*(volatile uint32_t *)(RCC_BASE + 0x9C)) /* RM0456 - Table 108 */ #define RCC_AHB3ENR_PWREN (1 << 2) #define RCC_ICSCR1 (*(volatile uint32_t *)(RCC_BASE + 0x08)) @@ -249,10 +251,12 @@ /* GPIO*/ #define GPIOC_BASE 0x52020800 +#define GPIOD_BASE 0x52020C00 #define GPIOG_BASE 0x52021800 #define GPIOH_BASE 0x52021C00 #define GPIOC_SECCFGR (*(volatile uint32_t *)(GPIOC_BASE + 0x30)) +#define GPIOD_SECCFGR (*(volatile uint32_t *)(GPIOD_BASE + 0x30)) #define GPIOG_SECCFGR (*(volatile uint32_t *)(GPIOG_BASE + 0x30)) #define GPIOH_SECCFGR (*(volatile uint32_t *)(GPIOH_BASE + 0x30)) @@ -266,6 +270,7 @@ #define RCC_AHB2ENR1_CLOCK_ER (*(volatile uint32_t *)(RCC_BASE + 0x8C )) #define GPIOC_AHB2ENR1_CLOCK_ER (1 << 2) +#define GPIOD_AHB2ENR1_CLOCK_ER (1 << 3) #define GPIOG_AHB2ENR1_CLOCK_ER (1 << 6) #define GPIOH_AHB2ENR1_CLOCK_ER (1 << 7) #define TRNG_AHB2_CLOCK_ER (1 << 18) diff --git a/test-app/emu-test-apps/Makefile b/test-app/emu-test-apps/Makefile new file mode 100644 index 0000000000..01f73e4d58 --- /dev/null +++ b/test-app/emu-test-apps/Makefile @@ -0,0 +1,105 @@ +# 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 +include ../../tools/config.mk +include ../../options.mk +include ../../tools/test.mk + +ifneq ($(wildcard $(WOLFBOOT_ROOT)/lib/wolfssl/wolfcrypt/src/asn.c),) + WOLFBOOT_LIB_WOLFSSL:=$(WOLFBOOT_ROOT)/lib/wolfssl +else ifneq ($(wildcard $(WOLFBOOT_ROOT)/../wolfssl/wolfcrypt/src/asn.c),) + WOLFBOOT_LIB_WOLFSSL:=$(WOLFBOOT_ROOT)/../wolfssl +endif +export WOLFBOOT_LIB_WOLFSSL + +WOLFBOOT_ROOT?=$(abspath ../..) + +EMU_VERSION?=1 +EMU_EXPECT_VERSION?=$(EMU_VERSION) +PRIVATE_KEY?=$(WOLFBOOT_ROOT)/wolfboot_signing_private_key.der + +M33MU?=$(WOLFBOOT_ROOT)/../m33mu/build/m33mu + +ifeq ($(TARGET),stm32h563) + EMU_DIR=stm32h563 + EMU_CPU=stm32h563 +else ifeq ($(TARGET),stm32h5) + EMU_DIR=stm32h563 + EMU_CPU=stm32h563 +else ifeq ($(TARGET),stm32u585) + EMU_DIR=stm32u585 + EMU_CPU=stm32u585 +else ifeq ($(TARGET),stm32u5) + EMU_DIR=stm32u585 + EMU_CPU=stm32u585 +else ifeq ($(TARGET),stm32l552) + EMU_DIR=stm32l552 + EMU_CPU=stm32l552 +else ifeq ($(TARGET),stm32l5) + EMU_DIR=stm32l552 + EMU_CPU=stm32l552 +else ifeq ($(TARGET),nrf5340) + EMU_DIR=nrf5340 + EMU_CPU=nrf5340 +else ifeq ($(TARGET),mcxw) + EMU_DIR=mcxw71 + EMU_CPU=mcxw71c +else ifeq ($(TARGET),mcxw71) + EMU_DIR=mcxw71 + EMU_CPU=mcxw71c +else + EMU_DIR= + EMU_CPU= +endif + +ifeq ($(strip $(EMU_DIR)),) + $(error Unsupported or unset TARGET=$(TARGET). Use TARGET=stm32h563|stm32h5|stm32u585|stm32u5|stm32l552|stm32l5|nrf5340|mcxw) +endif + +EMU_PATH=$(WOLFBOOT_ROOT)/test-app/emu-test-apps/$(EMU_DIR) + +.PHONY: all clean test-emu sign-emu run-emu + +all: + $(MAKE) -C $(EMU_PATH) clean app.bin + +sign-emu: all $(WOLFBOOT_ROOT)/wolfboot_signing_private_key.der + @cp $(EMU_PATH)/app.bin $(EMU_PATH)/image.bin + $(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(EMU_PATH)/image.bin $(PRIVATE_KEY) $(EMU_VERSION) + +run-emu: sign-emu + @echo "[EMU] CPU=$(EMU_CPU) VERSION=$(EMU_VERSION)" + @$(M33MU) --cpu $(EMU_CPU) --uart-stdout --no-tz --boot-offset=$(IMAGE_HEADER_SIZE) \ + $(EMU_PATH)/image_v$(EMU_VERSION)_signed.bin --timeout 2 \ + | tee $(EMU_PATH)/emu_uart.log + @grep -q "get_version=$(EMU_EXPECT_VERSION)" $(EMU_PATH)/emu_uart.log + +# Entry point for top-level make test-emu +# Builds, signs, runs, and validates UART output. + +test-emu: run-emu + +clean: + $(MAKE) -C $(EMU_PATH) clean + @rm -f $(EMU_PATH)/image.bin $(EMU_PATH)/image_v*_signed.bin $(EMU_PATH)/emu_uart.log + +$(WOLFBOOT_ROOT)/wolfboot_signing_private_key.der: + $(MAKE) -C $(WOLFBOOT_ROOT) WOLFBOOT_LIB_WOLFSSL="$(WOLFBOOT_LIB_WOLFSSL)" wolfboot_signing_private_key.der diff --git a/test-app/emu-test-apps/common/emu_app.h b/test-app/emu-test-apps/common/emu_app.h new file mode 100644 index 0000000000..2e4841dcf1 --- /dev/null +++ b/test-app/emu-test-apps/common/emu_app.h @@ -0,0 +1,31 @@ +/* emu_app.h + * + * 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 + */ + +#ifndef EMU_APP_H +#define EMU_APP_H + +#include + +void emu_uart_init(void); +int emu_uart_read(uint8_t *c); +void emu_uart_write(uint8_t c); + +#endif /* EMU_APP_H */ diff --git a/test-app/emu-test-apps/common/emu_hal.c b/test-app/emu-test-apps/common/emu_hal.c new file mode 100644 index 0000000000..3db3149d8b --- /dev/null +++ b/test-app/emu-test-apps/common/emu_hal.c @@ -0,0 +1,136 @@ +/* emu_hal.c + * + * 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 +#include +#include "target.h" +#include "hal.h" + +#ifndef EMU_FLASH_SECTOR_SIZE +#define EMU_FLASH_SECTOR_SIZE WOLFBOOT_SECTOR_SIZE +#endif + +#if defined(EMU_STM32) +#define FLASH_BASE 0x40022000u +#define FLASH_NSKEYR (*(volatile uint32_t *)(FLASH_BASE + 0x004u)) +#define FLASH_NSCR (*(volatile uint32_t *)(FLASH_BASE + 0x028u)) +#define FLASH_KEY1 0x45670123u +#define FLASH_KEY2 0xCDEF89ABu +#define FLASH_CR_LOCK (1u << 0) +#define FLASH_CR_PG (1u << 1) +#define FLASH_CR_SER (1u << 2) +#define FLASH_CR_STRT (1u << 5) +#define FLASH_CR_SNB_SHIFT 6 +#define FLASH_CR_SNB_MASK (0x7fu << FLASH_CR_SNB_SHIFT) +#endif + +#if defined(EMU_NRF5340) +#define NVMC_BASE 0x40039000u +#define NVMC_CONFIG (*(volatile uint32_t *)(NVMC_BASE + 0x504u)) +#endif + +void hal_init(void) +{ +} + +void hal_prepare_boot(void) +{ +} + +int hal_flash_write(uint32_t address, const uint8_t *data, int len) +{ + if (data == 0 || len <= 0) { + return 0; + } + memcpy((void *)address, data, (size_t)len); + return 0; +} + +int hal_flash_erase(uint32_t address, int len) +{ +#if defined(EMU_NRF5340) + (void)address; + (void)len; + return 0; +#else + uint32_t end; +#if defined(EMU_STM32) + uint32_t base = WOLFBOOT_PARTITION_BOOT_ADDRESS; + uint32_t sector = EMU_FLASH_SECTOR_SIZE; + uint32_t start_sector; + uint32_t end_sector; + uint32_t snb; + static uint32_t last_erase_sector = 0xFFFFFFFFu; +#endif + if (len <= 0) { + return 0; + } +#if defined(EMU_STM32) + if (sector == 0u) { + return 0; + } + if (address < base) { + return 0; + } + end = address + (uint32_t)len; + start_sector = (address - base) / sector; + end_sector = ((end - 1u) - base) / sector; + for (snb = start_sector; snb <= end_sector; ++snb) { + if (snb == last_erase_sector) { + continue; + } + uint32_t cr = FLASH_NSCR & ~FLASH_CR_SNB_MASK; + cr |= FLASH_CR_SER | (snb << FLASH_CR_SNB_SHIFT); + FLASH_NSCR = cr; + FLASH_NSCR = cr | FLASH_CR_STRT; + last_erase_sector = snb; + } + FLASH_NSCR &= ~FLASH_CR_SER; +#else + end = address + (uint32_t)len; + memset((void *)address, 0xFF, (size_t)(end - address)); +#endif + return 0; +#endif +} + +void hal_flash_unlock(void) +{ +#if defined(EMU_STM32) + if ((FLASH_NSCR & FLASH_CR_LOCK) != 0u) { + FLASH_NSKEYR = FLASH_KEY1; + FLASH_NSKEYR = FLASH_KEY2; + } + FLASH_NSCR |= FLASH_CR_PG; +#elif defined(EMU_NRF5340) + NVMC_CONFIG = 1u; +#endif +} + +void hal_flash_lock(void) +{ +#if defined(EMU_STM32) + FLASH_NSCR &= ~FLASH_CR_PG; + FLASH_NSCR |= FLASH_CR_LOCK; +#elif defined(EMU_NRF5340) + NVMC_CONFIG = 0u; +#endif +} diff --git a/test-app/emu-test-apps/common/emu_ivt.c b/test-app/emu-test-apps/common/emu_ivt.c new file mode 100644 index 0000000000..dd26cd5678 --- /dev/null +++ b/test-app/emu-test-apps/common/emu_ivt.c @@ -0,0 +1,59 @@ +/* emu_ivt.c + * + * 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 + +extern void Reset_Handler(void); +extern unsigned long _estack; + +static void default_handler(void) +{ + while (1) { + } +} + +void NMI_Handler(void) __attribute__((weak, alias("default_handler"))); +void HardFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void MemManage_Handler(void) __attribute__((weak, alias("default_handler"))); +void BusFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void UsageFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void SVC_Handler(void) __attribute__((weak, alias("default_handler"))); +void DebugMon_Handler(void) __attribute__((weak, alias("default_handler"))); +void PendSV_Handler(void) __attribute__((weak, alias("default_handler"))); +void SysTick_Handler(void) __attribute__((weak, alias("default_handler"))); + +__attribute__((section(".isr_vector"))) +const uint32_t vector_table[16 + 48] = { + [0] = (uint32_t)&_estack, + [1] = (uint32_t)&Reset_Handler, + [2] = (uint32_t)&NMI_Handler, + [3] = (uint32_t)&HardFault_Handler, + [4] = (uint32_t)&MemManage_Handler, + [5] = (uint32_t)&BusFault_Handler, + [6] = (uint32_t)&UsageFault_Handler, + [7] = 0, [8] = 0, [9] = 0, [10] = 0, + [11] = (uint32_t)&SVC_Handler, + [12] = (uint32_t)&DebugMon_Handler, + [13] = 0, + [14] = (uint32_t)&PendSV_Handler, + [15] = (uint32_t)&SysTick_Handler, + [16 ... 63] = (uint32_t)&default_handler +}; diff --git a/test-app/emu-test-apps/common/emu_startup.c b/test-app/emu-test-apps/common/emu_startup.c new file mode 100644 index 0000000000..a244c1285a --- /dev/null +++ b/test-app/emu-test-apps/common/emu_startup.c @@ -0,0 +1,53 @@ +/* emu_startup.c + * + * 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 + +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; +extern void __libc_init_array(void); + +int main(void); + +void Reset_Handler(void) +{ + uint32_t *src; + uint32_t *dst; + + src = &_sidata; + for (dst = &_sdata; dst < &_edata; ) { + *dst++ = *src++; + } + + for (dst = &_sbss; dst < &_ebss; ) { + *dst++ = 0u; + } + + __libc_init_array(); + (void)main(); + + while (1) { + __asm volatile("wfi"); + } +} diff --git a/test-app/emu-test-apps/common/emu_syscalls.c b/test-app/emu-test-apps/common/emu_syscalls.c new file mode 100644 index 0000000000..33af31c776 --- /dev/null +++ b/test-app/emu-test-apps/common/emu_syscalls.c @@ -0,0 +1,148 @@ +/* emu_syscalls.c + * + * 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 +#include +#include +#include +#include +#include + +extern uint32_t _ebss; +extern uint32_t _estack; +extern volatile uint32_t systick_ms; +void emu_uart_putc(char c); + +static char *heap_end; + +int _write(int file, const char *ptr, int len) +{ + int i; + (void)file; + for (i = 0; i < len; ++i) { + emu_uart_putc(ptr[i]); + } + return len; +} + +int _close(int file) +{ + (void)file; + return -1; +} + +int _fstat(int file, struct stat *st) +{ + (void)file; + if (st == 0) { + errno = EINVAL; + return -1; + } + st->st_mode = S_IFCHR; + return 0; +} + +int _isatty(int file) +{ + (void)file; + return 1; +} + +int _lseek(int file, int ptr, int dir) +{ + (void)file; + (void)ptr; + (void)dir; + return 0; +} + +int _read(int file, char *ptr, int len) +{ + (void)file; + (void)ptr; + (void)len; + return 0; +} + +void *_sbrk(ptrdiff_t incr) +{ + char *prev; + if (heap_end == 0) { + heap_end = (char *)&_ebss; + } + prev = heap_end; + if ((heap_end + incr) >= (char *)&_estack) { + errno = ENOMEM; + return (void *)-1; + } + heap_end += incr; + return prev; +} + +int _gettimeofday(struct timeval *tv, void *tzvp) +{ + (void)tzvp; + if (tv == 0) { + errno = EINVAL; + return -1; + } + tv->tv_sec = (time_t)(systick_ms / 1000u); + tv->tv_usec = (suseconds_t)((systick_ms % 1000u) * 1000u); + return 0; +} + +time_t time(time_t *t) +{ + time_t now = (time_t)(systick_ms / 1000u); + if (t != 0) { + *t = now; + } + return now; +} + +void _exit(int status) +{ + (void)status; + while (1) { + __asm volatile("wfi"); + } +} + +int _kill(int pid, int sig) +{ + (void)pid; + (void)sig; + errno = EINVAL; + return -1; +} + +int _getpid(void) +{ + return 1; +} + +void _init(void) +{ +} + +void _fini(void) +{ +} diff --git a/test-app/emu-test-apps/common/emu_update.c b/test-app/emu-test-apps/common/emu_update.c new file mode 100644 index 0000000000..b342d77bdb --- /dev/null +++ b/test-app/emu-test-apps/common/emu_update.c @@ -0,0 +1,326 @@ +/* emu_update.c + * + * 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 +#include +#include +#include + +#include "emu_app.h" +#include "target.h" +#include "hal.h" +#include "wolfboot/wolfboot.h" + +#define MSGSIZE 16 +#define PAGESIZE 256 + +volatile uint32_t systick_ms = 0; + +static uint8_t page[PAGESIZE]; +static uint8_t msg[MSGSIZE]; + +static const uint8_t ERR = '!'; +static const uint8_t START = '*'; +static const uint8_t ACK = '#'; + +static uint32_t emu_im2n(uint32_t val) +{ +#ifdef BIG_ENDIAN_ORDER + val = (((val & 0x000000FFu) << 24) | + ((val & 0x0000FF00u) << 8) | + ((val & 0x00FF0000u) >> 8) | + ((val & 0xFF000000u) >> 24)); +#endif + return val; +} + +static uint8_t emu_read_u8(uintptr_t addr) +{ + uint8_t v; + __asm volatile("ldrb %0, [%1]" : "=r"(v) : "r"(addr) : "memory"); + return v; +} + +static uint32_t emu_read_u32(uintptr_t addr) +{ + uint32_t v; + __asm volatile("ldr %0, [%1]" : "=r"(v) : "r"(addr) : "memory"); + return v; +} + +static uint32_t emu_get_blob_version_addr(uintptr_t base) +{ + uintptr_t p = base + IMAGE_HEADER_OFFSET; + uintptr_t max_p = base + IMAGE_HEADER_SIZE; + uint32_t magic = emu_read_u32(base); + + if (magic != WOLFBOOT_MAGIC) { + return 0; + } + + while ((p + 4u) <= max_p) { + uint16_t htype = (uint16_t)(emu_read_u8(p) | (emu_read_u8(p + 1u) << 8)); + uint16_t len; + + if (htype == 0u) { + break; + } + if ((emu_read_u8(p) == HDR_PADDING) || ((p & 1u) != 0u)) { + p++; + continue; + } + + len = (uint16_t)(emu_read_u8(p + 2u) | (emu_read_u8(p + 3u) << 8)); + if ((4u + len) > (uint16_t)(IMAGE_HEADER_SIZE - IMAGE_HEADER_OFFSET)) { + break; + } + if (p + 4u + len > max_p) { + break; + } + + p += 4u; + if (htype == HDR_VERSION) { + return emu_im2n(emu_read_u32(p)); + } + p += len; + } + return 0; +} + +static uint32_t emu_current_version(void) +{ + uintptr_t addr = (uintptr_t)WOLFBOOT_PARTITION_BOOT_ADDRESS; + +#ifdef WOLFCRYPT_SECURE_MODE + return wolfBoot_nsc_current_firmware_version(); +#else + if (addr == 0u) { + return emu_get_blob_version_addr(0u); + } + return wolfBoot_get_blob_version((uint8_t *)addr); +#endif +} + +void emu_uart_putc(char c) +{ + emu_uart_write((uint8_t)c); +} + +static void uart_write_buf(const uint8_t *buf, uint32_t len) +{ + uint32_t i; + for (i = 0; i < len; ++i) { + emu_uart_write(buf[i]); + } +} + +static uint8_t uart_read_blocking(void) +{ + uint8_t c = 0; + while (!emu_uart_read(&c)) { + __asm volatile("nop"); + } + return c; +} + +static void ack(uint32_t off) +{ + uint8_t *bytes = (uint8_t *)&off; + uint32_t i; + emu_uart_write(ACK); + for (i = 0; i < 4; i++) { + emu_uart_write(bytes[i]); + } +} + +static int check(uint8_t *pkt, int size) +{ + int i; + uint16_t c = 0; + uint16_t c_rx = *((uint16_t *)(pkt + 2)); + uint16_t *p = (uint16_t *)(pkt + 4); + for (i = 0; i < ((size - 4) >> 1); i++) { + c += p[i]; + } + if (c == c_rx) { + return 0; + } + return -1; +} + +static void wait_for_update(uint32_t version) +{ + uint32_t tlen = 0; + uint32_t recv_seq = 0; + uint32_t r_total = 0; + uint32_t tot_len = 0; + uint32_t next_seq = 0; + uint8_t *v_array = (uint8_t *)&version; + int i; + + memset(page, 0xFF, PAGESIZE); + +#ifndef WOLFCRYPT_SECURE_MODE + hal_flash_unlock(); +#endif + + emu_uart_write(START); + for (i = 3; i >= 0; i--) { + emu_uart_write(v_array[i]); + } + + while (1) { + r_total = 0; + do { + while (r_total < 2) { + msg[r_total++] = uart_read_blocking(); + if ((r_total == 2) && ((msg[0] != 0xA5) || (msg[1] != 0x5A))) { + r_total = 0; + continue; + } + } + msg[r_total++] = uart_read_blocking(); + if ((tot_len == 0) && r_total == 2 + sizeof(uint32_t)) { + break; + } + if ((r_total > 8) && (tot_len <= ((r_total - 8) + next_seq))) { + break; + } + } while (r_total < MSGSIZE); + + if (tot_len == 0) { + tlen = msg[2] + (msg[3] << 8) + (msg[4] << 16) + (msg[5] << 24); + if (tlen > WOLFBOOT_PARTITION_SIZE - 8) { + emu_uart_write(ERR); + emu_uart_write(ERR); + emu_uart_write(ERR); + emu_uart_write(ERR); + emu_uart_write(START); + recv_seq = 0; + tot_len = 0; + continue; + } + tot_len = tlen; + ack(0); + continue; + } + + if (check(msg, r_total) < 0) { + ack(next_seq); + continue; + } + + recv_seq = msg[4] + (msg[5] << 8) + (msg[6] << 16) + (msg[7] << 24); + if (recv_seq == next_seq) { + int psize = r_total - 8; + int page_idx = (int)(recv_seq % PAGESIZE); + memcpy(&page[page_idx], msg + 8, psize); + page_idx += psize; + if ((page_idx == PAGESIZE) || (next_seq + (uint32_t)psize >= tot_len)) { + uint32_t dst = (WOLFBOOT_PARTITION_UPDATE_ADDRESS + recv_seq + (uint32_t)psize) - (uint32_t)page_idx; + uint32_t dst_off = (recv_seq + (uint32_t)psize) - (uint32_t)page_idx; +#ifdef WOLFCRYPT_SECURE_MODE + if ((dst_off % WOLFBOOT_SECTOR_SIZE) == 0u) { + wolfBoot_nsc_erase_update(dst_off, WOLFBOOT_SECTOR_SIZE); + } + wolfBoot_nsc_write_update(dst_off, page, PAGESIZE); +#else + if ((dst % WOLFBOOT_SECTOR_SIZE) == 0u) { + hal_flash_erase(dst, WOLFBOOT_SECTOR_SIZE); + } + hal_flash_write(dst, page, PAGESIZE); +#endif + memset(page, 0xFF, PAGESIZE); + } + next_seq += (uint32_t)psize; + } + ack(next_seq); + if (next_seq >= tot_len) { + uint32_t update_ver; +#ifdef WOLFCRYPT_SECURE_MODE + update_ver = wolfBoot_nsc_update_firmware_version(); +#else + update_ver = wolfBoot_get_blob_version((uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS); +#endif + if (update_ver == 7u) { + __asm volatile("bkpt #0x4D"); + break; + } +#ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_nsc_update_trigger(); +#else + wolfBoot_update_trigger(); +#endif + __asm volatile("bkpt #0x47"); + break; + } + } + +#ifndef WOLFCRYPT_SECURE_MODE + hal_flash_lock(); +#endif + + while (1) { + __asm volatile("wfi"); + } +} + +int main(void) +{ + uint32_t version; + + emu_uart_init(); + + version = emu_current_version(); + printf("get_version=%lu\n", (unsigned long)version); + + if (version == 4u) { +#ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_nsc_success(); +#else + wolfBoot_success(); +#endif + __asm volatile("bkpt #0x4A"); + while (1) { + __asm volatile("wfi"); + } + } + if (version == 3u) { + __asm volatile("bkpt #0x4B"); + while (1) { + __asm volatile("wfi"); + } + } + if (version == 8u) { +#ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_nsc_success(); +#else + wolfBoot_success(); +#endif + __asm volatile("bkpt #0x4E"); + while (1) { + __asm volatile("wfi"); + } + } + + wait_for_update(version); + return 0; +} diff --git a/test-app/emu-test-apps/mcxw71/Makefile b/test-app/emu-test-apps/mcxw71/Makefile new file mode 100644 index 0000000000..b2831f8018 --- /dev/null +++ b/test-app/emu-test-apps/mcxw71/Makefile @@ -0,0 +1,63 @@ +# 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 + +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +MCXW71_SDK ?= ../../../../MCXW71 +CFLAGS += -I. -I../common -I../../../include +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +CFLAGS += -DCPU_MCXW716CMFPA +CFLAGS += -I$(MCXW71_SDK)/devices/MCXW716C -I$(MCXW71_SDK)/devices/MCXW716C/periph2 +CFLAGS += -I$(MCXW71_SDK)/CMSIS/Core/Include +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/mcxw71/target.ld b/test-app/emu-test-apps/mcxw71/target.ld new file mode 100644 index 0000000000..57603086a1 --- /dev/null +++ b/test-app/emu-test-apps/mcxw71/target.ld @@ -0,0 +1,85 @@ +/* target.ld + * + * 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 + */ + +/* Minimal linker script for MCXW716C memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000100, LENGTH = 0x000FFF00 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0001C000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/mcxw71/target.ld.in b/test-app/emu-test-apps/mcxw71/target.ld.in new file mode 100644 index 0000000000..94ac011dad --- /dev/null +++ b/test-app/emu-test-apps/mcxw71/target.ld.in @@ -0,0 +1,85 @@ +/* target.ld.in + * + * 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 + */ + +/* Minimal linker script for MCXW716C memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x000FFF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x0001C000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/mcxw71/uart.c b/test-app/emu-test-apps/mcxw71/uart.c new file mode 100644 index 0000000000..d35129b7fa --- /dev/null +++ b/test-app/emu-test-apps/mcxw71/uart.c @@ -0,0 +1,67 @@ +/* uart.c + * + * 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 +#include "fsl_device_registers.h" +#include "emu_app.h" + +/* MRCC */ +#define MRCC_BASE 0x4001C000u +#define MRCC_LPUART0 0xE0u + +static inline void mrcc_enable(uint32_t off) +{ + volatile uint32_t *reg = (volatile uint32_t *)(MRCC_BASE + off); + *reg = (1u << 31) | (1u << 30) | 1u; +} + +/* LPUART0 */ +#define LPUART0_BASE 0x40038000u +#define LPUART_STAT(b) (*(volatile uint32_t *)((b) + 0x14u)) +#define LPUART_CTRL(b) (*(volatile uint32_t *)((b) + 0x18u)) +#define LPUART_DATA(b) (*(volatile uint32_t *)((b) + 0x1Cu)) + +#define LPUART_STAT_TDRE (1u << 23) +#define LPUART_STAT_RDRF (1u << 21) +#define LPUART_CTRL_RE (1u << 18) +#define LPUART_CTRL_TE (1u << 19) + +void emu_uart_init(void) +{ + mrcc_enable(MRCC_LPUART0); + LPUART_CTRL(LPUART0_BASE) = LPUART_CTRL_TE | LPUART_CTRL_RE; +} + +void emu_uart_write(uint8_t c) +{ + while ((LPUART_STAT(LPUART0_BASE) & LPUART_STAT_TDRE) == 0u) { + } + LPUART_DATA(LPUART0_BASE) = (uint32_t)c; +} + +int emu_uart_read(uint8_t *c) +{ + if ((LPUART_STAT(LPUART0_BASE) & LPUART_STAT_RDRF) == 0u) { + return 0; + } + *c = (uint8_t)LPUART_DATA(LPUART0_BASE); + return 1; +} diff --git a/test-app/emu-test-apps/nrf5340/Makefile b/test-app/emu-test-apps/nrf5340/Makefile new file mode 100644 index 0000000000..1b63dad3f3 --- /dev/null +++ b/test-app/emu-test-apps/nrf5340/Makefile @@ -0,0 +1,59 @@ +# 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 + +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +CFLAGS += -I. -I../common -I../../../include -DEMU_NRF5340 +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/nrf5340/target.ld b/test-app/emu-test-apps/nrf5340/target.ld new file mode 100644 index 0000000000..9c52db20ce --- /dev/null +++ b/test-app/emu-test-apps/nrf5340/target.ld @@ -0,0 +1,90 @@ +/* target.ld + * + * 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 + */ + +/* Minimal linker script for nRF5340 (application core) memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000100, LENGTH = 0x000FFF00 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00080000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM + + .testpage ORIGIN(FLASH) + LENGTH(FLASH) - 0x1000 : + { + KEEP(*(.testpage*)) + } > FLASH +} diff --git a/test-app/emu-test-apps/nrf5340/target.ld.in b/test-app/emu-test-apps/nrf5340/target.ld.in new file mode 100644 index 0000000000..465647c526 --- /dev/null +++ b/test-app/emu-test-apps/nrf5340/target.ld.in @@ -0,0 +1,90 @@ +/* target.ld.in + * + * 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 + */ + +/* Minimal linker script for nRF5340 (application core) memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x000FFF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x00080000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM + + .testpage ORIGIN(FLASH) + LENGTH(FLASH) - 0x1000 : + { + KEEP(*(.testpage*)) + } > FLASH +} diff --git a/test-app/emu-test-apps/nrf5340/uart.c b/test-app/emu-test-apps/nrf5340/uart.c new file mode 100644 index 0000000000..f3eda65df8 --- /dev/null +++ b/test-app/emu-test-apps/nrf5340/uart.c @@ -0,0 +1,84 @@ +/* uart.c + * + * 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 +#include "emu_app.h" + +#define UARTE0_BASE 0x40008000u +#define CLOCK_BASE 0x40005000u +#define CLOCK_TASKS_HFCLKSTART (*(volatile uint32_t *)((CLOCK_BASE) + 0x000u)) +#define UARTE_TASKS_STARTRX(b) (*(volatile uint32_t *)((b) + 0x000u)) +#define UARTE_TASKS_STOPRX(b) (*(volatile uint32_t *)((b) + 0x004u)) +#define UARTE_TASKS_STARTTX(b) (*(volatile uint32_t *)((b) + 0x008u)) +#define UARTE_EVENTS_ENDRX(b) (*(volatile uint32_t *)((b) + 0x110u)) +#define UARTE_EVENTS_ENDTX(b) (*(volatile uint32_t *)((b) + 0x120u)) +#define UARTE_ENABLE(b) (*(volatile uint32_t *)((b) + 0x500u)) +#define UARTE_PSEL_TXD(b) (*(volatile uint32_t *)((b) + 0x50Cu)) +#define UARTE_PSEL_RXD(b) (*(volatile uint32_t *)((b) + 0x514u)) +#define UARTE_BAUDRATE(b) (*(volatile uint32_t *)((b) + 0x524u)) +#define UARTE_RXD_PTR(b) (*(volatile uint32_t *)((b) + 0x534u)) +#define UARTE_RXD_MAXCNT(b) (*(volatile uint32_t *)((b) + 0x538u)) +#define UARTE_TXD_PTR(b) (*(volatile uint32_t *)((b) + 0x544u)) +#define UARTE_TXD_MAXCNT(b) (*(volatile uint32_t *)((b) + 0x548u)) + +static volatile uint8_t uart_tx_byte; +static volatile uint8_t uart_rx_byte; + +static void uarte0_start_rx(void) +{ + UARTE_RXD_PTR(UARTE0_BASE) = (uint32_t)&uart_rx_byte; + UARTE_RXD_MAXCNT(UARTE0_BASE) = 1u; + UARTE_EVENTS_ENDRX(UARTE0_BASE) = 0u; + UARTE_TASKS_STARTRX(UARTE0_BASE) = 1u; +} + +void emu_uart_init(void) +{ + CLOCK_TASKS_HFCLKSTART = 1u; + UARTE_ENABLE(UARTE0_BASE) = 0u; + UARTE_PSEL_TXD(UARTE0_BASE) = 0u; + UARTE_PSEL_RXD(UARTE0_BASE) = 0u; + UARTE_BAUDRATE(UARTE0_BASE) = 0x01D7E000u; /* 115200 */ + UARTE_ENABLE(UARTE0_BASE) = 8u; + uarte0_start_rx(); +} + +void emu_uart_write(uint8_t c) +{ + uart_tx_byte = c; + UARTE_TXD_PTR(UARTE0_BASE) = (uint32_t)&uart_tx_byte; + UARTE_TXD_MAXCNT(UARTE0_BASE) = 1u; + UARTE_EVENTS_ENDTX(UARTE0_BASE) = 0u; + UARTE_TASKS_STARTTX(UARTE0_BASE) = 1u; + while (UARTE_EVENTS_ENDTX(UARTE0_BASE) == 0u) { + } +} + +int emu_uart_read(uint8_t *c) +{ + if (UARTE_EVENTS_ENDRX(UARTE0_BASE) == 0u) { + return 0; + } + UARTE_EVENTS_ENDRX(UARTE0_BASE) = 0u; + *c = uart_rx_byte; + uarte0_start_rx(); + return 1; +} diff --git a/test-app/emu-test-apps/stm32h563/Makefile b/test-app/emu-test-apps/stm32h563/Makefile new file mode 100644 index 0000000000..d0e3234a96 --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/Makefile @@ -0,0 +1,59 @@ +# 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 + +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +CFLAGS += -I. -I../common -I../../../include -DEMU_STM32 +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/stm32h563/target.ld b/test-app/emu-test-apps/stm32h563/target.ld new file mode 100644 index 0000000000..5cf38c4669 --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/target.ld @@ -0,0 +1,83 @@ +/* target.ld + * + * 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 + */ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x8060400, LENGTH = 0x9fc00 + RAM (rwx) : ORIGIN = 0x20050000, LENGTH = 0x40000 +} + +SECTIONS +{ + .text : + { + _start_text = .; + . = ALIGN(8); + KEEP(*(.isr_vector)) + . = ALIGN(8); + *(.init) + *(.fini) + *(.text*) + *(.rodata*) + . = ALIGN(8); + _end_text = .; + } > FLASH + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(8); + KEEP(*(.ramcode)) + . = ALIGN(8); + _end_data = .; + } > RAM + + .bss : + { + _start_bss = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + _end_bss = .; + _end = .; + } > RAM +} + +PROVIDE(_start_heap = _end); +PROVIDE(_heap_size = 4K); +PROVIDE(_end_stack = ORIGIN(RAM) + LENGTH(RAM)); + +/* Emu app startup expects these symbols. */ +_estack = _end_stack; +_sidata = _stored_data; +_sdata = _start_data; +_edata = _end_data; +_sbss = _start_bss; +_ebss = _end_bss; diff --git a/test-app/emu-test-apps/stm32h563/target.ld.in b/test-app/emu-test-apps/stm32h563/target.ld.in new file mode 100644 index 0000000000..aa2ea51211 --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/target.ld.in @@ -0,0 +1,85 @@ +/* target.ld.in + * + * 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 + */ + +/* Minimal linker script for STM32H563 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x001FFF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x000A0000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32h563/target_v8.ld b/test-app/emu-test-apps/stm32h563/target_v8.ld new file mode 100644 index 0000000000..5760374f0b --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/target_v8.ld @@ -0,0 +1,85 @@ +/* target_v8.ld + * + * 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 + */ + +/* Minimal linker script for STM32H563 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x8060100, LENGTH = 0x001FFF00 + RAM (rwx) : ORIGIN = 0x8060100, LENGTH = 0x000A0000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32h563/uart.c b/test-app/emu-test-apps/stm32h563/uart.c new file mode 100644 index 0000000000..460c3ef225 --- /dev/null +++ b/test-app/emu-test-apps/stm32h563/uart.c @@ -0,0 +1,114 @@ +/* uart.c + * + * 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 +#include "emu_app.h" + +#define SYSCLK_HZ 64000000u + +/* RCC */ +#define RCC_BASE 0x44020C00u +#define RCC_AHB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x8Cu)) +#define RCC_APB1LENR (*(volatile uint32_t *)(RCC_BASE + 0x9Cu)) + +/* GPIOA/GPIOB/GPIOD */ +#define GPIOA_BASE 0x42020000u +#define GPIOB_BASE 0x42020400u +#define GPIOD_BASE 0x42020C00u +#define GPIO_MODER(x) (*(volatile uint32_t *)((x) + 0x00u)) +#define GPIO_OTYPER(x) (*(volatile uint32_t *)((x) + 0x04u)) +#define GPIO_OSPEEDR(x) (*(volatile uint32_t *)((x) + 0x08u)) +#define GPIO_PUPDR(x) (*(volatile uint32_t *)((x) + 0x0Cu)) +#define GPIO_AFRH(x) (*(volatile uint32_t *)((x) + 0x24u)) + +/* USART3 */ +#define USART3_BASE 0x40004800u +#define USART_CR1(b) (*(volatile uint32_t *)((b) + 0x00u)) +#define USART_CR2(b) (*(volatile uint32_t *)((b) + 0x04u)) +#define USART_CR3(b) (*(volatile uint32_t *)((b) + 0x08u)) +#define USART_BRR(b) (*(volatile uint32_t *)((b) + 0x0Cu)) +#define USART_ISR(b) (*(volatile uint32_t *)((b) + 0x1Cu)) +#define USART_RDR(b) (*(volatile uint32_t *)((b) + 0x24u)) +#define USART_TDR(b) (*(volatile uint32_t *)((b) + 0x28u)) + +static void gpio_config_usart3_pd8_pd9(void) +{ + uint32_t v; + RCC_AHB2ENR |= (1u << 3); + + v = GPIO_MODER(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_MODER(GPIOD_BASE) = v; + + v = GPIO_OTYPER(GPIOD_BASE); + v &= ~((1u << 8) | (1u << 9)); + GPIO_OTYPER(GPIOD_BASE) = v; + + v = GPIO_OSPEEDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_OSPEEDR(GPIOD_BASE) = v; + + v = GPIO_PUPDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (1u << (9u * 2u)); + GPIO_PUPDR(GPIOD_BASE) = v; + + v = GPIO_AFRH(GPIOD_BASE); + v &= ~((0xFu << ((8u - 8u) * 4u)) | (0xFu << ((9u - 8u) * 4u))); + v |= (7u << ((8u - 8u) * 4u)) | (7u << ((9u - 8u) * 4u)); + GPIO_AFRH(GPIOD_BASE) = v; +} + +static void usart3_init_115200(void) +{ + uint32_t brr; + RCC_APB1LENR |= (1u << 18); + USART_CR1(USART3_BASE) = 0; + USART_CR2(USART3_BASE) = 0; + USART_CR3(USART3_BASE) = 0; + brr = SYSCLK_HZ / 115200u; + USART_BRR(USART3_BASE) = brr; + USART_CR1(USART3_BASE) = (1u << 0) | (1u << 2) | (1u << 3); +} + +void emu_uart_init(void) +{ + gpio_config_usart3_pd8_pd9(); + usart3_init_115200(); +} + +void emu_uart_write(uint8_t c) +{ + while ((USART_ISR(USART3_BASE) & (1u << 7)) == 0u) { + } + USART_TDR(USART3_BASE) = (uint32_t)c; +} + +int emu_uart_read(uint8_t *c) +{ + if ((USART_ISR(USART3_BASE) & (1u << 5)) == 0u) { + return 0; + } + *c = (uint8_t)USART_RDR(USART3_BASE); + return 1; +} diff --git a/test-app/emu-test-apps/stm32l552/Makefile b/test-app/emu-test-apps/stm32l552/Makefile new file mode 100644 index 0000000000..5aec36d6ba --- /dev/null +++ b/test-app/emu-test-apps/stm32l552/Makefile @@ -0,0 +1,60 @@ +# 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 + +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +CFLAGS += -I. -I../common -I../../../include -DEMU_STM32 +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DNONSECURE_APP + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/stm32l552/target.ld b/test-app/emu-test-apps/stm32l552/target.ld new file mode 100644 index 0000000000..d23d777180 --- /dev/null +++ b/test-app/emu-test-apps/stm32l552/target.ld @@ -0,0 +1,82 @@ +/* target.ld + * + * 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 + */ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x8040400, LENGTH = 0x1f400 + RAM (rwx) : ORIGIN = 0x20020000, LENGTH = 0x20000 +} + +SECTIONS +{ + .text : + { + _start_text = .; + . = ALIGN(8); + KEEP(*(.isr_vector)) + . = ALIGN(8); + *(.init) + *(.fini) + *(.text*) + *(.rodata*) + . = ALIGN(8); + _end_text = .; + } > FLASH + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(8); + KEEP(*(.ramcode)) + . = ALIGN(8); + _end_data = .; + } > RAM + + .bss : + { + _start_bss = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + _end_bss = .; + _end = .; + } > RAM +} + +PROVIDE(_start_heap = _end); +PROVIDE(_end_stack = ORIGIN(RAM) + LENGTH(RAM)); + +/* Emu app startup expects these symbols. */ +_estack = _end_stack; +_sidata = _stored_data; +_sdata = _start_data; +_edata = _end_data; +_sbss = _start_bss; +_ebss = _end_bss; diff --git a/test-app/emu-test-apps/stm32l552/target.ld.in b/test-app/emu-test-apps/stm32l552/target.ld.in new file mode 100644 index 0000000000..68c3f6e1ce --- /dev/null +++ b/test-app/emu-test-apps/stm32l552/target.ld.in @@ -0,0 +1,85 @@ +/* target.ld.in + * + * 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 + */ + +/* Minimal linker script for STM32L552 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x0007FF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x00040000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32l552/uart.c b/test-app/emu-test-apps/stm32l552/uart.c new file mode 100644 index 0000000000..0eddec05d0 --- /dev/null +++ b/test-app/emu-test-apps/stm32l552/uart.c @@ -0,0 +1,114 @@ +/* uart.c + * + * 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 +#include "emu_app.h" + +#define SYSCLK_HZ 64000000u + +/* RCC */ +#define RCC_BASE 0x40021000u +#define RCC_AHB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x4Cu)) +#define RCC_APB1LENR (*(volatile uint32_t *)(RCC_BASE + 0x58u)) + +/* GPIOA/GPIOB/GPIOD */ +#define GPIOA_BASE 0x42020000u +#define GPIOB_BASE 0x42020400u +#define GPIOD_BASE 0x42020C00u +#define GPIO_MODER(x) (*(volatile uint32_t *)((x) + 0x00u)) +#define GPIO_OTYPER(x) (*(volatile uint32_t *)((x) + 0x04u)) +#define GPIO_OSPEEDR(x) (*(volatile uint32_t *)((x) + 0x08u)) +#define GPIO_PUPDR(x) (*(volatile uint32_t *)((x) + 0x0Cu)) +#define GPIO_AFRH(x) (*(volatile uint32_t *)((x) + 0x24u)) + +/* USART3 */ +#define USART3_BASE 0x40004800u +#define USART_CR1(b) (*(volatile uint32_t *)((b) + 0x00u)) +#define USART_CR2(b) (*(volatile uint32_t *)((b) + 0x04u)) +#define USART_CR3(b) (*(volatile uint32_t *)((b) + 0x08u)) +#define USART_BRR(b) (*(volatile uint32_t *)((b) + 0x0Cu)) +#define USART_ISR(b) (*(volatile uint32_t *)((b) + 0x1Cu)) +#define USART_RDR(b) (*(volatile uint32_t *)((b) + 0x24u)) +#define USART_TDR(b) (*(volatile uint32_t *)((b) + 0x28u)) + +static void gpio_config_usart3_pd8_pd9(void) +{ + uint32_t v; + RCC_AHB2ENR |= (1u << 3); + + v = GPIO_MODER(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_MODER(GPIOD_BASE) = v; + + v = GPIO_OTYPER(GPIOD_BASE); + v &= ~((1u << 8) | (1u << 9)); + GPIO_OTYPER(GPIOD_BASE) = v; + + v = GPIO_OSPEEDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_OSPEEDR(GPIOD_BASE) = v; + + v = GPIO_PUPDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (1u << (9u * 2u)); + GPIO_PUPDR(GPIOD_BASE) = v; + + v = GPIO_AFRH(GPIOD_BASE); + v &= ~((0xFu << ((8u - 8u) * 4u)) | (0xFu << ((9u - 8u) * 4u))); + v |= (7u << ((8u - 8u) * 4u)) | (7u << ((9u - 8u) * 4u)); + GPIO_AFRH(GPIOD_BASE) = v; +} + +static void usart3_init_115200(void) +{ + uint32_t brr; + RCC_APB1LENR |= (1u << 18); + USART_CR1(USART3_BASE) = 0; + USART_CR2(USART3_BASE) = 0; + USART_CR3(USART3_BASE) = 0; + brr = SYSCLK_HZ / 115200u; + USART_BRR(USART3_BASE) = brr; + USART_CR1(USART3_BASE) = (1u << 0) | (1u << 2) | (1u << 3); +} + +void emu_uart_init(void) +{ + gpio_config_usart3_pd8_pd9(); + usart3_init_115200(); +} + +void emu_uart_write(uint8_t c) +{ + while ((USART_ISR(USART3_BASE) & (1u << 7)) == 0u) { + } + USART_TDR(USART3_BASE) = (uint32_t)c; +} + +int emu_uart_read(uint8_t *c) +{ + if ((USART_ISR(USART3_BASE) & (1u << 5)) == 0u) { + return 0; + } + *c = (uint8_t)USART_RDR(USART3_BASE); + return 1; +} diff --git a/test-app/emu-test-apps/stm32u585/Makefile b/test-app/emu-test-apps/stm32u585/Makefile new file mode 100644 index 0000000000..5aec36d6ba --- /dev/null +++ b/test-app/emu-test-apps/stm32u585/Makefile @@ -0,0 +1,60 @@ +# 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 + +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +CFLAGS := -mcpu=cortex-m33 -mthumb -Os -ffreestanding -fdata-sections -ffunction-sections -g -ggdb +CFLAGS += -I. -I../common -I../../../include -DEMU_STM32 +CFLAGS += -DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections +LDLIBS := -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +NSC_OBJ := +ifeq ($(TZEN),1) + CFLAGS += -DNONSECURE_APP + CFLAGS += -DWOLFCRYPT_SECURE_MODE + NSC_OBJ := ../../../src/wc_secure_calls.o +endif + +VPATH := ../common + +COMMON_SRCS := emu_ivt.c emu_startup.c emu_syscalls.c emu_update.c emu_hal.c +LIBWOLFBOOT_SRC := ../../../src/libwolfboot.c +SRCS := $(COMMON_SRCS) uart.c +OBJS := $(SRCS:.c=.o) libwolfboot.o $(NSC_OBJ) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libwolfboot.o: $(LIBWOLFBOOT_SRC) + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(SRCS:.c=.o) libwolfboot.o app.elf app.bin + +.PHONY: all clean diff --git a/test-app/emu-test-apps/stm32u585/target.ld b/test-app/emu-test-apps/stm32u585/target.ld new file mode 100644 index 0000000000..5438ff062b --- /dev/null +++ b/test-app/emu-test-apps/stm32u585/target.ld @@ -0,0 +1,82 @@ +/* target.ld + * + * 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 + */ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x8040100, LENGTH = 0x1ff00 + RAM (rwx) : ORIGIN = 0x20020000, LENGTH = 128K +} + +SECTIONS +{ + .text : + { + _start_text = .; + . = ALIGN(8); + KEEP(*(.isr_vector)) + . = ALIGN(8); + *(.init) + *(.fini) + *(.text*) + *(.rodata*) + . = ALIGN(8); + _end_text = .; + } > FLASH + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(8); + KEEP(*(.ramcode)) + . = ALIGN(8); + _end_data = .; + } > RAM + + .bss : + { + _start_bss = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + _end_bss = .; + _end = .; + } > RAM +} + +PROVIDE(_start_heap = _end); +PROVIDE(_end_stack = ORIGIN(RAM) + LENGTH(RAM)); + +/* Emu app startup expects these symbols. */ +_estack = _end_stack; +_sidata = _stored_data; +_sdata = _start_data; +_edata = _end_data; +_sbss = _start_bss; +_ebss = _end_bss; diff --git a/test-app/emu-test-apps/stm32u585/target.ld.in b/test-app/emu-test-apps/stm32u585/target.ld.in new file mode 100644 index 0000000000..38688d984f --- /dev/null +++ b/test-app/emu-test-apps/stm32u585/target.ld.in @@ -0,0 +1,85 @@ +/* target.ld.in + * + * 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 + */ + +/* Minimal linker script for STM32U585 memory map */ +MEMORY +{ + FLASH (rx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x001FFF00 + RAM (rwx) : ORIGIN = @FLASH_ORIGIN@, LENGTH = 0x000C0000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +} diff --git a/test-app/emu-test-apps/stm32u585/uart.c b/test-app/emu-test-apps/stm32u585/uart.c new file mode 100644 index 0000000000..81558f6bd9 --- /dev/null +++ b/test-app/emu-test-apps/stm32u585/uart.c @@ -0,0 +1,114 @@ +/* uart.c + * + * 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 +#include "emu_app.h" + +#define SYSCLK_HZ 64000000u + +/* RCC */ +#define RCC_BASE 0x46020C00u +#define RCC_AHB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x8Cu)) +#define RCC_APB1LENR (*(volatile uint32_t *)(RCC_BASE + 0x9Cu)) + +/* GPIOA/GPIOB/GPIOD */ +#define GPIOA_BASE 0x42020000u +#define GPIOB_BASE 0x42020400u +#define GPIOD_BASE 0x42020C00u +#define GPIO_MODER(x) (*(volatile uint32_t *)((x) + 0x00u)) +#define GPIO_OTYPER(x) (*(volatile uint32_t *)((x) + 0x04u)) +#define GPIO_OSPEEDR(x) (*(volatile uint32_t *)((x) + 0x08u)) +#define GPIO_PUPDR(x) (*(volatile uint32_t *)((x) + 0x0Cu)) +#define GPIO_AFRH(x) (*(volatile uint32_t *)((x) + 0x24u)) + +/* USART3 */ +#define USART3_BASE 0x40004800u +#define USART_CR1(b) (*(volatile uint32_t *)((b) + 0x00u)) +#define USART_CR2(b) (*(volatile uint32_t *)((b) + 0x04u)) +#define USART_CR3(b) (*(volatile uint32_t *)((b) + 0x08u)) +#define USART_BRR(b) (*(volatile uint32_t *)((b) + 0x0Cu)) +#define USART_ISR(b) (*(volatile uint32_t *)((b) + 0x1Cu)) +#define USART_RDR(b) (*(volatile uint32_t *)((b) + 0x24u)) +#define USART_TDR(b) (*(volatile uint32_t *)((b) + 0x28u)) + +static void gpio_config_usart3_pd8_pd9(void) +{ + uint32_t v; + RCC_AHB2ENR |= (1u << 3); + + v = GPIO_MODER(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_MODER(GPIOD_BASE) = v; + + v = GPIO_OTYPER(GPIOD_BASE); + v &= ~((1u << 8) | (1u << 9)); + GPIO_OTYPER(GPIOD_BASE) = v; + + v = GPIO_OSPEEDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (2u << (8u * 2u)) | (2u << (9u * 2u)); + GPIO_OSPEEDR(GPIOD_BASE) = v; + + v = GPIO_PUPDR(GPIOD_BASE); + v &= ~((3u << (8u * 2u)) | (3u << (9u * 2u))); + v |= (1u << (9u * 2u)); + GPIO_PUPDR(GPIOD_BASE) = v; + + v = GPIO_AFRH(GPIOD_BASE); + v &= ~((0xFu << ((8u - 8u) * 4u)) | (0xFu << ((9u - 8u) * 4u))); + v |= (7u << ((8u - 8u) * 4u)) | (7u << ((9u - 8u) * 4u)); + GPIO_AFRH(GPIOD_BASE) = v; +} + +static void usart3_init_115200(void) +{ + uint32_t brr; + RCC_APB1LENR |= (1u << 18); + USART_CR1(USART3_BASE) = 0; + USART_CR2(USART3_BASE) = 0; + USART_CR3(USART3_BASE) = 0; + brr = SYSCLK_HZ / 115200u; + USART_BRR(USART3_BASE) = brr; + USART_CR1(USART3_BASE) = (1u << 0) | (1u << 2) | (1u << 3); +} + +void emu_uart_init(void) +{ + gpio_config_usart3_pd8_pd9(); + usart3_init_115200(); +} + +void emu_uart_write(uint8_t c) +{ + while ((USART_ISR(USART3_BASE) & (1u << 7)) == 0u) { + } + USART_TDR(USART3_BASE) = (uint32_t)c; +} + +int emu_uart_read(uint8_t *c) +{ + if ((USART_ISR(USART3_BASE) & (1u << 5)) == 0u) { + return 0; + } + *c = (uint8_t)USART_RDR(USART3_BASE); + return 1; +} diff --git a/test-app/emu-test-apps/test.sh b/test-app/emu-test-apps/test.sh new file mode 100755 index 0000000000..a6b5ec3a87 --- /dev/null +++ b/test-app/emu-test-apps/test.sh @@ -0,0 +1,546 @@ +#!/usr/bin/env bash + +# test.sh +# +# 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 + +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WOLFBOOT_ROOT="${WOLFBOOT_ROOT:-$(cd "$script_dir/../.." && pwd)}" +EMU_APPS="$WOLFBOOT_ROOT/test-app/emu-test-apps" +M33MU="${M33MU:-$(command -v m33mu || true)}" +UPDATE_SERVER_SRC="$WOLFBOOT_ROOT/tools/test-update-server/server.c" +BIN_ASSEMBLE="$WOLFBOOT_ROOT/tools/bin-assemble/bin-assemble" + +log() { + echo "==> $*" +} + +die() { + echo "error: $*" >&2 + exit 1 +} + +need_cmd() { + command -v "$1" >/dev/null 2>&1 || die "missing required command: $1" +} + +cfg_get() { + local key="$1" + local val + val="$(grep -m1 -E "^${key}[?]*[:]*=" "$WOLFBOOT_ROOT/.config" 2>/dev/null | sed -E "s/^${key}[?]*[:]*=//" || true)" + echo "${val}" +} + +if [[ -z "${TARGET:-}" && -f "$WOLFBOOT_ROOT/.config" ]]; then + TARGET="$(cfg_get TARGET)" +fi +TARGET="${TARGET:-}" +[[ -n "$TARGET" ]] || die "TARGET not set (export TARGET=... or set in .config)" + +EMU_DIR="" +UART_BASE="" + +get_m33mu_target() { + case "$1" in + stm32h563|stm32h5) echo "stm32h563" ;; + stm32u585|stm32u5) echo "stm32u585" ;; + stm32l552|stm32l5) echo "stm32l552" ;; + nrf5340) echo "nrf5340" ;; + mcxw|mcxw71) echo "mcxw71c" ;; + *) echo "" ;; + esac +} + +case "$TARGET" in + stm32h563|stm32h5) EMU_DIR=stm32h563; UART_BASE=40004800 ;; + stm32u585|stm32u5) EMU_DIR=stm32u585; UART_BASE=40004800 ;; + stm32l552|stm32l5) EMU_DIR=stm32l552; UART_BASE=40004800 ;; + nrf5340) EMU_DIR=nrf5340; UART_BASE=40008000 ;; + mcxw|mcxw71) EMU_DIR=mcxw71; UART_BASE=40038000 ;; + *) die "unsupported TARGET=$TARGET" ;; + esac + +EMU_CPU="$(get_m33mu_target "$TARGET")" +[[ -n "$EMU_CPU" ]] || die "unsupported TARGET=$TARGET (no m33mu mapping)" + +need_cmd "$M33MU" +need_cmd make +need_cmd grep +need_cmd python3 +need_cmd gcc +need_cmd sed +need_cmd cut +need_cmd tac + +IMAGE_HEADER_SIZE="$(cfg_get IMAGE_HEADER_SIZE)" +IMAGE_HEADER_SIZE="${IMAGE_HEADER_SIZE:-256}" +ARCH_OFFSET="$(cfg_get ARCH_OFFSET)" +ARCH_OFFSET="${ARCH_OFFSET:-0}" +BOOT_ADDR="$(cfg_get WOLFBOOT_PARTITION_BOOT_ADDRESS)" +UPDATE_ADDR="$(cfg_get WOLFBOOT_PARTITION_UPDATE_ADDRESS)" +PART_SIZE="$(cfg_get WOLFBOOT_PARTITION_SIZE)" +SECTOR_SIZE="$(cfg_get WOLFBOOT_SECTOR_SIZE)" +RAM_CODE="$(cfg_get RAM_CODE)" +TZEN="$(cfg_get TZEN)" + +[[ -n "$BOOT_ADDR" && -n "$UPDATE_ADDR" && -n "$PART_SIZE" && -n "$SECTOR_SIZE" ]] || \ + die "missing required config values (boot/update addr, partition/sector size)" + +# If ARCH_OFFSET is unset/0 but partitions are in 0x0800_0000 (STM32), use that +# as the base so bin-assemble offsets stay within the flash image. +if [[ "$ARCH_OFFSET" == "0" || "$ARCH_OFFSET" == "0x0" ]]; then + if (( BOOT_ADDR >= 0x08000000 )); then + ARCH_OFFSET=0x08000000 + fi +fi + +normalize_flash_addr() { + local addr="$1" + if [[ "$ARCH_OFFSET" == "0x08000000" ]]; then + if (( addr >= 0x0c000000 && addr < 0x10000000 )); then + addr=$((addr - 0x04000000)) + fi + fi + echo "$addr" +} + +BOOT_ADDR_NORM="$(normalize_flash_addr "$BOOT_ADDR")" +UPDATE_ADDR_NORM="$(normalize_flash_addr "$UPDATE_ADDR")" + +BOOT_OFFSET=$((BOOT_ADDR_NORM - ARCH_OFFSET)) +UPDATE_OFFSET=$((UPDATE_ADDR_NORM - ARCH_OFFSET)) +BOOT_OFFSET_HEX=$(printf "0x%x" "$BOOT_OFFSET") +UPDATE_OFFSET_HEX=$(printf "0x%x" "$UPDATE_OFFSET") + +get_check_config_val() { + local key="$1" + local val + make -C "$WOLFBOOT_ROOT/tools/check_config" check_config RAM_CODE=0 >/dev/null + val="$("$WOLFBOOT_ROOT/tools/check_config/check_config" | grep -m1 "^${key}" | sed 's/.*: *//')" + [[ -n "$val" ]] || die "missing ${key} from tools/check_config output" + echo "0x$val" +} + +BOOT_FLAGS_ADDR="$(get_check_config_val PART_BOOT_ENDFLAGS)" +UPDATE_FLAGS_ADDR="$(get_check_config_val PART_UPDATE_ENDFLAGS)" +BOOT_FLAGS_ADDR_NORM="$(normalize_flash_addr "$BOOT_FLAGS_ADDR")" +UPDATE_FLAGS_ADDR_NORM="$(normalize_flash_addr "$UPDATE_FLAGS_ADDR")" +BOOT_FLAGS_OFFSET=$((BOOT_FLAGS_ADDR_NORM - ARCH_OFFSET)) +UPDATE_FLAGS_OFFSET=$((UPDATE_FLAGS_ADDR_NORM - ARCH_OFFSET)) +BOOT_FLAGS_OFFSET_HEX=$(printf "0x%x" "$BOOT_FLAGS_OFFSET") +UPDATE_FLAGS_OFFSET_HEX=$(printf "0x%x" "$UPDATE_FLAGS_OFFSET") + +M33MU_TZ_ARGS=(--no-tz) +if [[ "${TZEN}" == "1" ]]; then + M33MU_TZ_ARGS=() +fi + +STDBUF="" +if command -v stdbuf >/dev/null 2>&1; then + STDBUF="stdbuf -o0 -e0" +fi + +SCENARIOS_RAW="${SCENARIOS:-}" +SCENARIOS_UP="$(echo "$SCENARIOS_RAW" | tr '[:lower:]' '[:upper:]' | tr -d ' ' | sed -e 's/,,*/,/g' -e 's/^,//' -e 's/,$//')" + +want_scenario() { + local s="$1" + if [[ -z "$SCENARIOS_UP" ]]; then + return 0 + fi + echo "$SCENARIOS_UP" | grep -Eq "(^|,)$s(,|$)" +} + +EMU_PATH="$EMU_APPS/$EMU_DIR" +WOLFBOOT_BIN="$WOLFBOOT_ROOT/wolfboot.bin" +FACTORY_FLASH="$EMU_PATH/factory.bin" +UPDATE_SERVER_BIN="$EMU_PATH/test-update-server" + +UPDATE_IMAGE_V1="$EMU_PATH/image_v1_signed.bin" +UPDATE_IMAGE_V3="$EMU_PATH/image_v3_signed.bin" +UPDATE_IMAGE_V4="$EMU_PATH/image_v4_signed.bin" +UPDATE_IMAGE_V7="$EMU_PATH/image_v7_signed.bin" +UPDATE_IMAGE_V8="$EMU_PATH/image_v8_signed.bin" + +BOOT_TIMEOUT="${BOOT_TIMEOUT:-10}" +UPDATE_TIMEOUT="${UPDATE_TIMEOUT:-10}" +REBOOT_TIMEOUT="${REBOOT_TIMEOUT:-10}" + +write_target_ld() { + local tpl="" + local base="" + local addr + local size + addr=$((BOOT_ADDR + IMAGE_HEADER_SIZE)) + size=$((PART_SIZE - IMAGE_HEADER_SIZE)) + + case "$TARGET" in + stm32h563|stm32h5) base="ARM-stm32h5" ;; + stm32u585|stm32u5) base="ARM-stm32u5" ;; + stm32l552|stm32l5) base="ARM-stm32l5" ;; + nrf5340) base="ARM-nrf5340" ;; + mcxw|mcxw71) base="ARM-mcxw" ;; + *) die "unsupported TARGET for linker template: $TARGET" ;; + esac + + if [[ "${TZEN}" == "1" && -f "$WOLFBOOT_ROOT/test-app/${base}-ns.ld" ]]; then + tpl="$WOLFBOOT_ROOT/test-app/${base}-ns.ld" + else + tpl="$WOLFBOOT_ROOT/test-app/${base}.ld" + fi + + [[ -f "$tpl" ]] || die "missing linker template: $tpl" + + sed -e "s/@WOLFBOOT_TEST_APP_ADDRESS@/0x$(printf '%x' "$addr")/g" \ + -e "s/@WOLFBOOT_TEST_APP_SIZE@/0x$(printf '%x' "$size")/g" \ + "$tpl" > "$EMU_PATH/target.ld" + cat <<'SYM' >> "$EMU_PATH/target.ld" + +/* Emu app startup expects these symbols. */ +_estack = _end_stack; +_sidata = _stored_data; +_sdata = _start_data; +_edata = _end_data; +_sbss = _start_bss; +_ebss = _end_bss; +SYM +} + +check_pty_available() { + python3 - <<'PY' +import pty, os +m, s = pty.openpty() +os.close(m) +os.close(s) +PY +} + +wait_for_pts() { + local log_file="$1" + local base="$2" + local pid="$3" + local pts="" + local i + for i in $(seq 1 2000); do + pts="$(grep "\\[UART\\] ${base} attached to" "$log_file" | tail -n1 | sed 's/.* //' || true)" + if [[ -n "$pts" ]]; then + echo "$pts" + return 0 + fi + kill -0 "$pid" >/dev/null 2>&1 || break + sleep 0.05 + done + return 1 +} + +build_update_server() { + local uart_dev="$1" + gcc -Wall -g -ggdb -DUART_DEV="\"$uart_dev\"" -o "$UPDATE_SERVER_BIN" \ + "$UPDATE_SERVER_SRC" -lpthread +} + +assemble_factory() { + log "Assembling factory.bin from wolfboot.bin + image_v1_signed.bin" + "$BIN_ASSEMBLE" "$FACTORY_FLASH" \ + 0 "$WOLFBOOT_BIN" \ + "$BOOT_OFFSET_HEX" "$UPDATE_IMAGE_V1" >/dev/null +} + +print_partition_flags() { + local label="$1" + python3 - "$FACTORY_FLASH" "$BOOT_FLAGS_OFFSET_HEX" "$UPDATE_FLAGS_OFFSET_HEX" "$SECTOR_SIZE" <<'PY' | sed "s/^/==> ${label}: /" +import sys +path, boot_s, update_s, sect_s = sys.argv[1:5] +boot = int(boot_s, 0) +update = int(update_s, 0) +sect = int(sect_s, 0) + +def decode(state): + if state is None: + return "MISSING" + if state == 0xFF: + return "NEW(0xFF)" + if state == 0x70: + return "UPDATING(0x70)" + if state == 0x10: + return "TESTING(0x10)" + if state == 0x00: + return "SUCCESS(0x00)" + return f"0x{state:02x}" + +def read_state(endflags): + try: + with open(path, "rb") as f: + f.seek(endflags - 4) + magic = f.read(4) + if magic != b"BOOT": + return None + f.seek(endflags - 5) + b = f.read(1) + if not b: + return None + return b[0] + except Exception: + return None + +def read_state_alt(endflags): + try: + with open(path, "rb") as f: + f.seek(endflags - sect - 4) + magic = f.read(4) + if magic != b"BOOT": + return None + f.seek(endflags - sect - 5) + b = f.read(1) + if not b: + return None + return b[0] + except Exception: + return None + +bs0 = read_state(boot) +bs1 = read_state_alt(boot) +us0 = read_state(update) +us1 = read_state_alt(update) +print(f"boot_flags=[S0:{decode(bs0)} S1:{decode(bs1)}] update_flags=[S0:{decode(us0)} S1:{decode(us1)}]") +PY +} + +print_partition_versions() { + local label="$1" + local boot_ver + local update_ver + boot_ver="$(python3 - "$FACTORY_FLASH" "$BOOT_OFFSET_HEX" "$IMAGE_HEADER_SIZE" <<'PY' +import sys, struct +path, off_s, hdr_s = sys.argv[1], sys.argv[2], sys.argv[3] +off = int(off_s, 16) +hdr = int(hdr_s, 0) +data = open(path, "rb").read() +if off + 8 > len(data): + print("NA") + sys.exit(0) +magic, = struct.unpack_from(" end: + break + if t == 1: + ver = struct.unpack_from(" len(data): + print("NA") + sys.exit(0) +magic, = struct.unpack_from(" end: + break + if t == 1: + ver = struct.unpack_from(""$update_log" + check_pty_available || die "no PTY devices available (needed for test-update-server)" + print_partition_flags "$label: flags before" + log "$label: start emulator (expect BKPT $expected_bkpt when update completes)" + $STDBUF "$M33MU" --cpu "$EMU_CPU" "${M33MU_TZ_ARGS[@]}" --persist \ + --timeout "$UPDATE_TIMEOUT" --expect-bkpt="$expected_bkpt" --quit-on-faults \ + "$FACTORY_FLASH" >"$update_log" 2>&1 & + emu_pid=$! + + pts="$(wait_for_pts "$update_log" "$UART_BASE" "$emu_pid")" || { + tail -n 60 "$update_log" | sed 's/^/ | /' + die "$label: failed to detect UART PTY" + } + log "$label: UART attached at $pts" + build_update_server "$pts" + + log "$label: transferring update image (v$expected_version) over UART" + $STDBUF "$UPDATE_SERVER_BIN" "$update_image" >"$server_log" 2>&1 & + server_pid=$! + + set +e + wait "$emu_pid" + emu_rc=$? + set -e + + kill "$server_pid" >/dev/null 2>&1 || true + wait "$server_pid" >/dev/null 2>&1 || true + + if ! grep -q "\\[EXPECT BKPT\\] Success" "$update_log"; then + tail -n 80 "$update_log" | sed 's/^/ | /' + die "$label: expected BKPT $expected_bkpt" + fi + + log "$label: BKPT $expected_bkpt hit" + print_partition_flags "$label: flags after" + + if [[ $emu_rc -ne 0 && $emu_rc -ne 127 ]]; then + die "$label: m33mu exited with $emu_rc" + fi +} + +log "Rebuilding wolfboot.bin (TZEN=${TZEN:-0})" +make -C "$WOLFBOOT_ROOT" clean wolfboot.bin + +log "Building emu-test-apps images" +write_target_ld +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=1 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=3 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=4 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=7 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu +make -C "$EMU_APPS" TARGET="$TARGET" TZEN="${TZEN:-0}" EMU_VERSION=8 IMAGE_HEADER_SIZE="$IMAGE_HEADER_SIZE" sign-emu + +if want_scenario "A"; then + assemble_factory + + log "Scenario A: factory boot" + print_partition_flags "Scenario A: flags before factory run" + log "factory run: boot image v1, expect UART get_version=1" + set +e + $STDBUF "$M33MU" --cpu "$EMU_CPU" --uart-stdout "${M33MU_TZ_ARGS[@]}" \ + --timeout "$BOOT_TIMEOUT" --quit-on-faults \ + "$FACTORY_FLASH" >"$EMU_PATH/factory.log" 2>&1 + factory_rc=$? + set -e + if ! grep -q "get_version=1" "$EMU_PATH/factory.log"; then + tail -n 80 "$EMU_PATH/factory.log" | sed 's/^/ | /' + die "factory run: expected get_version=1" + fi + if [[ $factory_rc -ne 0 && $factory_rc -ne 127 ]]; then + die "factory run: m33mu exited with $factory_rc" + fi + log "factory run: ok (version=1)" + + log "Scenario A: receive v7 update without trigger (expect BKPT 0x4D, stay on v1)" + assemble_factory + run_update_scenario "scenario_a_update_v7" "$UPDATE_IMAGE_V7" 7 0x4d + print_partition_versions "Scenario A: v7 update stored, version remains 1" +fi + +if want_scenario "B"; then + log "Scenario B: successful update from v1 to v4" + assemble_factory + print_partition_flags "Scenario B: flags before update" + run_update_scenario "scenario_b_update" "$UPDATE_IMAGE_V4" 4 0x47 + + for i in 1 2; do + run_log="$EMU_PATH/reboot_v4_${i}.log" + log "Scenario B: reboot run $i: boot updated image v4, expect BKPT 0x4A (success)" + $STDBUF "$M33MU" --cpu "$EMU_CPU" --uart-stdout "${M33MU_TZ_ARGS[@]}" \ + --timeout "$REBOOT_TIMEOUT" --expect-bkpt=0x4a --quit-on-faults \ + "$FACTORY_FLASH" >"$run_log" 2>&1 || die "reboot v4 run $i: m33mu failed" + grep -q "\\[EXPECT BKPT\\] Success" "$run_log" || die "reboot v4 run $i: expected BKPT 0x4A" + log "Scenario B: reboot run $i: BKPT 0x4A hit" + done +fi + +if want_scenario "C"; then + log "Scenario C: update from v1 to v3, then fallback (no wolfBoot_success is called)" + assemble_factory + print_partition_flags "Scenario C: flags before update" + run_update_scenario "scenario_c_update" "$UPDATE_IMAGE_V3" 3 0x47 + + log "Scenario C: first boot after update: reboot into v3 (expect BKPT 0x4B, no success call)" + run_log_v3="$EMU_PATH/reboot_v3.log" + print_partition_flags "Scenario C: flags before v3 reboot" + $STDBUF "$M33MU" --cpu "$EMU_CPU" --uart-stdout "${M33MU_TZ_ARGS[@]}" \ + --timeout "$REBOOT_TIMEOUT" --expect-bkpt=0x4b --persist --quit-on-faults \ + "$FACTORY_FLASH" >"$run_log_v3" 2>&1 || die "reboot v3 run: m33mu failed" + grep -q "\\[EXPECT BKPT\\] Success" "$run_log_v3" || die "reboot v3 run: expected BKPT 0x4B" + log "Scenario C: reboot v3: BKPT 0x4B hit" + print_partition_flags "Scenario C: flags after v3 reboot" + + log "Scenario C: second reboot, expect v1 after fallback" + run_log_fallback="$EMU_PATH/reboot_fallback_v1.log" + set +e + $STDBUF "$M33MU" --cpu "$EMU_CPU" --uart-stdout "${M33MU_TZ_ARGS[@]}" \ + --timeout "$UPDATE_TIMEOUT" --persist --quit-on-faults \ + "$FACTORY_FLASH" >"$run_log_fallback" 2>&1 + fallback_rc=$? + set -e + print_partition_flags "Scenario C: flags after fallback run" + print_partition_versions "Scenario C: versions after fallback run" + if ! grep -q "get_version=1" "$run_log_fallback"; then + tail -n 80 "$run_log_fallback" | sed 's/^/ | /' + die "fallback run: expected get_version=1" + fi + if [[ $fallback_rc -ne 0 && $fallback_rc -ne 127 ]]; then + die "fallback run: m33mu exited with $fallback_rc" + fi + log "Scenario C: fallback ok (version=1)" +fi + +if want_scenario "S"; then + if [[ "$RAM_CODE" == "1" ]]; then + log "Scenario S: self-update enabled (RAM_CODE=1)" + log "Scenario S: not enabled in this script yet" + else + log "Scenario S: RAM_CODE disabled, skipping" + fi +fi + +log "ok: $TARGET emu tests passed" diff --git a/tools/test-update-server/server.c b/tools/test-update-server/server.c index 15c2eb700b..0e8f85e0da 100644 --- a/tools/test-update-server/server.c +++ b/tools/test-update-server/server.c @@ -129,7 +129,15 @@ int main(int argc, char** argv) struct stat st; union usb_ack ack; struct termios tty; - sigset(SIGALRM, alarm_handler); + struct sigaction sa; + sigset_t mask; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = alarm_handler; + sigemptyset(&sa.sa_mask); + (void)sigaction(SIGALRM, &sa, NULL); + sigemptyset(&mask); + sigaddset(&mask, SIGALRM); + (void)sigprocmask(SIG_UNBLOCK, &mask, NULL); if (argc != 2) { printf("Usage: %s firmware_filename\n", argv[0]);