From e0eef372dbbb2b5e372bc98526e14749599a4515 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Thu, 26 Feb 2026 15:59:56 -0500 Subject: [PATCH 01/12] Initial support for lpc55s69 --- arch.mk | 36 +++++ config/examples/lpc55s69.config | 40 +++++ docs/Targets.md | 3 +- hal/lpc55s69-ns.ld | 55 +++++++ hal/lpc55s69.c | 258 ++++++++++++++++++++++++++++++++ test-app/ARM-lpc55s69.ld | 58 +++++++ test-app/Makefile | 21 +++ test-app/app_lpc55s69.c | 107 +++++++++++++ 8 files changed, 577 insertions(+), 1 deletion(-) create mode 100644 config/examples/lpc55s69.config create mode 100644 hal/lpc55s69-ns.ld create mode 100644 hal/lpc55s69.c create mode 100644 test-app/ARM-lpc55s69.ld create mode 100644 test-app/app_lpc55s69.c diff --git a/arch.mk b/arch.mk index 6f562b2286..5443f2551d 100644 --- a/arch.mk +++ b/arch.mk @@ -1112,6 +1112,42 @@ ifeq ($(TARGET),lpc) endif endif +ifeq ($(TARGET),lpc55s69) + ifneq ($(TZEN),1) + LSCRIPT_IN=hal/$(TARGET)-ns.ld + endif + CFLAGS+=\ + -I$(MCUXPRESSO_PROJECT_TEMPLATE) \ + -I$(MCUXPRESSO_DRIVERS) \ + -I$(MCUXPRESSO_DRIVERS)/drivers \ + -I$(MCUXPRESSO_DRIVERS)/../periph \ + -I$(MCUXPRESSO)/drivers \ + -I$(MCUXPRESSO)/drivers/common \ + -I$(MCUXPRESSO)/drivers/flexcomm \ + -I$(MCUXPRESSO)/drivers/flexcomm/usart \ + -I$(MCUXPRESSO)/drivers/iap1 \ + -I$(MCUXPRESSO)/drivers/lpc_gpio \ + -I$(MCUXPRESSO)/drivers/lpc_iocon \ + -I$(MCUXPRESSO_CMSIS)/Include \ + -I$(MCUXPRESSO_CMSIS)/Core/Include + CFLAGS+=-DCPU_$(MCUXPRESSO_CPU) + CFLAGS+=-mcpu=cortex-m33 -DCORTEX_M33 -U__ARM_FEATURE_DSP + LDFLAGS+=-mcpu=cortex-m33 + OBJS+=\ + $(MCUXPRESSO_PROJECT_TEMPLATE)/clock_config.o \ + $(MCUXPRESSO_DRIVERS)/drivers/fsl_clock.o \ + $(MCUXPRESSO_DRIVERS)/drivers/fsl_power.o \ + $(MCUXPRESSO)/drivers/common/fsl_common_arm.o \ + $(MCUXPRESSO)/drivers/iap1/fsl_iap.o \ + $(MCUXPRESSO)/drivers/lpc_gpio/fsl_gpio.o + ifeq ($(DEBUG_UART),1) + OBJS+=\ + $(MCUXPRESSO_DRIVERS)/drivers/fsl_reset.o \ + $(MCUXPRESSO)/drivers/flexcomm/fsl_flexcomm.o \ + $(MCUXPRESSO)/drivers/flexcomm/usart/fsl_usart.o + endif +endif + ifeq ($(TARGET),psoc6) CORTEX_M0=1 OBJS+=\ diff --git a/config/examples/lpc55s69.config b/config/examples/lpc55s69.config new file mode 100644 index 0000000000..391e7a548a --- /dev/null +++ b/config/examples/lpc55s69.config @@ -0,0 +1,40 @@ +ARCH?=ARM +TZEN?=0 +TARGET?=lpc55s69 +SIGN?=ECC384 +HASH?=SHA384 +MCUXSDK?=1 +MCUXPRESSO?=$(PWD)/../NXP/mcuxpresso-sdk/mcuxsdk +MCUXPRESSO_CMSIS?=$(PWD)/../NXP/CMSIS_5/CMSIS +MCUXPRESSO_CPU?=LPC55S69JBD100_cm33_core0 +MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/LPC/LPC5500/LPC55S69 +MCUXPRESSO_PROJECT_TEMPLATE?=$(MCUXPRESSO)/examples/_boards/lpcxpresso55s69/project_template +DEBUG?=0 +DEBUG_UART?=1 +VTOR?=1 +CORTEX_M0?=0 +CORTEX_M33?=1 +NO_ASM?=0 +NO_MPU=1 +EXT_FLASH?=0 +SPI_FLASH?=0 +ALLOW_DOWNGRADE?=0 +NVM_FLASH_WRITEONCE?=1 +NO_ARM_ASM=1 +WOLFBOOT_VERSION?=0 +V?=0 +SPMATH?=1 +RAM_CODE?=1 +DUALBANK_SWAP?=0 +PKA?=1 +FLASH_MULTI_SECTOR_ERASE?=1 + +# 512-byte pages erasable/writeable +WOLFBOOT_SECTOR_SIZE?=0x200 + +# Default configuration +# 32KB boot, 48KB partitions, 512 swap +WOLFBOOT_PARTITION_SIZE?=0xB000 +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xA000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x15000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x20000 diff --git a/docs/Targets.md b/docs/Targets.md index 2c07dcb1f4..016f33df2b 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -20,6 +20,7 @@ This README describes configuration of supported targets. * [NXP iMX-RT](#nxp-imx-rt) * [NXP Kinetis](#nxp-kinetis) * [NXP LPC54xxx](#nxp-lpc54xxx) +* [NXP LPC55S69](#lpc55s69) * [NXP LS1028A](#nxp-ls1028a) * [NXP MCXA153](#nxp-mcxa153) * [NXP MCXW716](#nxp-mcxw716) @@ -1743,7 +1744,7 @@ Example configurations for this target are provided in: 1. Download `aarch64-none-elf-` toolchain. -2. Copy the example `nxp-ls1028a.cofig` file to root directory and rename to `.config` +2. Copy the example `nxp-ls1028a.config` file to root directory and rename to `.config` 3. Build keytools and wolfboot diff --git a/hal/lpc55s69-ns.ld b/hal/lpc55s69-ns.ld new file mode 100644 index 0000000000..5e54a2e996 --- /dev/null +++ b/hal/lpc55s69-ns.ld @@ -0,0 +1,55 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = @WOLFBOOT_PARTITION_BOOT_ADDRESS@ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256K +} + +SECTIONS +{ + .text : + { + _start_text = .; + KEEP(*(.isr_vector)) + . = 0x200; + *(.keystore*) + *(.text*) + *(.rodata*) + *(.init*) + *(.fini*) + . = ALIGN(4); + _end_text = .; + } > FLASH + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + KEEP(*(.ramcode)) + . = ALIGN(4); + _end_data = .; + } > RAM + + .bss (NOLOAD) : + { + _start_bss = .; + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end_bss = .; + __bss_end__ = .; + _end = .; + } > RAM + . = ALIGN(4); +} + +END_STACK = ORIGIN(RAM) + LENGTH(RAM); diff --git a/hal/lpc55s69.c b/hal/lpc55s69.c new file mode 100644 index 0000000000..0937b22847 --- /dev/null +++ b/hal/lpc55s69.c @@ -0,0 +1,258 @@ +/* lpc55s69.c + * + * Copyright (C) 2025 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 "fsl_common.h" +#include "image.h" + +#include "clock_config.h" +#include "fsl_clock.h" +#include "fsl_iap.h" +#include "fsl_iocon.h" +#include "fsl_reset.h" +#include "fsl_usart.h" +#include "loader.h" + +#ifdef TZEN +#include "hal/armv8m_tz.h" +#endif + +static flash_config_t pflash; +static const uint32_t pflash_page_size = 512U; +uint32_t SystemCoreClock; /* set in clock_config.c */ + +#ifdef TZEN +static void hal_sau_init(void) +{ + /* Non-secure callable area */ + sau_init_region(0, WOLFBOOT_NSC_ADDRESS, + WOLFBOOT_NSC_ADDRESS + WOLFBOOT_NSC_SIZE - 1, 1); + + /* Non-secure: application flash area (boot partition) */ + sau_init_region(1, WOLFBOOT_PARTITION_BOOT_ADDRESS, + WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE - 1, + 0); + + /* Non-secure RAM */ + sau_init_region(2, 0x20020000, 0x20025FFF, 0); + + /* Peripherals */ + sau_init_region(3, 0x40000000, 0x4005FFFF, 0); + sau_init_region(4, 0x40080000, 0x400DFFFF, 0); + sau_init_region(5, 0x40100000, 0x4013FFFF, 0); + + /* Enable SAU */ + SAU_CTRL = SAU_INIT_CTRL_ENABLE; + + /* Enable securefault handler */ + SCB_SHCSR |= SCB_SHCSR_SECUREFAULT_EN; +} + +static void periph_unsecure(void) +{ + // CLOCK_EnableClock(kCLOCK_Gpio0); + // CLOCK_EnableClock(kCLOCK_Gpio1); + // CLOCK_EnableClock(kCLOCK_Port0); + // CLOCK_EnableClock(kCLOCK_Port1); + + // GPIO_EnablePinControlNonSecure(GPIO0, (1UL << 10) | (1UL << 27)); + // GPIO_EnablePinControlNonSecure(GPIO1, (1UL << 2) | (1UL << 8) | (1UL << 9)); +} +#endif + +void hal_init(void) +{ +#ifdef __WOLFBOOT + /* lpc55s69 must run < 100 MHz for flash write/erase to work */ + BOARD_BootClockFROHF96M(); +// BOARD_BootClockPLL150M(); +#ifdef DEBUG_UART + uart_init(); +#endif +#endif + + uart_write("lpc55s69 init\n", 14); + +#if defined(__WOLFBOOT) || !defined(TZEN) + memset(&pflash, 0, sizeof(pflash)); + FLASH_Init(&pflash); + // FLASH_GetProperty(&pflash, kFLASH_PropertyPflashSectorSize, + // &pflash_sector_size); +#endif + +#if defined(TZEN) && !defined(NONSECURE_APP) + hal_sau_init(); +#endif +} + +#ifdef __WOLFBOOT +/* Assert hook needed by SDK assert() macro. */ +void __assert_func(const char *a, int b, const char *c, const char *d) +{ + (void)a; + (void)b; + (void)c; + (void)d; + while (1) { + } +} + +void hal_prepare_boot(void) +{ +#ifdef TZEN + periph_unsecure(); +#endif +} +#endif + +int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) +{ + if ( + address % pflash_page_size == 0 && + len % pflash_page_size == 0 && + FLASH_Program(&pflash, address, data, len) == kStatus_FLASH_Success + ) + { + return 0; + } + + return -1; +} + +void RAMFUNCTION hal_flash_unlock(void) +{ +} + +void RAMFUNCTION hal_flash_lock(void) +{ +} + +int RAMFUNCTION hal_flash_erase(uint32_t address, int len) +{ + if ( + address % pflash_page_size == 0 && + len % pflash_page_size == 0 && + FLASH_Erase(&pflash, address, len, kFLASH_ApiEraseKey) + == kStatus_FLASH_Success && + FLASH_VerifyErase(&pflash, address, len) == kStatus_FLASH_Success + ) + { + return 0; + } + + return -1; +} + +#ifdef WOLFCRYPT_SECURE_MODE +/* These functions are stubs for now, because the MCUXpresso SDK doesn't + * implement drivers for the MCXN's TRNG. */ +void hal_trng_init(void) +{ +} + +void hal_trng_fini(void) +{ +} + +int hal_trng_get_entropy(unsigned char *out, unsigned int len) +{ + (void)out; + (void)len; + return -1; +} +#endif + + +#define IOCON_PIO_DIGITAL_EN 0x0100u /*!<@brief Enables digital function */ +#define IOCON_PIO_FUNC1 0x01u /*!<@brief Selects pin function 1 */ +#define IOCON_PIO_INV_DI 0x00u /*!<@brief Input function is not inverted */ +#define IOCON_PIO_MODE_INACT 0x00u /*!<@brief No addition pin function */ +#define IOCON_PIO_OPENDRAIN_DI 0x00u /*!<@brief Open drain is disabled */ +#define IOCON_PIO_SLEW_STANDARD 0x00u /*!<@brief Standard mode, output slew rate control is enabled */ + +void uart_init(void) +{ + CLOCK_EnableClock(kCLOCK_Iocon); + const uint32_t port0_pin29_config = (/* Pin is configured as FC0_RXD_SDA_MOSI_DATA */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT0 PIN29 (coords: 92) is configured as FC0_RXD_SDA_MOSI_DATA */ + IOCON_PinMuxSet(IOCON, 0U, 29U, port0_pin29_config); + const uint32_t port0_pin30_config = (/* Pin is configured as FC0_TXD_SCL_MISO_WS */ + IOCON_PIO_FUNC1 | + /* No addition pin function */ + IOCON_PIO_MODE_INACT | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + /* PORT0 PIN30 (coords: 94) is configured as FC0_TXD_SCL_MISO_WS */ + IOCON_PinMuxSet(IOCON, 0U, 30U, port0_pin30_config); + + /* attach 12 MHz clock to FLEXCOMM0 (debug console) */ + CLOCK_AttachClk(kFRO12M_to_FLEXCOMM0); + RESET_ClearPeripheralReset(kFC0_RST_SHIFT_RSTn); + + usart_config_t config; + USART_GetDefaultConfig(&config); + config.baudRate_Bps = 115200U; + config.enableTx = true; + config.enableRx = true; + (void)USART_Init(USART0, &config, 12000000U); +} + +void uart_write(const char *buf, unsigned int sz) +{ + const char *line; + unsigned int line_sz; + + while (sz > 0) + { + line = memchr(buf, '\n', sz); + if (line == NULL) { + (void)USART_WriteBlocking(USART0, (const uint8_t *)buf, sz); + break; + } + line_sz = (unsigned int)(line - buf); + if (line_sz > sz - 1U) { + line_sz = sz - 1U; + } + (void)USART_WriteBlocking(USART0, (const uint8_t *)buf, line_sz); + (void)USART_WriteBlocking(USART0, (const uint8_t *)"\r\n", 2U); + buf = line + 1; + sz -= line_sz + 1U; + } +} diff --git a/test-app/ARM-lpc55s69.ld b/test-app/ARM-lpc55s69.ld new file mode 100644 index 0000000000..f1b3872433 --- /dev/null +++ b/test-app/ARM-lpc55s69.ld @@ -0,0 +1,58 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = @WOLFBOOT_TEST_APP_ADDRESS@, LENGTH = @WOLFBOOT_TEST_APP_SIZE@ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256K +} + +SECTIONS +{ + .text : + { + _start_text = .; + KEEP(*(.isr_vector)) + *(.init) + *(.fini) + *(.text*) + KEEP(*(.rodata*)) + . = ALIGN(4); + _end_text = .; + } > FLASH + + .ARM : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + KEEP(*(.ramcode)) + . = ALIGN(4); + _end_data = .; + } > RAM + + .bss : + { + _start_bss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end_bss = .; + _end = .; + } > RAM +} + +_wolfboot_partition_boot_address = @WOLFBOOT_PARTITION_BOOT_ADDRESS@; +_wolfboot_partition_size = @WOLFBOOT_PARTITION_SIZE@; +_wolfboot_partition_update_address = @WOLFBOOT_PARTITION_UPDATE_ADDRESS@; +_wolfboot_partition_swap_address = @WOLFBOOT_PARTITION_SWAP_ADDRESS@; + +PROVIDE(_start_heap = _end); +PROVIDE(end = _end); +PROVIDE(_end_stack = ORIGIN(RAM) + LENGTH(RAM)); diff --git a/test-app/Makefile b/test-app/Makefile index f0f1bd0878..f8200b6e4b 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -475,6 +475,27 @@ ifeq ($(TARGET),mcxn) endif endif +ifeq ($(TARGET),lpc55s69) + ifeq ($(TZEN),1) + LSCRIPT_TEMPLATE=ARM-lpc55s69-ns.ld + CFLAGS:=$(filter-out -mcmse, $(CFLAGS)) + else + LSCRIPT_TEMPLATE=ARM-lpc55s69.ld + endif + APP_OBJS+=\ + $(MCUXPRESSO_PROJECT_TEMPLATE)/clock_config.o \ + $(MCUXPRESSO_DRIVERS)/drivers/fsl_clock.o \ + $(MCUXPRESSO_DRIVERS)/drivers/fsl_reset.o \ + $(MCUXPRESSO)/drivers/common/fsl_common_arm.o \ + $(MCUXPRESSO)/drivers/flexcomm/fsl_flexcomm.o \ + $(MCUXPRESSO)/drivers/flexcomm/usart/fsl_usart.o \ + $(MCUXPRESSO)/drivers/iap1/fsl_iap.o \ + $(MCUXPRESSO)/drivers/lpc_gpio/fsl_gpio.o + ifeq (,$(findstring nosys.specs,$(LDFLAGS))) + LDFLAGS+=--specs=nosys.specs + endif +endif + ifeq ($(TARGET),imx_rt) LDFLAGS+=\ -mcpu=cortex-m7 -Wall --specs=nosys.specs -fno-common -ffunction-sections -fdata-sections \ diff --git a/test-app/app_lpc55s69.c b/test-app/app_lpc55s69.c new file mode 100644 index 0000000000..0b6fae2ec7 --- /dev/null +++ b/test-app/app_lpc55s69.c @@ -0,0 +1,107 @@ +/* app_lpc55s69.c + * + * Copyright (C) 2025 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_clock.h" +#include "fsl_gpio.h" +#include "fsl_iocon.h" + +#include "target.h" +#include "wolfboot/wolfboot.h" +#include "printf.h" + +#define RED_LED 6 +#define GREEN_LED 7 +#define BLUE_LED 4 + +extern void hal_init(void); + +#define IOCON_PIO_FUNC0 0x00u /*!<@brief Selects pin function 0 */ +#define IOCON_PIO_MODE_PULLUP 0x20u /*!<@brief Selects pull-up function */ +#define IOCON_PIO_SLEW_STANDARD 0x00u /*!<@brief Standard mode, output slew rate control is enabled */ +#define IOCON_PIO_INV_DI 0x00u /*!<@brief Input function is not inverted */ +#define IOCON_PIO_DIGITAL_EN 0x0100u /*!<@brief Enables digital function */ +#define IOCON_PIO_OPENDRAIN_DI 0x00u /*!<@brief Open drain is disabled */ + +static void leds_init(void) +{ + CLOCK_EnableClock(kCLOCK_Iocon); + CLOCK_EnableClock(kCLOCK_Gpio1); + + const gpio_pin_config_t LED_GPIOPIN_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = 1U /* off */ + }; + GPIO_PinInit(GPIO, 1, 6, &LED_GPIOPIN_config); /* red off */ + GPIO_PinInit(GPIO, 1, 7, &LED_GPIOPIN_config); /* green off */ + GPIO_PinInit(GPIO, 1, 4, &LED_GPIOPIN_config); /* blue off */ + + const uint32_t LED_PINMUX_CONFIG = (/* Pin is configured as PIO */ + IOCON_PIO_FUNC0 | + /* Selects pull-up function */ + IOCON_PIO_MODE_PULLUP | + /* Standard mode, output slew rate control is enabled */ + IOCON_PIO_SLEW_STANDARD | + /* Input function is not inverted */ + IOCON_PIO_INV_DI | + /* Enables digital function */ + IOCON_PIO_DIGITAL_EN | + /* Open drain is disabled */ + IOCON_PIO_OPENDRAIN_DI); + IOCON_PinMuxSet(IOCON, 1, 6, LED_PINMUX_CONFIG); /* red */ + IOCON_PinMuxSet(IOCON, 1, 7, LED_PINMUX_CONFIG); /* green */ + IOCON_PinMuxSet(IOCON, 1, 4, LED_PINMUX_CONFIG); /* blue */ +} + +void main(void) +{ + uint32_t boot_ver; + + hal_init(); + leds_init(); + +#ifdef WOLFCRYPT_SECURE_MODE + boot_ver = wolfBoot_nsc_current_firmware_version(); +#else + boot_ver = wolfBoot_current_firmware_version(); +#endif + + wolfBoot_printf("Hello from firmware version %d\n", boot_ver); + + if (boot_ver == 1) { + /* blue on */ + GPIO_PinWrite(GPIO, 1, BLUE_LED, 0); + } + else { + /* green on */ + GPIO_PinWrite(GPIO, 1, GREEN_LED, 0); + +#ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_nsc_success(); +#else + wolfBoot_success(); +#endif + } + + while (1) { + __asm__ volatile ("wfi"); + } +} From d7c290ad3aaf524c6757723c4614f0ae2318fa7d Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Fri, 27 Feb 2026 01:29:51 -0500 Subject: [PATCH 02/12] Deploy NO_DIRECT_READ_OF_ERASED_SECTOR to protect against hardfault with AHB read of erased sector. --- config/examples/lpc55s69.config | 1 + hal/lpc55s69.c | 12 +++- include/hal.h | 3 + include/wolfboot/wolfboot.h | 2 +- options.mk | 4 ++ src/image.c | 13 +++- src/libwolfboot.c | 110 ++++++++++++++++++++++++++++---- src/update_flash.c | 7 +- test-app/app_lpc55s69.c | 2 +- 9 files changed, 133 insertions(+), 21 deletions(-) diff --git a/config/examples/lpc55s69.config b/config/examples/lpc55s69.config index 391e7a548a..2111f374b7 100644 --- a/config/examples/lpc55s69.config +++ b/config/examples/lpc55s69.config @@ -28,6 +28,7 @@ RAM_CODE?=1 DUALBANK_SWAP?=0 PKA?=1 FLASH_MULTI_SECTOR_ERASE?=1 +NO_DIRECT_READ_OF_ERASED_SECTOR?=1 # 512-byte pages erasable/writeable WOLFBOOT_SECTOR_SIZE?=0x200 diff --git a/hal/lpc55s69.c b/hal/lpc55s69.c index 0937b22847..d910cd517e 100644 --- a/hal/lpc55s69.c +++ b/hal/lpc55s69.c @@ -1,6 +1,6 @@ /* lpc55s69.c * - * Copyright (C) 2025 wolfSSL Inc. + * Copyright (C) 2026 wolfSSL Inc. * * This file is part of wolfBoot. * @@ -163,9 +163,15 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) return -1; } +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR +int RAMFUNCTION hal_flash_is_erased_at(uint32_t address) +{ + address &= ~(WOLFBOOT_SECTOR_SIZE - 1); + return FLASH_VerifyErase(&pflash, address, WOLFBOOT_SECTOR_SIZE) == kStatus_FLASH_Success; +} +#endif + #ifdef WOLFCRYPT_SECURE_MODE -/* These functions are stubs for now, because the MCUXpresso SDK doesn't - * implement drivers for the MCXN's TRNG. */ void hal_trng_init(void) { } diff --git a/include/hal.h b/include/hal.h index 893b23ef21..4ac8a15ec6 100644 --- a/include/hal.h +++ b/include/hal.h @@ -88,6 +88,9 @@ uint64_t hal_get_timer_us(void); void hal_flash_unlock(void); void hal_flash_lock(void); void hal_prepare_boot(void); +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + int hal_flash_is_erased_at(uint32_t address); +#endif #ifdef DUALBANK_SWAP void hal_flash_dualbank_swap(void); diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index f380835910..83067b2f2b 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -455,7 +455,7 @@ extern "C" { #define IMG_STATE_NEW 0x00 #define IMG_STATE_UPDATING 0x8F #define IMG_STATE_TESTING 0xEF -#define IMG_STATE_FINAL_FLAGS 0xBF +#define IMG_STATE_FINAL_FLAGS 0xCF #define IMG_STATE_SUCCESS 0xFF #define FLASH_BYTE_ERASED 0x00 #define FLASH_WORD_ERASED 0x00000000UL diff --git a/options.mk b/options.mk index 175206dba0..bd6c5f7c0b 100644 --- a/options.mk +++ b/options.mk @@ -670,6 +670,10 @@ ifeq ($(NVM_FLASH_WRITEONCE),1) CFLAGS+= -D"NVM_FLASH_WRITEONCE" endif +ifeq ($(NO_DIRECT_READ_OF_ERASED_SECTOR),1) + CFLAGS+= -D"NO_DIRECT_READ_OF_ERASED_SECTOR" +endif + ifeq ($(DISABLE_BACKUP),1) CFLAGS+= -D"DISABLE_BACKUP" endif diff --git a/src/image.c b/src/image.c index 7c11d06715..f49efb2fbb 100644 --- a/src/image.c +++ b/src/image.c @@ -1277,10 +1277,17 @@ uint32_t wolfBoot_image_size(uint8_t *image) */ int wolfBoot_open_image_address(struct wolfBoot_image *img, uint8_t *image) { - uint32_t *magic = (uint32_t *)(image); - if (*magic != WOLFBOOT_MAGIC) { + uint32_t *pmagic = (uint32_t *)(image); + uint32_t magic = FLASH_WORD_ERASED; + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + hal_flash_is_erased_at((uintptr_t)pmagic) || +#endif + (magic = *pmagic) != WOLFBOOT_MAGIC + ) + { wolfBoot_printf("Partition %d header magic 0x%08x invalid at %p\n", - img->part, (unsigned int)*magic, img->hdr); + img->part, (unsigned int)magic, img->hdr); return -1; } img->fw_size = wolfBoot_image_size(image); diff --git a/src/libwolfboot.c b/src/libwolfboot.c index 3bfee3476b..471f4aa5a1 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -228,6 +228,7 @@ static int RAMFUNCTION nvm_select_fresh_sector(int part) uint8_t* addrErase = 0; uint32_t word_0; uint32_t word_1; + uint32_t *ptr_word_0, *ptr_word_1; #if defined(EXT_FLASH) && !defined(FLAGS_HOME) if ((part == PART_UPDATE) && FLAGS_UPDATE_EXT()) { @@ -254,8 +255,28 @@ static int RAMFUNCTION nvm_select_fresh_sector(int part) } /* check magic in case the sector is corrupt */ - word_0 = *((uint32_t*)((uintptr_t)base - sizeof(uint32_t))); - word_1 = *((uint32_t*)((uintptr_t)base - (WOLFBOOT_SECTOR_SIZE + sizeof(uint32_t)))); + ptr_word_0 = (uint32_t*)((uintptr_t)base - sizeof(uint32_t)); + ptr_word_1 = (uint32_t*)((uintptr_t)base - (WOLFBOOT_SECTOR_SIZE + sizeof(uint32_t))); +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + if (hal_flash_is_erased_at((uintptr_t)ptr_word_0)) + { + word_0 = FLASH_WORD_ERASED; + } + else +#endif + { + word_0 = *ptr_word_0; + } +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + if (hal_flash_is_erased_at((uintptr_t)ptr_word_1)) + { + word_1 = FLASH_WORD_ERASED; + } + else +#endif + { + word_1 = *ptr_word_1; + } if (word_0 == WOLFBOOT_MAGIC_TRAIL && word_1 != WOLFBOOT_MAGIC_TRAIL) { sel = 0; @@ -301,8 +322,15 @@ static int RAMFUNCTION nvm_select_fresh_sector(int part) finish: /* Erase the non-selected partition, requires unlocked flash */ addrErase -= WOLFBOOT_SECTOR_SIZE * (!sel); - if (*((uint32_t*)(addrErase + WOLFBOOT_SECTOR_SIZE - sizeof(uint32_t))) - != FLASH_WORD_ERASED) { + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + ! hal_flash_is_erased_at((uintptr_t)addrErase) +#else + *((uint32_t*)(addrErase + WOLFBOOT_SECTOR_SIZE - sizeof(uint32_t))) + != FLASH_WORD_ERASED +#endif + ) + { hal_flash_erase((uintptr_t)addrErase, WOLFBOOT_SECTOR_SIZE); } return sel; @@ -624,11 +652,20 @@ int RAMFUNCTION wolfBoot_set_partition_state(uint8_t part, uint8_t newst) if (part == PART_NONE) return -1; magic = get_partition_magic(part); - if (*magic != WOLFBOOT_MAGIC_TRAIL) + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + hal_flash_is_erased_at((uintptr_t)magic) || +#endif + *magic != WOLFBOOT_MAGIC_TRAIL + ) + { set_partition_magic(part); + } state = get_partition_state(part); if (*state != newst) + { set_partition_state(part, newst); + } return 0; } @@ -650,8 +687,15 @@ int RAMFUNCTION wolfBoot_set_update_sector_flag(uint16_t sector, uint8_t pos = sector >> 1; magic = get_partition_magic(PART_UPDATE); - if (*magic != wolfboot_magic_trail) + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + hal_flash_is_erased_at((uintptr_t)magic) || +#endif + *magic != wolfboot_magic_trail + ) + { set_partition_magic(PART_UPDATE); + } flags = get_update_sector_flags(pos); if (sector == (pos << 1)) @@ -679,8 +723,15 @@ int RAMFUNCTION wolfBoot_get_partition_state(uint8_t part, uint8_t *st) if (part == PART_NONE) return -1; magic = get_partition_magic(part); - if (*magic != WOLFBOOT_MAGIC_TRAIL) + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + hal_flash_is_erased_at((uintptr_t)magic) || +#endif + *magic != WOLFBOOT_MAGIC_TRAIL + ) + { return -1; + } state = get_partition_state(part); *st = *state; return 0; @@ -704,8 +755,15 @@ int wolfBoot_get_update_sector_flag(uint16_t sector, uint8_t *flag) uint8_t *flags; uint8_t pos = sector >> 1; magic = get_partition_magic(PART_UPDATE); - if (*magic != WOLFBOOT_MAGIC_TRAIL) + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + hal_flash_is_erased_at((uintptr_t)magic) || +#endif + *magic != WOLFBOOT_MAGIC_TRAIL + ) + { return -1; + } flags = get_update_sector_flags(pos); if (sector == (pos << 1)) *flag = *flags & 0x0F; @@ -984,8 +1042,15 @@ int wolfBoot_get_delta_info(uint8_t part, int inverse, uint32_t **img_offset, /* Don't check image against NULL to allow using address 0x00000000 */ magic = (uint32_t *)image; - if (*magic != WOLFBOOT_MAGIC) + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + hal_flash_is_erased_at((uintptr_t)magic) || +#endif + *magic != WOLFBOOT_MAGIC + ) + { return -1; + } if (inverse) { if (wolfBoot_find_header((uint8_t *)(image + IMAGE_HEADER_OFFSET), HDR_IMG_DELTA_INVERSE, (uint8_t **)img_offset) @@ -1058,8 +1123,15 @@ uint32_t wolfBoot_get_blob_version(uint8_t *blob) img_bin = dec_hdr; #endif magic = (uint32_t *)img_bin; - if (*magic != WOLFBOOT_MAGIC) + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + hal_flash_is_erased_at((uintptr_t)magic) || +#endif + *magic != WOLFBOOT_MAGIC + ) + { return 0; + } if (wolfBoot_find_header(img_bin + IMAGE_HEADER_OFFSET, HDR_VERSION, (void *)&version_field) == 0) return 0; @@ -1091,8 +1163,15 @@ uint16_t wolfBoot_get_blob_type(uint8_t *blob) img_bin = dec_hdr; #endif magic = (uint32_t *)img_bin; - if (*magic != WOLFBOOT_MAGIC) + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + hal_flash_is_erased_at((uintptr_t)magic) || +#endif + *magic != WOLFBOOT_MAGIC + ) + { return 0; + } if (wolfBoot_find_header(img_bin + IMAGE_HEADER_OFFSET, HDR_IMG_TYPE, (void *)&type_field) == 0) return 0; @@ -1128,8 +1207,15 @@ uint32_t wolfBoot_get_blob_diffbase_version(uint8_t *blob) img_bin = dec_hdr; #endif magic = (uint32_t *)img_bin; - if (*magic != WOLFBOOT_MAGIC) + if ( +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + hal_flash_is_erased_at((uintptr_t)magic) || +#endif + *magic != WOLFBOOT_MAGIC + ) + { return 0; + } if (wolfBoot_find_header(img_bin + IMAGE_HEADER_OFFSET, HDR_IMG_DELTA_BASE, (void *)&delta_base) == 0) return 0; diff --git a/src/update_flash.c b/src/update_flash.c index b2213d076f..e7fab39cc1 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -336,7 +336,12 @@ static int RAMFUNCTION wolfBoot_swap_and_final_erase(int resume) ext_flash_read((uintptr_t)(boot->hdr + tmpBootPos), (void*)tmpBuffer, sizeof(tmpBuffer)); #else - memcpy(tmpBuffer, boot->hdr + tmpBootPos, sizeof(tmpBuffer)); +# ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + if (hal_flash_is_erased_at((uintptr_t)(boot->hdr + tmpBootPos))) + memset(tmpBuffer, 0xFF, sizeof(tmpBuffer)); + else +# endif + memcpy(tmpBuffer, boot->hdr + tmpBootPos, sizeof(tmpBuffer)); #endif /* Check if the magic trailer exists - indicates an interrupted swap diff --git a/test-app/app_lpc55s69.c b/test-app/app_lpc55s69.c index 0b6fae2ec7..3ddb8e5911 100644 --- a/test-app/app_lpc55s69.c +++ b/test-app/app_lpc55s69.c @@ -1,6 +1,6 @@ /* app_lpc55s69.c * - * Copyright (C) 2025 wolfSSL Inc. + * Copyright (C) 2026 wolfSSL Inc. * * This file is part of wolfBoot. * From 947e483ebba08cb270d80edfe8e7b9c4d9f67366 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Sun, 1 Mar 2026 19:30:36 -0500 Subject: [PATCH 03/12] Eliminate linker warnings for syscalls --- test-app/app_lpc55s69.c | 62 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/test-app/app_lpc55s69.c b/test-app/app_lpc55s69.c index 3ddb8e5911..4b7a4ca0e1 100644 --- a/test-app/app_lpc55s69.c +++ b/test-app/app_lpc55s69.c @@ -105,3 +105,65 @@ void main(void) __asm__ volatile ("wfi"); } } + + +#include "sys/stat.h" +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + (void)pid; + (void)sig; + return -1; +} + +void _exit(int status) +{ + _kill(status, -1); + while (1) {} +} + +int _read(int file, char *ptr, int len) +{ + (void)file; + (void)ptr; + (void)len; + return -1; +} + +int _write(int file, char *ptr, int len) +{ + (void)file; + (void)ptr; + return len; +} + +int _close(int file) +{ + (void)file; + return -1; +} + +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 _fstat(int file, struct stat *st) +{ + (void)file; + st->st_mode = S_IFCHR; + return 0; +} From 2cc62ea4c27598f1543a4e640e4a818ccfd99d42 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Sun, 1 Mar 2026 19:31:57 -0500 Subject: [PATCH 04/12] Add an update test to the test-app. Fix bugs found from the update test. --- src/libwolfboot.c | 28 +++++++++++++++++++++------- test-app/app_lpc55s69.c | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/libwolfboot.c b/src/libwolfboot.c index 6eef27c355..80b7c49f1f 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -355,7 +355,12 @@ static int RAMFUNCTION trailer_write(uint8_t part, uintptr_t addr, uint8_t val) nvm_cached_sector = nvm_select_fresh_sector(part); addr_read = addr_align - (nvm_cached_sector * NVM_CACHE_SIZE); - XMEMCPY(NVM_CACHE, (void*)addr_read, NVM_CACHE_SIZE); +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + if (hal_flash_is_erased_at((uintptr_t)addr_read)) + XMEMSET(NVM_CACHE, 0xFF, NVM_CACHE_SIZE); + else +#endif + XMEMCPY(NVM_CACHE, (void*)addr_read, NVM_CACHE_SIZE); NVM_CACHE[addr_off] = val; /* Calculate write address */ @@ -399,7 +404,12 @@ static int RAMFUNCTION partition_magic_write(uint8_t part, uintptr_t addr) nvm_cached_sector = nvm_select_fresh_sector(part); addr_read = base - (nvm_cached_sector * NVM_CACHE_SIZE); addr_write = base - (!nvm_cached_sector * NVM_CACHE_SIZE); - XMEMCPY(NVM_CACHE, (void*)addr_read, NVM_CACHE_SIZE); +#ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + if (hal_flash_is_erased_at((uintptr_t)addr_read)) + XMEMSET(NVM_CACHE, 0xFF, NVM_CACHE_SIZE); + else +#endif + XMEMCPY(NVM_CACHE, (void*)addr_read, NVM_CACHE_SIZE); XMEMCPY(NVM_CACHE + off, &wolfboot_magic_trail, sizeof(uint32_t)); ret = hal_flash_write(addr_write, NVM_CACHE, WOLFBOOT_SECTOR_SIZE); nvm_cached_sector = !nvm_cached_sector; @@ -850,12 +860,17 @@ void RAMFUNCTION wolfBoot_update_trigger(void) #else uint32_t magic = WOLFBOOT_MAGIC_TRAIL; uint32_t offset = SECTOR_FLAGS_SIZE; -#ifdef FLAGS_HOME +# ifdef FLAGS_HOME offset -= (PART_BOOT_ENDFLAGS - PART_UPDATE_ENDFLAGS); -#endif +# endif selSec = nvm_select_fresh_sector(PART_UPDATE); - XMEMCPY(NVM_CACHE, (uint8_t*)lastSector - WOLFBOOT_SECTOR_SIZE * selSec, - WOLFBOOT_SECTOR_SIZE); +# ifdef NO_DIRECT_READ_OF_ERASED_SECTOR + if (hal_flash_is_erased_at((uintptr_t)lastSector - WOLFBOOT_SECTOR_SIZE * selSec)) + XMEMSET(NVM_CACHE, 0xFF, WOLFBOOT_SECTOR_SIZE); + else +# endif + XMEMCPY(NVM_CACHE, (uint8_t*)lastSector - WOLFBOOT_SECTOR_SIZE * selSec, + WOLFBOOT_SECTOR_SIZE); /* write to the non selected sector */ hal_flash_erase(lastSector - WOLFBOOT_SECTOR_SIZE * !selSec, WOLFBOOT_SECTOR_SIZE); @@ -870,7 +885,6 @@ void RAMFUNCTION wolfBoot_update_trigger(void) #endif } - if (FLAGS_UPDATE_EXT()) { ext_flash_lock(); } else { diff --git a/test-app/app_lpc55s69.c b/test-app/app_lpc55s69.c index 4b7a4ca0e1..c12a688252 100644 --- a/test-app/app_lpc55s69.c +++ b/test-app/app_lpc55s69.c @@ -87,8 +87,27 @@ void main(void) wolfBoot_printf("Hello from firmware version %d\n", boot_ver); if (boot_ver == 1) { + uint32_t update_ver; + /* blue on */ GPIO_PinWrite(GPIO, 1, BLUE_LED, 0); + +#ifdef WOLFCRYPT_SECURE_MODE + update_ver = wolfBoot_nsc_update_firmware_version(); +#else + update_ver = wolfBoot_update_firmware_version(); +#endif + + if (update_ver != 0) { + wolfBoot_printf("Update firmware detected, version: 0x%lx\n", update_ver); + wolfBoot_printf("Triggering update...\n"); +#ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_nsc_update_trigger(); +#else + wolfBoot_update_trigger(); +#endif + wolfBoot_printf("...done. Reboot to apply.\n"); + } } else { /* green on */ From 4cd2180c7deeed8519765642e8f51bd719ea1239 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Wed, 4 Mar 2026 12:01:06 -0500 Subject: [PATCH 05/12] Add trustzone example, rework a few things for tz support. --- config/examples/lpc55s69-tz.config | 46 +++++++++++++++ config/examples/lpc55s69.config | 2 +- hal/lpc55s69-ns.ld | 4 +- hal/lpc55s69.c | 26 +++------ hal/lpc55s69.ld | 75 +++++++++++++++++++++++++ test-app/ARM-lpc55s69-ns.ld | 58 +++++++++++++++++++ test-app/ARM-lpc55s69.ld | 2 +- test-app/app_lpc55s69.c | 90 ++++++++++++++++++++---------- 8 files changed, 251 insertions(+), 52 deletions(-) create mode 100644 config/examples/lpc55s69-tz.config create mode 100644 hal/lpc55s69.ld create mode 100644 test-app/ARM-lpc55s69-ns.ld diff --git a/config/examples/lpc55s69-tz.config b/config/examples/lpc55s69-tz.config new file mode 100644 index 0000000000..ad0b5f107b --- /dev/null +++ b/config/examples/lpc55s69-tz.config @@ -0,0 +1,46 @@ +ARCH?=ARM +TZEN?=1 +TARGET?=lpc55s69 +SIGN?=ECC384 +HASH?=SHA384 +MCUXSDK?=1 +MCUXPRESSO?=$(PWD)/../NXP/mcuxpresso-sdk/mcuxsdk +MCUXPRESSO_CMSIS?=$(PWD)/../NXP/CMSIS_5/CMSIS +MCUXPRESSO_CPU?=LPC55S69JBD100_cm33_core0 +MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/LPC/LPC5500/LPC55S69 +MCUXPRESSO_PROJECT_TEMPLATE?=$(MCUXPRESSO)/examples/_boards/lpcxpresso55s69/project_template +DEBUG?=0 +DEBUG_UART?=1 +VTOR?=1 +CORTEX_M0?=0 +CORTEX_M33?=1 +NO_ASM?=0 +NO_MPU=1 +EXT_FLASH?=0 +SPI_FLASH?=0 +ALLOW_DOWNGRADE?=0 +NVM_FLASH_WRITEONCE?=1 +NO_ARM_ASM=1 +WOLFBOOT_VERSION?=0 +V?=0 +SPMATH?=1 +RAM_CODE?=1 +DUALBANK_SWAP?=0 +PKA?=1 +FLASH_MULTI_SECTOR_ERASE?=1 +NO_DIRECT_READ_OF_ERASED_SECTOR?=1 +WOLFCRYPT_TZ?=1 +WOLFCRYPT_TZ_PKCS11?=1 + +# 512-byte pages erasable/writeable +WOLFBOOT_SECTOR_SIZE?=0x200 + +# 200KB boot, 80KB keyvault, 8KB NSC, 56KB partitions, 512 swap +WOLFBOOT_KEYVAULT_ADDRESS?=0x10032000 +WOLFBOOT_KEYVAULT_SIZE?=0x14000 +WOLFBOOT_NSC_ADDRESS?=0x10046000 +WOLFBOOT_NSC_SIZE?=0x2000 +WOLFBOOT_PARTITION_SIZE?=0xE000 +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x00048000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x00056000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x00064000 diff --git a/config/examples/lpc55s69.config b/config/examples/lpc55s69.config index 2111f374b7..da06a83f58 100644 --- a/config/examples/lpc55s69.config +++ b/config/examples/lpc55s69.config @@ -34,7 +34,7 @@ NO_DIRECT_READ_OF_ERASED_SECTOR?=1 WOLFBOOT_SECTOR_SIZE?=0x200 # Default configuration -# 32KB boot, 48KB partitions, 512 swap +# 40KB boot, 44KB partitions, 512 swap WOLFBOOT_PARTITION_SIZE?=0xB000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xA000 WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x15000 diff --git a/hal/lpc55s69-ns.ld b/hal/lpc55s69-ns.ld index 5e54a2e996..fc690ad66d 100644 --- a/hal/lpc55s69-ns.ld +++ b/hal/lpc55s69-ns.ld @@ -1,7 +1,7 @@ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = @WOLFBOOT_PARTITION_BOOT_ADDRESS@ - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256K + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = @BOOTLOADER_PARTITION_SIZE@ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } SECTIONS diff --git a/hal/lpc55s69.c b/hal/lpc55s69.c index d910cd517e..63ec5ad31e 100644 --- a/hal/lpc55s69.c +++ b/hal/lpc55s69.c @@ -48,18 +48,18 @@ static void hal_sau_init(void) sau_init_region(0, WOLFBOOT_NSC_ADDRESS, WOLFBOOT_NSC_ADDRESS + WOLFBOOT_NSC_SIZE - 1, 1); - /* Non-secure: application flash area (boot partition) */ + /* Non-secure: application flash area (boot+update partition) */ sau_init_region(1, WOLFBOOT_PARTITION_BOOT_ADDRESS, - WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE - 1, + WOLFBOOT_PARTITION_BOOT_ADDRESS + (WOLFBOOT_PARTITION_SIZE * 2) - 1, 0); /* Non-secure RAM */ - sau_init_region(2, 0x20020000, 0x20025FFF, 0); + sau_init_region(2, 0x20020000, 0x20027FFF, 0); /* Peripherals */ - sau_init_region(3, 0x40000000, 0x4005FFFF, 0); - sau_init_region(4, 0x40080000, 0x400DFFFF, 0); - sau_init_region(5, 0x40100000, 0x4013FFFF, 0); + sau_init_region(3, 0x40000000, 0x4003FFFF, 0); + sau_init_region(4, 0x40080000, 0x400AFFFF, 0); + sau_init_region(5, 0x40100000, 0x4010FFFF, 0); /* Enable SAU */ SAU_CTRL = SAU_INIT_CTRL_ENABLE; @@ -70,13 +70,8 @@ static void hal_sau_init(void) static void periph_unsecure(void) { - // CLOCK_EnableClock(kCLOCK_Gpio0); - // CLOCK_EnableClock(kCLOCK_Gpio1); - // CLOCK_EnableClock(kCLOCK_Port0); - // CLOCK_EnableClock(kCLOCK_Port1); - - // GPIO_EnablePinControlNonSecure(GPIO0, (1UL << 10) | (1UL << 27)); - // GPIO_EnablePinControlNonSecure(GPIO1, (1UL << 2) | (1UL << 8) | (1UL << 9)); + CLOCK_EnableClock(kCLOCK_Iocon); + CLOCK_EnableClock(kCLOCK_Gpio1); } #endif @@ -96,8 +91,6 @@ void hal_init(void) #if defined(__WOLFBOOT) || !defined(TZEN) memset(&pflash, 0, sizeof(pflash)); FLASH_Init(&pflash); - // FLASH_GetProperty(&pflash, kFLASH_PropertyPflashSectorSize, - // &pflash_sector_size); #endif #if defined(TZEN) && !defined(NONSECURE_APP) @@ -153,8 +146,7 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) address % pflash_page_size == 0 && len % pflash_page_size == 0 && FLASH_Erase(&pflash, address, len, kFLASH_ApiEraseKey) - == kStatus_FLASH_Success && - FLASH_VerifyErase(&pflash, address, len) == kStatus_FLASH_Success + == kStatus_FLASH_Success ) { return 0; diff --git a/hal/lpc55s69.ld b/hal/lpc55s69.ld new file mode 100644 index 0000000000..077d26b9d3 --- /dev/null +++ b/hal/lpc55s69.ld @@ -0,0 +1,75 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x10000000, LENGTH = @WOLFBOOT_KEYVAULT_ADDRESS@ - @ARCH_FLASH_OFFSET@ + RAM (rwx) : ORIGIN = 0x30000000, LENGTH = 0x10000 /* 64K */ + RAM_HEAP (rwx) : ORIGIN = 0x30010000, LENGTH = 0xC000 /* 48K */ + RAM_KV (rwx) : ORIGIN = 0x3001C000, LENGTH = 0x2000 /* 8K */ + FLASH_KEYVAULT (rw) : ORIGIN = @WOLFBOOT_KEYVAULT_ADDRESS@, LENGTH = @WOLFBOOT_KEYVAULT_SIZE@ + FLASH_NSC (rx) : ORIGIN = @WOLFBOOT_NSC_ADDRESS@, LENGTH = @WOLFBOOT_NSC_SIZE@ +} + +SECTIONS +{ + + .text : + { + _start_text = .; + KEEP(*(.isr_vector)) + . = 0x200; + *(.keystore*) + *(.text*) + *(.rodata*) + *(.init*) + *(.fini*) + . = ALIGN(4); + _end_text = .; + } > FLASH + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > FLASH + + .gnu.sgstubs : + { + . += 0x400; + . = ALIGN(4); + *(.gnu.sgstubs*) /* Secure Gateway Stubs */ + . = ALIGN(4); + } > FLASH_NSC + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + _end_data = .; + } > RAM + + .bss (NOLOAD) : + { + _start_bss = .; + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end_bss = .; + __bss_end__ = .; + _end = .; + } > RAM + . = ALIGN(4); +} + +END_STACK = ORIGIN(RAM) + LENGTH(RAM); + +_keyvault_origin = ORIGIN(RAM_KV); +_keyvault_size = LENGTH(RAM_KV); + +_flash_keyvault = ORIGIN(FLASH_KEYVAULT); +_flash_keyvault_size = LENGTH(FLASH_KEYVAULT); + +_start_heap = ORIGIN(RAM_HEAP); +_heap_size = LENGTH(RAM_HEAP); diff --git a/test-app/ARM-lpc55s69-ns.ld b/test-app/ARM-lpc55s69-ns.ld new file mode 100644 index 0000000000..aa3200f9eb --- /dev/null +++ b/test-app/ARM-lpc55s69-ns.ld @@ -0,0 +1,58 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = @WOLFBOOT_TEST_APP_ADDRESS@, LENGTH = @WOLFBOOT_TEST_APP_SIZE@ + RAM (rwx) : ORIGIN = 0x20020000, LENGTH = 32K +} + +SECTIONS +{ + .text : + { + _start_text = .; + KEEP(*(.isr_vector)) + *(.init) + *(.fini) + *(.text*) + KEEP(*(.rodata*)) + . = ALIGN(4); + _end_text = .; + } > FLASH + + .ARM : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + KEEP(*(.ramcode)) + . = ALIGN(4); + _end_data = .; + } > RAM + + .bss : + { + _start_bss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end_bss = .; + _end = .; + } > RAM +} + +_wolfboot_partition_boot_address = @WOLFBOOT_PARTITION_BOOT_ADDRESS@; +_wolfboot_partition_size = @WOLFBOOT_PARTITION_SIZE@; +_wolfboot_partition_update_address = @WOLFBOOT_PARTITION_UPDATE_ADDRESS@; +_wolfboot_partition_swap_address = @WOLFBOOT_PARTITION_SWAP_ADDRESS@; + +PROVIDE(_start_heap = _end); +PROVIDE(end = _end); +PROVIDE(_end_stack = ORIGIN(RAM) + LENGTH(RAM)); diff --git a/test-app/ARM-lpc55s69.ld b/test-app/ARM-lpc55s69.ld index f1b3872433..aa3200f9eb 100644 --- a/test-app/ARM-lpc55s69.ld +++ b/test-app/ARM-lpc55s69.ld @@ -1,7 +1,7 @@ MEMORY { FLASH (rx) : ORIGIN = @WOLFBOOT_TEST_APP_ADDRESS@, LENGTH = @WOLFBOOT_TEST_APP_SIZE@ - RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256K + RAM (rwx) : ORIGIN = 0x20020000, LENGTH = 32K } SECTIONS diff --git a/test-app/app_lpc55s69.c b/test-app/app_lpc55s69.c index c12a688252..410cb36879 100644 --- a/test-app/app_lpc55s69.c +++ b/test-app/app_lpc55s69.c @@ -43,16 +43,20 @@ extern void hal_init(void); static void leds_init(void) { +#ifndef TZEN CLOCK_EnableClock(kCLOCK_Iocon); CLOCK_EnableClock(kCLOCK_Gpio1); +#endif - const gpio_pin_config_t LED_GPIOPIN_config = { - .pinDirection = kGPIO_DigitalOutput, - .outputLogic = 1U /* off */ - }; - GPIO_PinInit(GPIO, 1, 6, &LED_GPIOPIN_config); /* red off */ - GPIO_PinInit(GPIO, 1, 7, &LED_GPIOPIN_config); /* green off */ - GPIO_PinInit(GPIO, 1, 4, &LED_GPIOPIN_config); /* blue off */ + /* red output off */ + GPIO->SET[1] = 1UL << RED_LED; + GPIO->DIR[1] |= 1UL << RED_LED; + /* green output off */ + GPIO->SET[1] = 1UL << GREEN_LED; + GPIO->DIR[1] |= 1UL << GREEN_LED; + /* blue output off */ + GPIO->SET[1] = 1UL << BLUE_LED; + GPIO->DIR[1] |= 1UL << BLUE_LED; const uint32_t LED_PINMUX_CONFIG = (/* Pin is configured as PIO */ IOCON_PIO_FUNC0 | @@ -66,58 +70,82 @@ static void leds_init(void) IOCON_PIO_DIGITAL_EN | /* Open drain is disabled */ IOCON_PIO_OPENDRAIN_DI); - IOCON_PinMuxSet(IOCON, 1, 6, LED_PINMUX_CONFIG); /* red */ - IOCON_PinMuxSet(IOCON, 1, 7, LED_PINMUX_CONFIG); /* green */ - IOCON_PinMuxSet(IOCON, 1, 4, LED_PINMUX_CONFIG); /* blue */ + IOCON_PinMuxSet(IOCON, 1, RED_LED, LED_PINMUX_CONFIG); + IOCON_PinMuxSet(IOCON, 1, GREEN_LED, LED_PINMUX_CONFIG); + IOCON_PinMuxSet(IOCON, 1, BLUE_LED, LED_PINMUX_CONFIG); +} + +static void check_parts( + uint32_t *pboot_ver, uint32_t *pupdate_ver, + uint8_t *pboot_state, uint8_t *pupdate_state +) +{ +#ifdef WOLFCRYPT_SECURE_MODE + *pboot_ver = wolfBoot_nsc_current_firmware_version(); + *pupdate_ver = wolfBoot_nsc_update_firmware_version(); + if (wolfBoot_nsc_get_partition_state(PART_BOOT, pboot_state) != 0) + *pboot_state = IMG_STATE_NEW; + if (wolfBoot_nsc_get_partition_state(PART_UPDATE, pupdate_state) != 0) + *pupdate_state = IMG_STATE_NEW; +#else + *pboot_ver = wolfBoot_current_firmware_version(); + *pupdate_ver = wolfBoot_update_firmware_version(); + if (wolfBoot_get_partition_state(PART_BOOT, pboot_state) != 0) + *pboot_state = IMG_STATE_NEW; + if (wolfBoot_get_partition_state(PART_UPDATE, pupdate_state) != 0) + *pupdate_state = IMG_STATE_NEW; +#endif + + wolfBoot_printf(" boot: ver=0x%lx state=0x%02x\n", *pboot_ver, *pboot_state); + wolfBoot_printf(" update: ver=0x%lx state=0x%02x\n", *pupdate_ver, *pupdate_state); } void main(void) { - uint32_t boot_ver; + uint32_t boot_ver, update_ver; + uint8_t boot_state, update_state; hal_init(); leds_init(); -#ifdef WOLFCRYPT_SECURE_MODE - boot_ver = wolfBoot_nsc_current_firmware_version(); -#else - boot_ver = wolfBoot_current_firmware_version(); -#endif + check_parts(&boot_ver, &update_ver, &boot_state, &update_state); wolfBoot_printf("Hello from firmware version %d\n", boot_ver); - if (boot_ver == 1) { - uint32_t update_ver; - - /* blue on */ - GPIO_PinWrite(GPIO, 1, BLUE_LED, 0); - + if ( + boot_ver != 0 && + (boot_state == IMG_STATE_TESTING || boot_state == IMG_STATE_NEW) + ) + { + wolfBoot_printf("Calling wolfBoot_success()\n"); #ifdef WOLFCRYPT_SECURE_MODE - update_ver = wolfBoot_nsc_update_firmware_version(); + wolfBoot_nsc_success(); #else - update_ver = wolfBoot_update_firmware_version(); + wolfBoot_success(); #endif + check_parts(&boot_ver, &update_ver, &boot_state, &update_state); + } + + if (boot_ver == 1) + { + /* blue on */ + GPIO_PinWrite(GPIO, 1, BLUE_LED, 0); if (update_ver != 0) { - wolfBoot_printf("Update firmware detected, version: 0x%lx\n", update_ver); + wolfBoot_printf("Update detected, version: 0x%lx\n", update_ver); wolfBoot_printf("Triggering update...\n"); #ifdef WOLFCRYPT_SECURE_MODE wolfBoot_nsc_update_trigger(); #else wolfBoot_update_trigger(); #endif + check_parts(&boot_ver, &update_ver, &boot_state, &update_state); wolfBoot_printf("...done. Reboot to apply.\n"); } } else { /* green on */ GPIO_PinWrite(GPIO, 1, GREEN_LED, 0); - -#ifdef WOLFCRYPT_SECURE_MODE - wolfBoot_nsc_success(); -#else - wolfBoot_success(); -#endif } while (1) { From dc87c8dee2f4909509bcf8b3c41efc1863992feb Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Wed, 4 Mar 2026 12:03:38 -0500 Subject: [PATCH 06/12] Fix bug due to uninitialized update partition state variable. --- src/update_flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/update_flash.c b/src/update_flash.c index dd837e33f3..df1992792a 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -384,7 +384,7 @@ static int RAMFUNCTION wolfBoot_swap_and_final_erase(int resume) struct wolfBoot_image boot[1]; struct wolfBoot_image update[1]; struct wolfBoot_image swap[1]; - uint8_t updateState; + uint8_t updateState = IMG_STATE_NEW; int eraseLen = (WOLFBOOT_SECTOR_SIZE #ifdef NVM_FLASH_WRITEONCE /* need to erase the redundant sector too */ * 2 From d365e4aa127374ae1c9ec0a4bb3f45666ddbe185 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Wed, 4 Mar 2026 18:16:54 -0500 Subject: [PATCH 07/12] Add .github workflow build tests --- .github/workflows/test-configs.yml | 14 ++++++++++++++ CMakeLists.txt | 1 + 2 files changed, 15 insertions(+) diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index a84cde0ccc..47a8af826e 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -140,6 +140,20 @@ jobs: config-file: ./config/examples/lpc54606j512.config board-name: lpcxpresso55s06 + lpc55s69_test: + uses: ./.github/workflows/test-build-mcux-sdk-manifests.yml + with: + arch: arm + config-file: ./config/examples/lpc55s69.config + board-name: lpcxpresso55s69 + + lpc55s69_tz_test: + uses: ./.github/workflows/test-build-mcux-sdk-manifests.yml + with: + arch: arm + config-file: ./config/examples/lpc55s69-tz.config + board-name: lpcxpresso55s69 + nrf52840_test: uses: ./.github/workflows/test-build.yml with: diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e10af46d0..0863a4bf0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -388,6 +388,7 @@ if(NOT DEFINED ARM_TARGETS) imx_rt kinetis lpc54606j512 + lpc55s69 mcxa mcxw mcxn From 6c48415fab4b4fdf9f3c3a1925ef75607771a27b Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Wed, 4 Mar 2026 18:18:57 -0500 Subject: [PATCH 08/12] Add lpc55s69 to targets.md --- docs/Targets.md | 314 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 313 insertions(+), 1 deletion(-) diff --git a/docs/Targets.md b/docs/Targets.md index b3b0af58ec..6ac959ac42 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -20,7 +20,7 @@ This README describes configuration of supported targets. * [NXP iMX-RT](#nxp-imx-rt) * [NXP Kinetis](#nxp-kinetis) * [NXP LPC54xxx](#nxp-lpc54xxx) -* [NXP LPC55S69](#lpc55s69) +* [NXP LPC55S69](#nxp-lpc55s69) * [NXP LS1028A](#nxp-ls1028a) * [NXP MCXA153](#nxp-mcxa153) * [NXP MCXW716](#nxp-mcxw716) @@ -1732,6 +1732,318 @@ arm-none-eabi-gdb wolfboot.elf -ex "target remote localhost:3333" ``` +## NXP LPC55S69 + +The NXP LPC55S69 is a dual-core Cortex-M33 microcontroller. The support has been +tested on the LPCXpresso55S69 board (LPC55S69-EVK), with the on-board LINK2 configured in +the default CMSIS-DAP mode. + +This requires the NXP MCUXpresso SDK. We tested using +[mcuxsdk-manifests](https://github.com/nxp-mcuxpresso/mcuxsdk-manifests) and +[CMSIS_5](https://github.com/nxp-mcuxpresso/CMSIS_5) placed under "../NXP". + +To set up the MCUXpresso SDK: + +``` +cd ../NXP + +# Install west +python -m venv west-venv +source west-venv/bin/activate +pip install west + +# Set up the repository +west init -m https://github.com/nxp-mcuxpresso/mcuxsdk-manifests.git mcuxpresso-sdk +cd mcuxpresso-sdk +west update_board --set board lpcxpresso55s69 + +deactivate +``` + +### LPC55S69: Configuring and compiling + +Copy the example configuration file and build with make: + +```sh +cp config/examples/lpc55s69.config .config +make +``` + +We also provide a TrustZone configuration at `config/examples/lpc55s69-tz.config`. + +### LPC55S69: Loading the firmware + +Download and install the LinkServer tool: +[@NXP: LinkServer for microcontrollers](https://www.nxp.com/design/design-center/software/development-software/mcuxpresso-software-and-tools-/linkserver-for-microcontrollers:LINKERSERVER#downloads) + +NOTE: The LPCXpresso55S69's on-board LINK2 debugger comes loaded with CMSIS-DAP protocol, but it can be +optionally updated to use JLink protocol instead. See the EVK user manual for how to do this, if desired. +The below examples were tested with the default CMSIS-DAP protocol. CMSIS-DAP is supported by default in +the MCUXpresso IDE for debugging purposes. + +Connect a USB cable from your development PC to P6 on the dev board. + +Open a terminal to the virtual COM port with putty or similar app, settings 115200-N-8-1. + +### LPC55S69: Testing firmware factory.bin + +1) Erase the entire flash: + +```sh +LinkServer flash LPC55S69 erase +``` + +2) Program the factory.bin, which contains both wolfBoot and the test-app version 1: + +```sh +LinkServer flash LPC55S69 load factory.bin:0 +``` + +3) The LED will light up blue to indicate version 1 of the firmware is running. You should also see output +like this in the terminal window: + +```sh +lpc55s69 init +Boot partition: 0xA000 (sz 24016, ver 0x1, type 0x601) +Partition 1 header magic 0xFFFFFFFF invalid at 0x15000 +Boot partition: 0xA000 (sz 24016, ver 0x1, type 0x601) +Booting version: 0x1 +lpc55s69 init + boot: ver=0x1 state=0xFF + update: ver=0x0 state=0xFF +Hello from firmware version 1 +Calling wolfBoot_success() + boot: ver=0x1 state=0x00 + update: ver=0x0 state=0xFF +``` + +### LPC55S69: Testing firmware update + +1) Sign the test-app with version 2: + +```sh +./tools/keytools/sign --ecc384 --sha384 test-app/image.bin wolfboot_signing_private_key.der 2 +``` + +2) Flash v2 update binary to your `.config`'s `WOLFBOOT_PARTITION_UPDATE_ADDRESS` + +Example: +```sh +LinkServer flash LPC55S69 load test-app/image_v2_signed.bin:0x15000 +``` + +3) You should see output like this in the terminal window: + +```sh +lpc55s69 init +Boot partition: 0xA000 (sz 24016, ver 0x1, type 0x601) +Update partition: 0x15000 (sz 24016, ver 0x2, type 0x601) +Boot partition: 0xA000 (sz 24016, ver 0x1, type 0x601) +Booting version: 0x1 +lpc55s69 init + boot: ver=0x1 state=0x00 + update: ver=0x2 state=0xFF +Hello from firmware version 1 +Update detected, version: 0x2 +Triggering update... + boot: ver=0x1 state=0x00 + update: ver=0x2 state=0x70 +...done. Reboot to apply. +``` + +4) Press the RESET button to reboot + +5) The LED will light up green to indicate version 2 of the firmware is running. You should also see output +like this in the terminal window: + +```sh +lpc55s69 init +Update partition: 0x15000 (sz 24016, ver 0x2, type 0x601) +Boot partition: 0xA000 (sz 24016, ver 0x1, type 0x601) +Update partition: 0x15000 (sz 24016, ver 0x2, type 0x601) +Starting Update (fallback allowed 0) +Update partition: 0x15000 (sz 24016, ver 0x2, type 0x601) +Boot partition: 0xA000 (sz 24016, ver 0x1, type 0x601) +Versions: Current 0x1, Update 0x2 +Copy sector 0 (part 1->2) +Copy sector 0 (part 0->1) +Copy sector 0 (part 2->0) +Boot partition: 0xA000 (sz 24016, ver 0x2, type 0x601) +Update partition: 0x15000 (sz 24016, ver 0x1, type 0x601) +Copy sector 1 (part 1->2) +Copy sector 1 (part 0->1) +Copy sector 1 (part 2->0) +Copy sector 2 (part 1->2) +Copy sector 2 (part 0->1) +Copy sector 2 (part 2->0) +Copy sector 3 (part 1->2) +Copy sector 3 (part 0->1) +Copy sector 3 (part 2->0) +Copy sector 4 (part 1->2) +Copy sector 4 (part 0->1) +Copy sector 4 (part 2->0) +Copy sector 5 (part 1->2) +Copy sector 5 (part 0->1) +Copy sector 5 (part 2->0) +Copy sector 6 (part 1->2) +Copy sector 6 (part 0->1) +Copy sector 6 (part 2->0) +Copy sector 7 (part 1->2) +Copy sector 7 (part 0->1) +Copy sector 7 (part 2->0) +Copy sector 8 (part 1->2) +Copy sector 8 (part 0->1) +Copy sector 8 (part 2->0) +Copy sector 9 (part 1->2) +Copy sector 9 (part 0->1) +Copy sector 9 (part 2->0) +Copy sector 10 (part 1->2) +Copy sector 10 (part 0->1) +Copy sector 10 (part 2->0) +Copy sector 11 (part 1->2) +Copy sector 11 (part 0->1) +Copy sector 11 (part 2->0) +Copy sector 12 (part 1->2) +Copy sector 12 (part 0->1) +Copy sector 12 (part 2->0) +Copy sector 13 (part 1->2) +Copy sector 13 (part 0->1) +Copy sector 13 (part 2->0) +Copy sector 14 (part 1->2) +Copy sector 14 (part 0->1) +Copy sector 14 (part 2->0) +Copy sector 15 (part 1->2) +Copy sector 15 (part 0->1) +Copy sector 15 (part 2->0) +Copy sector 16 (part 1->2) +Copy sector 16 (part 0->1) +Copy sector 16 (part 2->0) +Copy sector 17 (part 1->2) +Copy sector 17 (part 0->1) +Copy sector 17 (part 2->0) +Copy sector 18 (part 1->2) +Copy sector 18 (part 0->1) +Copy sector 18 (part 2->0) +Copy sector 19 (part 1->2) +Copy sector 19 (part 0->1) +Copy sector 19 (part 2->0) +Copy sector 20 (part 1->2) +Copy sector 20 (part 0->1) +Copy sector 20 (part 2->0) +Copy sector 21 (part 1->2) +Copy sector 21 (part 0->1) +Copy sector 21 (part 2->0) +Copy sector 22 (part 1->2) +Copy sector 22 (part 0->1) +Copy sector 22 (part 2->0) +Copy sector 23 (part 1->2) +Copy sector 23 (part 0->1) +Copy sector 23 (part 2->0) +Copy sector 24 (part 1->2) +Copy sector 24 (part 0->1) +Copy sector 24 (part 2->0) +Copy sector 25 (part 1->2) +Copy sector 25 (part 0->1) +Copy sector 25 (part 2->0) +Copy sector 26 (part 1->2) +Copy sector 26 (part 0->1) +Copy sector 26 (part 2->0) +Copy sector 27 (part 1->2) +Copy sector 27 (part 0->1) +Copy sector 27 (part 2->0) +Copy sector 28 (part 1->2) +Copy sector 28 (part 0->1) +Copy sector 28 (part 2->0) +Copy sector 29 (part 1->2) +Copy sector 29 (part 0->1) +Copy sector 29 (part 2->0) +Copy sector 30 (part 1->2) +Copy sector 30 (part 0->1) +Copy sector 30 (part 2->0) +Copy sector 31 (part 1->2) +Copy sector 31 (part 0->1) +Copy sector 31 (part 2->0) +Copy sector 32 (part 1->2) +Copy sector 32 (part 0->1) +Copy sector 32 (part 2->0) +Copy sector 33 (part 1->2) +Copy sector 33 (part 0->1) +Copy sector 33 (part 2->0) +Copy sector 34 (part 1->2) +Copy sector 34 (part 0->1) +Copy sector 34 (part 2->0) +Copy sector 35 (part 1->2) +Copy sector 35 (part 0->1) +Copy sector 35 (part 2->0) +Copy sector 36 (part 1->2) +Copy sector 36 (part 0->1) +Copy sector 36 (part 2->0) +Copy sector 37 (part 1->2) +Copy sector 37 (part 0->1) +Copy sector 37 (part 2->0) +Copy sector 38 (part 1->2) +Copy sector 38 (part 0->1) +Copy sector 38 (part 2->0) +Copy sector 39 (part 1->2) +Copy sector 39 (part 0->1) +Copy sector 39 (part 2->0) +Copy sector 40 (part 1->2) +Copy sector 40 (part 0->1) +Copy sector 40 (part 2->0) +Copy sector 41 (part 1->2) +Copy sector 41 (part 0->1) +Copy sector 41 (part 2->0) +Copy sector 42 (part 1->2) +Copy sector 42 (part 0->1) +Copy sector 42 (part 2->0) +Copy sector 43 (part 1->2) +Copy sector 43 (part 0->1) +Copy sector 43 (part 2->0) +Copy sector 44 (part 1->2) +Copy sector 44 (part 0->1) +Copy sector 44 (part 2->0) +Copy sector 45 (part 1->2) +Copy sector 45 (part 0->1) +Copy sector 45 (part 2->0) +Copy sector 46 (part 1->2) +Copy sector 46 (part 0->1) +Copy sector 46 (part 2->0) +Copy sector 47 (part 1->2) +Copy sector 47 (part 0->1) +Copy sector 47 (part 2->0) +Erasing remainder of partition (38 sectors)... +Boot partition: 0xA000 (sz 24016, ver 0x2, type 0x601) +Update partition: 0x15000 (sz 24016, ver 0x1, type 0x601) +Copy sector 85 (part 0->2) +Copied boot sector to swap +Boot partition: 0xA000 (sz 24016, ver 0x2, type 0x601) +Booting version: 0x2 +lpc55s69 init + boot: ver=0x2 state=0x10 + update: ver=0x1 state=0xFF +Hello from firmware version 2 +Calling wolfBoot_success() + boot: ver=0x2 state=0x00 + update: ver=0x1 state=0xFF +``` + +### LPC55S69: Debugging + +Debugging with GDB: + +Note: We include a `.gdbinit` in the wolfBoot root that loads the wolfboot and test-app elf files. + +In one terminal: `LinkServer gdbserver LPC55S69` + +In another terminal use `gdb`: + +``` +b main +mon reset +c +``` + + ## NXP LS1028A The LS1028A is a AARCH64 armv8-a Cortex-A72 processor. Support has been tested with the NXP LS1028ARDB. From 9376718149e8a0f379975008f381b2eacca71e5a Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Wed, 4 Mar 2026 18:35:29 -0500 Subject: [PATCH 09/12] Turn off linker warning due to ramcode rwx --- arch.mk | 2 +- test-app/Makefile | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch.mk b/arch.mk index 5f4676ccd4..ebbdb8bccf 100644 --- a/arch.mk +++ b/arch.mk @@ -1132,7 +1132,7 @@ ifeq ($(TARGET),lpc55s69) -I$(MCUXPRESSO_CMSIS)/Core/Include CFLAGS+=-DCPU_$(MCUXPRESSO_CPU) CFLAGS+=-mcpu=cortex-m33 -DCORTEX_M33 -U__ARM_FEATURE_DSP - LDFLAGS+=-mcpu=cortex-m33 + LDFLAGS+=-mcpu=cortex-m33 -Wl,--no-warn-rwx-segments OBJS+=\ $(MCUXPRESSO_PROJECT_TEMPLATE)/clock_config.o \ $(MCUXPRESSO_DRIVERS)/drivers/fsl_clock.o \ diff --git a/test-app/Makefile b/test-app/Makefile index 5ca61501b2..cc4be22d57 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -585,6 +585,7 @@ ifeq ($(TARGET),lpc55s69) ifeq (,$(findstring nosys.specs,$(LDFLAGS))) LDFLAGS+=--specs=nosys.specs endif + LDFLAGS+=-Wl,--no-warn-rwx-segments endif ifeq ($(TARGET),imx_rt) From 1bfd5b1ffd22348b6e5abf7c4348ff6c631cef78 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Thu, 5 Mar 2026 19:54:56 -0500 Subject: [PATCH 10/12] Add support for hardware rng --- arch.mk | 6 ++++++ hal/lpc55s69.c | 12 ++++++++++-- test-app/Makefile | 3 +++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/arch.mk b/arch.mk index ebbdb8bccf..c50ff65be8 100644 --- a/arch.mk +++ b/arch.mk @@ -1128,9 +1128,12 @@ ifeq ($(TARGET),lpc55s69) -I$(MCUXPRESSO)/drivers/iap1 \ -I$(MCUXPRESSO)/drivers/lpc_gpio \ -I$(MCUXPRESSO)/drivers/lpc_iocon \ + -I$(MCUXPRESSO)/drivers/rng_1 \ -I$(MCUXPRESSO_CMSIS)/Include \ -I$(MCUXPRESSO_CMSIS)/Core/Include CFLAGS+=-DCPU_$(MCUXPRESSO_CPU) + CFLAGS+=-DFSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL=1 + CFLAGS+=-DFSL_SDK_DISABLE_DRIVER_RESET_CONTROL=1 CFLAGS+=-mcpu=cortex-m33 -DCORTEX_M33 -U__ARM_FEATURE_DSP LDFLAGS+=-mcpu=cortex-m33 -Wl,--no-warn-rwx-segments OBJS+=\ @@ -1140,6 +1143,9 @@ ifeq ($(TARGET),lpc55s69) $(MCUXPRESSO)/drivers/common/fsl_common_arm.o \ $(MCUXPRESSO)/drivers/iap1/fsl_iap.o \ $(MCUXPRESSO)/drivers/lpc_gpio/fsl_gpio.o + ifeq ($(WOLFCRYPT_TZ),1) + OBJS+=$(MCUXPRESSO)/drivers/rng_1/fsl_rng.o + endif ifeq ($(DEBUG_UART),1) OBJS+=\ $(MCUXPRESSO_DRIVERS)/drivers/fsl_reset.o \ diff --git a/hal/lpc55s69.c b/hal/lpc55s69.c index 63ec5ad31e..eb39a6a060 100644 --- a/hal/lpc55s69.c +++ b/hal/lpc55s69.c @@ -30,6 +30,7 @@ #include "fsl_iap.h" #include "fsl_iocon.h" #include "fsl_reset.h" +#include "fsl_rng.h" #include "fsl_usart.h" #include "loader.h" @@ -166,6 +167,11 @@ int RAMFUNCTION hal_flash_is_erased_at(uint32_t address) #ifdef WOLFCRYPT_SECURE_MODE void hal_trng_init(void) { +#ifdef __WOLFBOOT + CLOCK_EnableClock(kCLOCK_Rng); + RESET_PeripheralReset(kRNG_RST_SHIFT_RSTn); +#endif + RNG_Init(RNG); } void hal_trng_fini(void) @@ -174,8 +180,9 @@ void hal_trng_fini(void) int hal_trng_get_entropy(unsigned char *out, unsigned int len) { - (void)out; - (void)len; + if (RNG_GetRandomData(RNG, out, len) == kStatus_Success) + return 0; + return -1; } #endif @@ -222,6 +229,7 @@ void uart_init(void) /* attach 12 MHz clock to FLEXCOMM0 (debug console) */ CLOCK_AttachClk(kFRO12M_to_FLEXCOMM0); + CLOCK_EnableClock(kCLOCK_FlexComm0); RESET_ClearPeripheralReset(kFC0_RST_SHIFT_RSTn); usart_config_t config; diff --git a/test-app/Makefile b/test-app/Makefile index cc4be22d57..89209734ee 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -582,6 +582,9 @@ ifeq ($(TARGET),lpc55s69) $(MCUXPRESSO)/drivers/flexcomm/usart/fsl_usart.o \ $(MCUXPRESSO)/drivers/iap1/fsl_iap.o \ $(MCUXPRESSO)/drivers/lpc_gpio/fsl_gpio.o + ifeq ($(WOLFCRYPT_TZ),1) + APP_OBJS+=$(MCUXPRESSO)/drivers/rng_1/fsl_rng.o + endif ifeq (,$(findstring nosys.specs,$(LDFLAGS))) LDFLAGS+=--specs=nosys.specs endif From ef4966cf626724cff45d718e1d7e5a2f818dc9d9 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Fri, 6 Mar 2026 17:45:29 -0500 Subject: [PATCH 11/12] Address copilot pr comments. --- docs/Targets.md | 3 --- hal/lpc55s69-ns.ld | 2 +- hal/lpc55s69.c | 5 +++-- include/wolfboot/wolfboot.h | 2 +- test-app/app_lpc55s69.c | 5 ++--- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/docs/Targets.md b/docs/Targets.md index 6ac959ac42..e82aa13990 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -1811,7 +1811,6 @@ Booting version: 0x1 lpc55s69 init boot: ver=0x1 state=0xFF update: ver=0x0 state=0xFF -Hello from firmware version 1 Calling wolfBoot_success() boot: ver=0x1 state=0x00 update: ver=0x0 state=0xFF @@ -1843,7 +1842,6 @@ Booting version: 0x1 lpc55s69 init boot: ver=0x1 state=0x00 update: ver=0x2 state=0xFF -Hello from firmware version 1 Update detected, version: 0x2 Triggering update... boot: ver=0x1 state=0x00 @@ -2021,7 +2019,6 @@ Booting version: 0x2 lpc55s69 init boot: ver=0x2 state=0x10 update: ver=0x1 state=0xFF -Hello from firmware version 2 Calling wolfBoot_success() boot: ver=0x2 state=0x00 update: ver=0x1 state=0xFF diff --git a/hal/lpc55s69-ns.ld b/hal/lpc55s69-ns.ld index fc690ad66d..b6e14cd3bd 100644 --- a/hal/lpc55s69-ns.ld +++ b/hal/lpc55s69-ns.ld @@ -1,6 +1,6 @@ MEMORY { - FLASH (rx) : ORIGIN = 0x00000000, LENGTH = @BOOTLOADER_PARTITION_SIZE@ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = @WOLFBOOT_PARTITION_BOOT_ADDRESS@ RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } diff --git a/hal/lpc55s69.c b/hal/lpc55s69.c index eb39a6a060..02ae8fae93 100644 --- a/hal/lpc55s69.c +++ b/hal/lpc55s69.c @@ -84,11 +84,10 @@ void hal_init(void) // BOARD_BootClockPLL150M(); #ifdef DEBUG_UART uart_init(); + uart_write("lpc55s69 init\n", 14); #endif #endif - uart_write("lpc55s69 init\n", 14); - #if defined(__WOLFBOOT) || !defined(TZEN) memset(&pflash, 0, sizeof(pflash)); FLASH_Init(&pflash); @@ -195,6 +194,7 @@ int hal_trng_get_entropy(unsigned char *out, unsigned int len) #define IOCON_PIO_OPENDRAIN_DI 0x00u /*!<@brief Open drain is disabled */ #define IOCON_PIO_SLEW_STANDARD 0x00u /*!<@brief Standard mode, output slew rate control is enabled */ +#ifdef DEBUG_UART void uart_init(void) { CLOCK_EnableClock(kCLOCK_Iocon); @@ -262,3 +262,4 @@ void uart_write(const char *buf, unsigned int sz) sz -= line_sz + 1U; } } +#endif \ No newline at end of file diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index b68caca145..eda5055677 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -477,7 +477,7 @@ extern "C" { #define IMG_STATE_NEW 0x00 #define IMG_STATE_UPDATING 0x8F #define IMG_STATE_TESTING 0xEF -#define IMG_STATE_FINAL_FLAGS 0xCF +#define IMG_STATE_FINAL_FLAGS 0xBF #define IMG_STATE_SUCCESS 0xFF #define FLASH_BYTE_ERASED 0x00 #define FLASH_WORD_ERASED 0x00000000UL diff --git a/test-app/app_lpc55s69.c b/test-app/app_lpc55s69.c index 410cb36879..4582bd7a1b 100644 --- a/test-app/app_lpc55s69.c +++ b/test-app/app_lpc55s69.c @@ -110,17 +110,16 @@ void main(void) check_parts(&boot_ver, &update_ver, &boot_state, &update_state); - wolfBoot_printf("Hello from firmware version %d\n", boot_ver); - if ( boot_ver != 0 && (boot_state == IMG_STATE_TESTING || boot_state == IMG_STATE_NEW) ) { - wolfBoot_printf("Calling wolfBoot_success()\n"); #ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_printf("Calling wolfBoot_nsc_success()\n"); wolfBoot_nsc_success(); #else + wolfBoot_printf("Calling wolfBoot_success()\n"); wolfBoot_success(); #endif check_parts(&boot_ver, &update_ver, &boot_state, &update_state); From c34ae42eddd0bab7aee368c968ed6de88dcf57a7 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Fri, 6 Mar 2026 18:03:16 -0500 Subject: [PATCH 12/12] Fix XMEMSET's per correct erased byte polarity. --- src/libwolfboot.c | 6 +++--- src/update_flash.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libwolfboot.c b/src/libwolfboot.c index 80b7c49f1f..f3ba7f7a55 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -357,7 +357,7 @@ static int RAMFUNCTION trailer_write(uint8_t part, uintptr_t addr, uint8_t val) addr_read = addr_align - (nvm_cached_sector * NVM_CACHE_SIZE); #ifdef NO_DIRECT_READ_OF_ERASED_SECTOR if (hal_flash_is_erased_at((uintptr_t)addr_read)) - XMEMSET(NVM_CACHE, 0xFF, NVM_CACHE_SIZE); + XMEMSET(NVM_CACHE, FLASH_BYTE_ERASED, NVM_CACHE_SIZE); else #endif XMEMCPY(NVM_CACHE, (void*)addr_read, NVM_CACHE_SIZE); @@ -406,7 +406,7 @@ static int RAMFUNCTION partition_magic_write(uint8_t part, uintptr_t addr) addr_write = base - (!nvm_cached_sector * NVM_CACHE_SIZE); #ifdef NO_DIRECT_READ_OF_ERASED_SECTOR if (hal_flash_is_erased_at((uintptr_t)addr_read)) - XMEMSET(NVM_CACHE, 0xFF, NVM_CACHE_SIZE); + XMEMSET(NVM_CACHE, FLASH_BYTE_ERASED, NVM_CACHE_SIZE); else #endif XMEMCPY(NVM_CACHE, (void*)addr_read, NVM_CACHE_SIZE); @@ -866,7 +866,7 @@ void RAMFUNCTION wolfBoot_update_trigger(void) selSec = nvm_select_fresh_sector(PART_UPDATE); # ifdef NO_DIRECT_READ_OF_ERASED_SECTOR if (hal_flash_is_erased_at((uintptr_t)lastSector - WOLFBOOT_SECTOR_SIZE * selSec)) - XMEMSET(NVM_CACHE, 0xFF, WOLFBOOT_SECTOR_SIZE); + XMEMSET(NVM_CACHE, FLASH_BYTE_ERASED, WOLFBOOT_SECTOR_SIZE); else # endif XMEMCPY(NVM_CACHE, (uint8_t*)lastSector - WOLFBOOT_SECTOR_SIZE * selSec, diff --git a/src/update_flash.c b/src/update_flash.c index 89226a17c9..5d1676711a 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -411,7 +411,7 @@ static int RAMFUNCTION wolfBoot_swap_and_final_erase(int resume) #else # ifdef NO_DIRECT_READ_OF_ERASED_SECTOR if (hal_flash_is_erased_at((uintptr_t)(boot->hdr + tmpBootPos))) - memset(tmpBuffer, 0xFF, sizeof(tmpBuffer)); + memset(tmpBuffer, FLASH_BYTE_ERASED, sizeof(tmpBuffer)); else # endif memcpy(tmpBuffer, boot->hdr + tmpBootPos, sizeof(tmpBuffer));