diff --git a/arch.mk b/arch.mk index 30590530..77a09dde 100644 --- a/arch.mk +++ b/arch.mk @@ -1183,6 +1183,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 00000000..391e7a54 --- /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 4829cfd0..953b54fe 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -21,6 +21,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) @@ -1948,7 +1949,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 00000000..5e54a2e9 --- /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 00000000..0937b228 --- /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 00000000..f1b38724 --- /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 77f1ca58..16fdeac8 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -643,6 +643,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 00000000..0b6fae2e --- /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"); + } +}