From 438c250288b0e0b24a8f71b1f848d756789f1902 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 22 Jan 2026 18:30:54 +0100 Subject: [PATCH 01/10] MCXN non-TrustZone + TrustZone port --- CMakeLists.txt | 1 + arch.mk | 39 +++- config/examples/mcxn-tz.config | 55 ++++++ config/examples/mcxn.config | 46 +++++ hal/mcxn-ns.ld | 54 ++++++ hal/mcxn.c | 331 +++++++++++++++++++++++++++++++++ hal/mcxn.ld | 75 ++++++++ test-app/ARM-mcxn-ns.ld | 58 ++++++ test-app/ARM-mcxn.ld | 58 ++++++ test-app/Makefile | 20 ++ test-app/app_mcxn.c | 122 ++++++++++++ 11 files changed, 858 insertions(+), 1 deletion(-) create mode 100644 config/examples/mcxn-tz.config create mode 100644 config/examples/mcxn.config create mode 100644 hal/mcxn-ns.ld create mode 100644 hal/mcxn.c create mode 100644 hal/mcxn.ld create mode 100644 test-app/ARM-mcxn-ns.ld create mode 100644 test-app/ARM-mcxn.ld create mode 100644 test-app/app_mcxn.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 210bedf49c..cc924d039d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -390,6 +390,7 @@ if(NOT DEFINED ARM_TARGETS) lpc54606j512 mcxa mcxw + mcxn nrf52 nrf52840 nrf5340 diff --git a/arch.mk b/arch.mk index d4467bf886..da526591b1 100644 --- a/arch.mk +++ b/arch.mk @@ -339,7 +339,7 @@ else ifeq ($(WOLFCRYPT_TZ),1) CORTEXM_ARM_EXTRA_OBJS= CORTEXM_ARM_EXTRA_CFLAGS= - SECURE_OBJS+=./src/wc_callable.o + SECURE_OBJS+=./src/wc_callable.o $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/random.o CFLAGS+=-DWOLFCRYPT_SECURE_MODE SECURE_LDFLAGS+=-Wl,--cmse-implib -Wl,--out-implib=./src/wc_secure_calls.o endif @@ -732,6 +732,43 @@ ifeq ($(TARGET),mcxw) $(MCUXPRESSO_DRIVERS)/drivers/fsl_romapi.o endif +ifeq ($(TARGET),mcxn) + CORTEX_M33=1 + ifneq ($(TZEN),1) + LSCRIPT_IN=hal/$(TARGET)-ns.ld + endif + CFLAGS+=\ + -I$(MCUXPRESSO_DRIVERS) \ + -I$(MCUXPRESSO_DRIVERS)/drivers \ + -I$(MCUXPRESSO_DRIVERS)/drivers/romapi/flash \ + -I$(MCUXPRESSO_DRIVERS)/../periph \ + -I$(MCUXPRESSO) \ + -I$(MCUXPRESSO)/drivers \ + -I$(MCUXPRESSO)/drivers/gpio \ + -I$(MCUXPRESSO)/drivers/port \ + -I$(MCUXPRESSO)/drivers/common \ + -I$(MCUXPRESSO)/drivers/lpflexcomm \ + -I$(MCUXPRESSO)/drivers/lpuart \ + -I$(MCUXPRESSO_PROJECT_TEMPLATE) \ + -I$(MCUXPRESSO_CMSIS)/Include \ + -I$(MCUXPRESSO_CMSIS)/Core/Include + CFLAGS+=-DCPU_$(MCUXPRESSO_CPU) -DDEBUG_CONSOLE_ASSERT_DISABLE=1 + CFLAGS+=-Wno-old-style-declaration + CFLAGS+=-mcpu=cortex-m33 -DCORTEX_M33 -U__ARM_FEATURE_DSP + LDFLAGS+=-mcpu=cortex-m33 + OBJS+=\ + $(MCUXPRESSO_DRIVERS)/drivers/fsl_clock.o \ + $(MCUXPRESSO_PROJECT_TEMPLATE)/clock_config.o \ + $(MCUXPRESSO_DRIVERS)/drivers/romapi/flash/src/fsl_flash.o + + ifeq ($(DEBUG_UART),1) + OBJS+=\ + $(MCUXPRESSO)/drivers/lpflexcomm/fsl_lpflexcomm.o \ + $(MCUXPRESSO)/drivers/lpuart/fsl_lpuart.o \ + $(MCUXPRESSO_DRIVERS)/drivers/fsl_reset.o + endif +endif + ifeq ($(TARGET),nrf5340) ifneq ($(TZEN), 1) LSCRIPT_IN=hal/$(TARGET)-ns.ld diff --git a/config/examples/mcxn-tz.config b/config/examples/mcxn-tz.config new file mode 100644 index 0000000000..9818286e1e --- /dev/null +++ b/config/examples/mcxn-tz.config @@ -0,0 +1,55 @@ +ARCH?=ARM +TZEN?=1 +TARGET?=mcxn +SIGN?=ECC384 +HASH?=SHA384 +MCUXSDK?=1 +MCUXPRESSO?=$(PWD)/../NXP/mcuxsdk/mcuxsdk +MCUXPRESSO_CMSIS?=$(PWD)/../NXP/CMSIS_5/CMSIS +MCUXPRESSO_CPU?=MCXN947VDF_cm33_core0 +MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/MCX/MCXN/MCXN947 +MCUXPRESSO_PROJECT_TEMPLATE?=$(MCUXPRESSO)/examples/_boards/frdmmcxn947/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 +WOLFCRYPT_TZ?=1 + +# 8KB sectors +WOLFBOOT_SECTOR_SIZE?=0x2000 + +# Default configuration +# 64KB boot, 80KB keyvault, 8KB NSC, 60KB partitions, 8KB swap +WOLFBOOT_KEYVAULT_ADDRESS?=0x10000 +WOLFBOOT_KEYVAULT_SIZE?=0x14000 +WOLFBOOT_NSC_ADDRESS?=0x24000 +WOLFBOOT_NSC_SIZE?=0x2000 +WOLFBOOT_PARTITION_SIZE?=0xF000 +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x26000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x35000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x44000 + +# Alternate larger configuration for debugging or ARMASM +# 128KB boot, 80KB keyvault, 8KB NSC, 60KB partitions, 8KB swap +#WOLFBOOT_KEYVAULT_ADDRESS?=0x20000 +#WOLFBOOT_KEYVAULT_SIZE?=0x14000 +#WOLFBOOT_NSC_ADDRESS?=0x34000 +#WOLFBOOT_NSC_SIZE?=0x2000 +#WOLFBOOT_PARTITION_SIZE?=0xF000 +#WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x36000 +#WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x45000 +#WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x54000 diff --git a/config/examples/mcxn.config b/config/examples/mcxn.config new file mode 100644 index 0000000000..2d3662ae34 --- /dev/null +++ b/config/examples/mcxn.config @@ -0,0 +1,46 @@ +ARCH?=ARM +TZEN?=0 +TARGET?=mcxn +SIGN?=ECC384 +HASH?=SHA384 +MCUXSDK?=1 +MCUXPRESSO?=$(PWD)/../NXP/mcuxsdk/mcuxsdk +MCUXPRESSO_CMSIS?=$(PWD)/../NXP/CMSIS_5/CMSIS +MCUXPRESSO_CPU?=MCXN947VDF_cm33_core0 +MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/MCX/MCXN/MCXN947 +MCUXPRESSO_PROJECT_TEMPLATE?=$(MCUXPRESSO)/examples/_boards/frdmmcxn947/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 + +# 8KB sectors +WOLFBOOT_SECTOR_SIZE?=0x2000 + +# Default configuration +# 40KB boot, 44KB partitions, 8KB swap +WOLFBOOT_PARTITION_SIZE?=0xB000 +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xA000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x15000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x20000 + +# Alternate larger configuration for debugging or ARMASM +# 64KB boot, 64KB partitions, 8KB swap +#WOLFBOOT_PARTITION_SIZE?=0x10000 +#WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x12000 +#WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x22000 +#WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x32000 diff --git a/hal/mcxn-ns.ld b/hal/mcxn-ns.ld new file mode 100644 index 0000000000..723276d324 --- /dev/null +++ b/hal/mcxn-ns.ld @@ -0,0 +1,54 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = @BOOTLOADER_PARTITION_SIZE@ + 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); + _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/mcxn.c b/hal/mcxn.c new file mode 100644 index 0000000000..e91d20e8b9 --- /dev/null +++ b/hal/mcxn.c @@ -0,0 +1,331 @@ +/* mcxn.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_flash.h" +#include "fsl_gpio.h" +#include "fsl_lpflexcomm.h" +#include "fsl_lpuart.h" +#include "fsl_port.h" +#include "fsl_reset.h" +#include "loader.h" +#include "PERI_AHBSC.h" + +#ifdef TZEN +#include "hal/armv8m_tz.h" +#endif + +static flash_config_t pflash; +static uint32_t pflash_sector_size = WOLFBOOT_SECTOR_SIZE; +uint32_t SystemCoreClock; + +#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 + /* Single-byte RAM writes unpredictably fail when ECC is enabled */ + SYSCON->ECC_ENABLE_CTRL = 0; + BOARD_InitBootClocks(); +#ifdef DEBUG_UART + uart_init(); +#endif +#endif + +#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) +{ + const uint32_t word_size = 4U; + int written = 0; + + while (len > 0) { + if ((address & (word_size - 1U)) || (len < (int)word_size)) { + uint32_t aligned = address & ~(word_size - 1U); + uint32_t word; + uint32_t offset = address - aligned; + uint32_t copy = word_size - offset; + + if (copy > (uint32_t)len) { + copy = (uint32_t)len; + } + + memcpy(&word, (void *)aligned, word_size); + memcpy(((uint8_t *)&word) + offset, data + written, copy); + if (FLASH_Program(&pflash, aligned, (uint8_t *)&word, word_size) != + kStatus_FLASH_Success) { + return -1; + } + + address += copy; + len -= (int)copy; + written += (int)copy; + } + else { + uint32_t chunk = (uint32_t)len & ~(word_size - 1U); + + if (FLASH_Program(&pflash, address, (uint8_t *)data + written, + chunk) != kStatus_FLASH_Success) { + return -1; + } + + address += chunk; + len -= (int)chunk; + written += (int)chunk; + } + } + + return 0; +} + +void RAMFUNCTION hal_flash_unlock(void) +{ +} + +void RAMFUNCTION hal_flash_lock(void) +{ +} + +int RAMFUNCTION hal_flash_erase(uint32_t address, int len) +{ + uint32_t sector_size = pflash_sector_size; + + if (sector_size == 0U) { + sector_size = WOLFBOOT_SECTOR_SIZE; + } + + if ((address % sector_size) != 0U) { + address -= address % sector_size; + } + + while (len > 0) { + if (FLASH_Erase(&pflash, address, sector_size, + kFLASH_ApiEraseKey) != kStatus_FLASH_Success) { + return -1; + } + if (FLASH_VerifyErase(&pflash, address, sector_size) != + kStatus_FLASH_Success) { + return -1; + } + address += sector_size; + len -= (int)sector_size; + } + + return 0; +} + +#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 + +void uart_init(void) +{ + lpuart_config_t config; + const port_pin_config_t uart_rx = { + .pullSelect = kPORT_PullUp, +#if defined(FSL_FEATURE_PORT_PCR_HAS_PULL_VALUE) && FSL_FEATURE_PORT_PCR_HAS_PULL_VALUE + .pullValueSelect = kPORT_LowPullResistor, +#endif +#if defined(FSL_FEATURE_PORT_HAS_SLEW_RATE) && FSL_FEATURE_PORT_HAS_SLEW_RATE + .slewRate = kPORT_FastSlewRate, +#endif +#if defined(FSL_FEATURE_PORT_HAS_PASSIVE_FILTER) && FSL_FEATURE_PORT_HAS_PASSIVE_FILTER + .passiveFilterEnable = kPORT_PassiveFilterDisable, +#endif +#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN + .openDrainEnable = kPORT_OpenDrainDisable, +#endif +#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH + .driveStrength = kPORT_LowDriveStrength, +#endif +#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH1) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH1 + .driveStrength1 = kPORT_NormalDriveStrength, +#endif + .mux = kPORT_MuxAlt2, +#if defined(FSL_FEATURE_PORT_HAS_INPUT_BUFFER) && FSL_FEATURE_PORT_HAS_INPUT_BUFFER + .inputBuffer = kPORT_InputBufferEnable, +#endif +#if defined(FSL_FEATURE_PORT_HAS_INVERT_INPUT) && FSL_FEATURE_PORT_HAS_INVERT_INPUT + .invertInput = kPORT_InputNormal, +#endif +#if defined(FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK) && FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK + .lockRegister = kPORT_UnlockRegister +#endif + }; + const port_pin_config_t uart_tx = { + .pullSelect = kPORT_PullDisable, +#if defined(FSL_FEATURE_PORT_PCR_HAS_PULL_VALUE) && FSL_FEATURE_PORT_PCR_HAS_PULL_VALUE + .pullValueSelect = kPORT_LowPullResistor, +#endif +#if defined(FSL_FEATURE_PORT_HAS_SLEW_RATE) && FSL_FEATURE_PORT_HAS_SLEW_RATE + .slewRate = kPORT_FastSlewRate, +#endif +#if defined(FSL_FEATURE_PORT_HAS_PASSIVE_FILTER) && FSL_FEATURE_PORT_HAS_PASSIVE_FILTER + .passiveFilterEnable = kPORT_PassiveFilterDisable, +#endif +#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN + .openDrainEnable = kPORT_OpenDrainDisable, +#endif +#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH + .driveStrength = kPORT_LowDriveStrength, +#endif +#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH1) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH1 + .driveStrength1 = kPORT_NormalDriveStrength, +#endif + .mux = kPORT_MuxAlt2, +#if defined(FSL_FEATURE_PORT_HAS_INPUT_BUFFER) && FSL_FEATURE_PORT_HAS_INPUT_BUFFER + .inputBuffer = kPORT_InputBufferEnable, +#endif +#if defined(FSL_FEATURE_PORT_HAS_INVERT_INPUT) && FSL_FEATURE_PORT_HAS_INVERT_INPUT + .invertInput = kPORT_InputNormal, +#endif +#if defined(FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK) && FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK + .lockRegister = kPORT_UnlockRegister +#endif + }; + + CLOCK_SetClkDiv(kCLOCK_DivFlexcom4Clk, 1U); + CLOCK_AttachClk(kFRO12M_to_FLEXCOMM4); + CLOCK_EnableClock(kCLOCK_LPFlexComm4); + RESET_ClearPeripheralReset(kFC4_RST_SHIFT_RSTn); + CLOCK_EnableClock(kCLOCK_Port1); + + PORT_SetPinConfig(PORT1, 8U, &uart_rx); + PORT_SetPinConfig(PORT1, 9U, &uart_tx); + + (void)LP_FLEXCOMM_Init(4U, LP_FLEXCOMM_PERIPH_LPUART); + LPUART_GetDefaultConfig(&config); + config.baudRate_Bps = 115200U; + config.enableTx = true; + config.enableRx = true; + (void)LPUART_Init(LPUART4, &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)LPUART_WriteBlocking(LPUART4, (const uint8_t *)buf, sz); + break; + } + line_sz = (unsigned int)(line - buf); + if (line_sz > sz - 1U) { + line_sz = sz - 1U; + } + (void)LPUART_WriteBlocking(LPUART4, (const uint8_t *)buf, line_sz); + (void)LPUART_WriteBlocking(LPUART4, (const uint8_t *)"\r\n", 2U); + buf = line + 1; + sz -= line_sz + 1U; + } +} diff --git a/hal/mcxn.ld b/hal/mcxn.ld new file mode 100644 index 0000000000..97db19c4e6 --- /dev/null +++ b/hal/mcxn.ld @@ -0,0 +1,75 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, 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-mcxn-ns.ld b/test-app/ARM-mcxn-ns.ld new file mode 100644 index 0000000000..f07640c245 --- /dev/null +++ b/test-app/ARM-mcxn-ns.ld @@ -0,0 +1,58 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = @WOLFBOOT_TEST_APP_ADDRESS@, LENGTH = @WOLFBOOT_TEST_APP_SIZE@ + RAM (rwx) : ORIGIN = 0x20020000, LENGTH = 24K +} + +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-mcxn.ld b/test-app/ARM-mcxn.ld new file mode 100644 index 0000000000..f1b3872433 --- /dev/null +++ b/test-app/ARM-mcxn.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 d2e39d218b..ccd8e27bcf 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -372,6 +372,26 @@ ifeq ($(TARGET),mcxw) LDFLAGS+=--specs=nosys.specs endif +ifeq ($(TARGET),mcxn) + ifeq ($(TZEN),1) + LSCRIPT_TEMPLATE=ARM-mcxn-ns.ld + CFLAGS:=$(filter-out -mcmse, $(CFLAGS)) + else + LSCRIPT_TEMPLATE=ARM-mcxn.ld + endif + APP_OBJS+=\ + $(MCUXPRESSO_PROJECT_TEMPLATE)/clock_config.o \ + $(MCUXPRESSO)/drivers/gpio/fsl_gpio.o \ + $(MCUXPRESSO)/drivers/lpflexcomm/fsl_lpflexcomm.o \ + $(MCUXPRESSO)/drivers/lpuart/fsl_lpuart.o \ + $(MCUXPRESSO_DRIVERS)/drivers/fsl_reset.o \ + $(MCUXPRESSO_DRIVERS)/drivers/fsl_clock.o \ + $(MCUXPRESSO_DRIVERS)/drivers/romapi/flash/src/fsl_flash.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_mcxn.c b/test-app/app_mcxn.c new file mode 100644 index 0000000000..9a0a97f85b --- /dev/null +++ b/test-app/app_mcxn.c @@ -0,0 +1,122 @@ +/* app_mcxn.c + * + * Minimal test application scaffold for NXP MCXN targets. + * + * 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_port.h" + +#include "target.h" +#include "wolfboot/wolfboot.h" +#include "printf.h" + +extern void hal_init(void); + +static void gpio_init_output(GPIO_Type *gpio, PORT_Type *port, + clock_ip_name_t gpio_clock, + clock_ip_name_t port_clock, uint32_t pin, + uint8_t initial_level) +{ + const port_pin_config_t pin_config = { + .pullSelect = kPORT_PullDisable, +#if defined(FSL_FEATURE_PORT_PCR_HAS_PULL_VALUE) && FSL_FEATURE_PORT_PCR_HAS_PULL_VALUE + .pullValueSelect = kPORT_LowPullResistor, +#endif +#if defined(FSL_FEATURE_PORT_HAS_SLEW_RATE) && FSL_FEATURE_PORT_HAS_SLEW_RATE + .slewRate = kPORT_FastSlewRate, +#endif +#if defined(FSL_FEATURE_PORT_HAS_PASSIVE_FILTER) && FSL_FEATURE_PORT_HAS_PASSIVE_FILTER + .passiveFilterEnable = kPORT_PassiveFilterDisable, +#endif +#if defined(FSL_FEATURE_PORT_HAS_OPEN_DRAIN) && FSL_FEATURE_PORT_HAS_OPEN_DRAIN + .openDrainEnable = kPORT_OpenDrainDisable, +#endif +#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH + .driveStrength = kPORT_LowDriveStrength, +#endif +#if defined(FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH1) && FSL_FEATURE_PORT_HAS_DRIVE_STRENGTH1 + .driveStrength1 = kPORT_LowDriveStrength, +#endif + .mux = kPORT_MuxAlt0, +#if defined(FSL_FEATURE_PORT_HAS_INPUT_BUFFER) && FSL_FEATURE_PORT_HAS_INPUT_BUFFER + .inputBuffer = kPORT_InputBufferEnable, +#endif +#if defined(FSL_FEATURE_PORT_HAS_INVERT_INPUT) && FSL_FEATURE_PORT_HAS_INVERT_INPUT + .invertInput = kPORT_InputNormal, +#endif +#if defined(FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK) && FSL_FEATURE_PORT_HAS_PIN_CONTROL_LOCK + .lockRegister = kPORT_UnlockRegister +#endif + }; + const gpio_pin_config_t gpio_config = { + .pinDirection = kGPIO_DigitalOutput, + .outputLogic = initial_level, + }; + + CLOCK_EnableClock(gpio_clock); + CLOCK_EnableClock(port_clock); + GPIO_PinInit(gpio, pin, &gpio_config); + PORT_SetPinConfig(port, pin, &pin_config); +} + +void main(void) +{ + uint32_t boot_ver; + + hal_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) { + /* Red off */ + gpio_init_output(GPIO0, PORT0, kCLOCK_Gpio0, kCLOCK_Port0, 10U, 1U); + /* Green off */ + gpio_init_output(GPIO0, PORT0, kCLOCK_Gpio0, kCLOCK_Port0, 27U, 1U); + /* Blue on */ + gpio_init_output(GPIO1, PORT1, kCLOCK_Gpio1, kCLOCK_Port1, 2U, 0U); + } + else { + /* Red off */ + gpio_init_output(GPIO0, PORT0, kCLOCK_Gpio0, kCLOCK_Port0, 10U, 1U); + /* Green on */ + gpio_init_output(GPIO0, PORT0, kCLOCK_Gpio0, kCLOCK_Port0, 27U, 0U); + /* Blue off */ + gpio_init_output(GPIO1, PORT1, kCLOCK_Gpio1, kCLOCK_Port1, 2U, 1U); + +#ifdef WOLFCRYPT_SECURE_MODE + wolfBoot_nsc_success(); +#else + wolfBoot_success(); +#endif + } + + while (1) { + __asm__ volatile ("wfi"); + } +} From 4cf18d4ec20d4648b68fcaec4c73ce87d58aee3b Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 22 Jan 2026 18:37:24 +0100 Subject: [PATCH 02/10] Use default name for SDK directory --- config/examples/mcxn-tz.config | 2 +- config/examples/mcxn.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/examples/mcxn-tz.config b/config/examples/mcxn-tz.config index 9818286e1e..9ef6b0a550 100644 --- a/config/examples/mcxn-tz.config +++ b/config/examples/mcxn-tz.config @@ -4,7 +4,7 @@ TARGET?=mcxn SIGN?=ECC384 HASH?=SHA384 MCUXSDK?=1 -MCUXPRESSO?=$(PWD)/../NXP/mcuxsdk/mcuxsdk +MCUXPRESSO?=$(PWD)/../NXP/mcuxpresso-sdk/mcuxsdk MCUXPRESSO_CMSIS?=$(PWD)/../NXP/CMSIS_5/CMSIS MCUXPRESSO_CPU?=MCXN947VDF_cm33_core0 MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/MCX/MCXN/MCXN947 diff --git a/config/examples/mcxn.config b/config/examples/mcxn.config index 2d3662ae34..ac475be14d 100644 --- a/config/examples/mcxn.config +++ b/config/examples/mcxn.config @@ -4,7 +4,7 @@ TARGET?=mcxn SIGN?=ECC384 HASH?=SHA384 MCUXSDK?=1 -MCUXPRESSO?=$(PWD)/../NXP/mcuxsdk/mcuxsdk +MCUXPRESSO?=$(PWD)/../NXP/mcuxpresso-sdk/mcuxsdk MCUXPRESSO_CMSIS?=$(PWD)/../NXP/CMSIS_5/CMSIS MCUXPRESSO_CPU?=MCXN947VDF_cm33_core0 MCUXPRESSO_DRIVERS?=$(MCUXPRESSO)/devices/MCX/MCXN/MCXN947 From 8c00a73cc8bed42afda1bddf3b7b0f18f3314fc2 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 22 Jan 2026 18:53:56 +0100 Subject: [PATCH 03/10] Add GitHub workflows --- .../test-build-mcux-sdk-manifests.yml | 108 ++++++++++++++++++ .github/workflows/test-configs.yml | 12 ++ 2 files changed, 120 insertions(+) create mode 100644 .github/workflows/test-build-mcux-sdk-manifests.yml diff --git a/.github/workflows/test-build-mcux-sdk-manifests.yml b/.github/workflows/test-build-mcux-sdk-manifests.yml new file mode 100644 index 0000000000..bf57ba28ba --- /dev/null +++ b/.github/workflows/test-build-mcux-sdk-manifests.yml @@ -0,0 +1,108 @@ +name: Wolfboot Reusable Build Workflow for MCUXpresso SDK + +on: + + workflow_call: + inputs: + arch: + required: true + type: string + config-file: + required: true + type: string + board-name: + required: true + type: string + make-args: + required: false + type: string + +jobs: + + build: + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - uses: actions/checkout@main + with: + repository: nxp-mcuxpresso/CMSIS_5 + path: CMSIS_5 + + - name: Workaround for sources.list + run: | + # Replace sources + + set -euxo pipefail + + # Peek (what repos are active now) + apt-cache policy + grep -RInE '^(deb|Types|URIs)' /etc/apt || true + + # Enable nullglob so *.list/*.sources that don't exist don't break sed + shopt -s nullglob + + echo "Replace sources.list (legacy)" + sudo sed -i \ + -e "s|https\?://azure\.archive\.ubuntu\.com/ubuntu/?|http://mirror.arizona.edu/ubuntu/|g" \ + /etc/apt/sources.list || true + + echo "Replace sources.list.d/*.list (legacy)" + for f in /etc/apt/sources.list.d/*.list; do + sudo sed -i \ + -e "s|https\?://azure\.archive\.ubuntu\.com/ubuntu/?|http://mirror.arizona.edu/ubuntu/|g" \ + "$f" + done + + echo "Replace sources.list.d/*.sources (deb822)" + for f in /etc/apt/sources.list.d/*.sources; do + sudo sed -i \ + -e "s|https\?://azure\.archive\.ubuntu\.com/ubuntu/?|http://mirror.arizona.edu/ubuntu/|g" \ + -e "s|https\?://azure\.archive\.ubuntu\.com|http://mirror.arizona.edu|g" \ + "$f" + done + + echo "Fix /etc/apt/apt-mirrors.txt (used by URIs: mirror+file:...)" + if grep -qE '^[[:space:]]*https?://azure\.archive\.ubuntu\.com/ubuntu/?' /etc/apt/apt-mirrors.txt; then + # Replace azure with our mirror (idempotent) + sudo sed -i 's|https\?://azure\.archive\.ubuntu\.com/ubuntu/|http://mirror.arizona.edu/ubuntu/|g' /etc/apt/apt-mirrors.txt + fi + + # Peek (verify changes) + grep -RIn "azure.archive.ubuntu.com" /etc/apt || true + grep -RInE '^(deb|Types|URIs)' /etc/apt || true + echo "--- apt-mirrors.txt ---" + cat /etc/apt/apt-mirrors.txt || true + + - name: Update repository + run: sudo apt-get update + + - name: Install software + run: | + sudo apt-get install -y gcc-arm-none-eabi west + + - name: Setup MCUXpresso SDK + run: | + west init -m https://github.com/nxp-mcuxpresso/mcuxsdk-manifests.git mcuxpresso-sdk + cd mcuxpresso-sdk + west update_board --set board ${{inputs.board-name}} + + - name: make distclean + run: | + make distclean + + - name: Select config + run: | + cp ${{inputs.config-file}} .config && make include/target.h + + - name: Build tools + run: | + make -C tools/keytools && make -C tools/bin-assemble + + - name: Build wolfboot + run: | + make MCUXSDK=1 MCUXPRESSO="$GITHUB_WORKSPACE/mcuxpresso-sdk/mcuxsdk" MCUXPRESSO_CMSIS="$GITHUB_WORKSPACE/CMSIS_5/CMSIS" ${{inputs.make-args}} V=1 diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index d173cdec91..8090d3c429 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -216,6 +216,18 @@ jobs: arch: arm config-file: ./config/examples/mcxw-tz.config + nxp_mcxn_test: + uses: ./.github/workflows/test-build-mcux-sdk-manifests.yml + with: + arch: arm + config-file: ./config/examples/mcxn.config + + nxp_mcxn_tz_test: + uses: ./.github/workflows/test-build-mcux-sdk-manifests.yml + with: + arch: arm + config-file: ./config/examples/mcxn-tz.config + nxp_s32k142_test: uses: ./.github/workflows/test-build.yml with: From d6bd79137434284a36debe4f5f04eb203bb1b0d4 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 22 Jan 2026 19:06:19 +0100 Subject: [PATCH 04/10] Remove temporary comment --- test-app/app_mcxn.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/test-app/app_mcxn.c b/test-app/app_mcxn.c index 9a0a97f85b..db8f6195fb 100644 --- a/test-app/app_mcxn.c +++ b/test-app/app_mcxn.c @@ -1,6 +1,4 @@ /* app_mcxn.c - * - * Minimal test application scaffold for NXP MCXN targets. * * Copyright (C) 2025 wolfSSL Inc. * From a3efac8325da7159cab977e2a4f1e394b5686a29 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 22 Jan 2026 23:24:45 +0100 Subject: [PATCH 05/10] Fix pkcs11 builds --- arch.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch.mk b/arch.mk index da526591b1..b1a4762d03 100644 --- a/arch.mk +++ b/arch.mk @@ -339,7 +339,8 @@ else ifeq ($(WOLFCRYPT_TZ),1) CORTEXM_ARM_EXTRA_OBJS= CORTEXM_ARM_EXTRA_CFLAGS= - SECURE_OBJS+=./src/wc_callable.o $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/random.o + SECURE_OBJS+=./src/wc_callable.o + WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/random.o CFLAGS+=-DWOLFCRYPT_SECURE_MODE SECURE_LDFLAGS+=-Wl,--cmse-implib -Wl,--out-implib=./src/wc_secure_calls.o endif From b1528bacb4d6ecc6b5b34cab1118f59ed6f01ea8 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 22 Jan 2026 23:34:06 +0100 Subject: [PATCH 06/10] Add board name to github workflows --- .github/workflows/test-build-mcux-sdk-manifests.yml | 2 +- .github/workflows/test-configs.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-build-mcux-sdk-manifests.yml b/.github/workflows/test-build-mcux-sdk-manifests.yml index bf57ba28ba..274b5093df 100644 --- a/.github/workflows/test-build-mcux-sdk-manifests.yml +++ b/.github/workflows/test-build-mcux-sdk-manifests.yml @@ -1,4 +1,4 @@ -name: Wolfboot Reusable Build Workflow for MCUXpresso SDK +name: Wolfboot Reusable Build Workflow for west-based MCUXpresso SDK on: diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index 8090d3c429..8651d5f191 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -221,12 +221,14 @@ jobs: with: arch: arm config-file: ./config/examples/mcxn.config + board-name: frdmmcxn947 nxp_mcxn_tz_test: uses: ./.github/workflows/test-build-mcux-sdk-manifests.yml with: arch: arm config-file: ./config/examples/mcxn-tz.config + board-name: frdmmcxn947 nxp_s32k142_test: uses: ./.github/workflows/test-build.yml From a4b2a9c42810080c7b4fb622868773bfeb48b448 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Fri, 23 Jan 2026 01:10:33 +0100 Subject: [PATCH 07/10] Fix west install in GitHub action --- .github/workflows/test-build-mcux-sdk-manifests.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-build-mcux-sdk-manifests.yml b/.github/workflows/test-build-mcux-sdk-manifests.yml index 274b5093df..2fb5abf4f7 100644 --- a/.github/workflows/test-build-mcux-sdk-manifests.yml +++ b/.github/workflows/test-build-mcux-sdk-manifests.yml @@ -83,12 +83,16 @@ jobs: - name: Install software run: | - sudo apt-get install -y gcc-arm-none-eabi west + sudo apt-get install -y gcc-arm-none-eabi - name: Setup MCUXpresso SDK run: | + python -m venv venv + source venv/bin/activate + pip install west west init -m https://github.com/nxp-mcuxpresso/mcuxsdk-manifests.git mcuxpresso-sdk cd mcuxpresso-sdk + sed -i '/se_hostlib\|emwin/d' manifests/boards/${{inputs.board-name}}.yml west update_board --set board ${{inputs.board-name}} - name: make distclean From f9b59288d77dd175cb11137def8ff26bc273a80e Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Fri, 23 Jan 2026 01:30:15 +0100 Subject: [PATCH 08/10] Add caching to GitHub workflows --- .github/workflows/test-build-mcux-sdk-manifests.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test-build-mcux-sdk-manifests.yml b/.github/workflows/test-build-mcux-sdk-manifests.yml index 2fb5abf4f7..50b785cf62 100644 --- a/.github/workflows/test-build-mcux-sdk-manifests.yml +++ b/.github/workflows/test-build-mcux-sdk-manifests.yml @@ -85,7 +85,17 @@ jobs: run: | sudo apt-get install -y gcc-arm-none-eabi + - name: Cache MCUXpresso SDK + id: cache-mcuxpresso + uses: actions/cache@v4 + with: + path: | + mcuxpresso-sdk + venv + key: mcuxpresso-sdk-${{inputs.board-name}}-${{hashFiles('.github/workflows/test-build-mcux-sdk-manifests.yml')}} + - name: Setup MCUXpresso SDK + if: steps.cache-mcuxpresso.outputs.cache-hit != 'true' run: | python -m venv venv source venv/bin/activate From 11ea2a336868a59817dd9a419afa598891cf3e04 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Fri, 23 Jan 2026 02:33:34 +0100 Subject: [PATCH 09/10] Add documentation --- docs/Targets.md | 114 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/docs/Targets.md b/docs/Targets.md index 2adf8dfe2f..98cea1d58d 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -23,6 +23,7 @@ This README describes configuration of supported targets. * [NXP LS1028A](#nxp-ls1028a) * [NXP MCXA153](#nxp-mcxa153) * [NXP MCXW716](#nxp-mcxw716) +* [NXP MCXN947](#nxp-mcxn947) * [NXP S32K1XX](#nxp-s32k1xx) * [NXP P1021 PPC](#nxp-qoriq-p1021-ppc) * [NXP T1024 PPC](#nxp-qoriq-t1024-ppc) @@ -2873,6 +2874,8 @@ cp config/examples/mcxw.config .config` make ``` +We also provide a TrustZone configuration at `config/examples/mcxw-tz.config`. + ### MCX W: Loading the firmware The NXP Freedom MCX W board debugger comes loaded with MCU Link, but it can be updated to JLink. @@ -2947,6 +2950,117 @@ c ``` +## NXP MCXN947 + +The NXP MCXN947 is a dual-core Cortex-M33 microcontroller. The support has been +tested on the FRDM-MCXN947 board, with the on-board MCU-Link configured in +JLink 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 +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 frdmmcxn947 + +deactivate +``` + +### MCX N: Configuring and compiling + +Copy the example configuration file and build with make: + +```sh +cp config/examples/mcxn.config .config` +make +``` + +We also provide a TrustZone configuration at `config/examples/mcxn-tz.config`. + +### MCX N: Loading the firmware + +The NXP Freedom MCX N board debugger comes loaded with MCU Link, but it can be updated to JLink. +- Download and install the tool to update MCU Link to support jlink: +[@NXP: LinkServer for microcontrollers](https://www.nxp.com/design/design-center/software/development-software/mcuxpresso-software-and-tools-/linkserver-for-microcontrollers:LINKERSERVER#downloads) + +- put the rom bootloader in 'dfu' mode by adding a jumper in J21 + +- run `scripts/program_JLINK` to update the onboard debugger + +- when the update is complete, remove the jumper in J21 + +Use JLinkExe tool to upload the initial firmware: `JLinkExe -if swd -Device MCXN947_M33_0` + +At the Jlink prompt, type: + +``` +loadbin factory.bin 0 +``` + +Reset or power cycle the board. + +The RGB will light up blue to indicate version 1 of the firmware has been +staged. + +### MCX N: Testing firmware update + +1) Sign the test-app with version 2: + +```sh +./tools/keytools/sign --ecc256 test-app/image.bin wolfboot_signing_private_key.der 2 +``` + +2) Create a bin footer with wolfBoot trailer "BOOT" and "p" (ASCII for 0x70 == IMG_STATE_UPDATING): + +```sh +echo -n "pBOOT" > trigger_magic.bin +``` + +3) Assembly new factory update.bin (replace `0xAFFB` with the appropriate +address, which should be your `.config`'s `WOLFBOOT_PARTITION_SIZE` minus `5`): + +```sh +./tools/bin-assemble/bin-assemble \ + update.bin \ + 0x0 test-app/image_v2_signed.bin \ + 0xAFFB trigger_magic.bin +``` + +4) Flash update.bin to your `.config`'s `WOLFBOOT_PARTITION_UPDATE_ADDRESS` +(e.g. `loadbin update.bin 0x15000`). + +Once wolfBoot has performed validation of the partition and staged a firmware +with version > 1, the RGB LED will light up green. + +### MCX N: Debugging + +Debugging with JLink: + +Note: We include a `.gdbinit` in the wolfBoot root that loads the wolfboot and test-app elf files. + +In one terminal: `JLinkGDBServer -if swd -Device MCXN947_M33_0 -port 3333` + +In another terminal use `gdb`: + +``` +b main +mon reset +c +``` + + ## NXP S32K1XX The NXP S32K1xx family (S32K142, S32K144, S32K146, S32K148) are automotive-grade From b7902769be508481e3bb5a6cadb392dc15e446ae Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Fri, 23 Jan 2026 16:04:44 +0100 Subject: [PATCH 10/10] Fix docs venv command --- docs/Targets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Targets.md b/docs/Targets.md index 98cea1d58d..b0b0ec2656 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -2967,7 +2967,7 @@ cd ../NXP # Install west python -m venv west-venv -west-venv/bin/activate +source west-venv/bin/activate pip install west # Set up the repository