gojimmypi 2025-11-21 17:54:14 -08:00
parent 8b91362761
commit 1ad66e9a6b
No known key found for this signature in database
GPG Key ID: 3D684FA88DC3FAA8
18 changed files with 1227 additions and 319 deletions

View File

@ -7,9 +7,30 @@ on:
jobs:
wolfboot_dot_config_test:
name: cmake .config test (${{ matrix.target }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
target:
# These are exact file names from config/examples (including .config)
# - imx-rt1040.config # Disabled, requires NXP SDK
- sim.config
- stm32c0.config
- stm32f1.config
- stm32f4-small-blocks-uart-update.config
- stm32f7.config
- stm32g0.config
- stm32h5.config
- stm32h7.config
- stm32l0.config
- stm32l4-cube.config
- stm32l5.config
- stm32u5.config
- stm32wb.config
steps:
- uses: actions/checkout@v4
with:
@ -60,7 +81,6 @@ jobs:
echo "--- apt-mirrors.txt ---"
cat /etc/apt/apt-mirrors.txt || true
- name: Install requirements
run: |
# Run system updates and install toolchain
@ -73,31 +93,59 @@ jobs:
set -euo pipefail
LOG_FILE="run.log"
TARGET="${{ matrix.target }}"
TARGET="${TARGET%.config}"
TARGET="${TARGET%%-*}"
BUILD_DIR="build-${TARGET}"
LOG_FILE="run-${TARGET}.log"
KEYWORD="Config mode: dot"
echo "Saving output to $LOG_FILE"
echo "Fetch stm32h7 example .config"
cp ./config/examples/stm32h7.config ./.config
ls .config
cat .config
echo ""
echo "Target: ${TARGET}"
echo "Build dir: ${BUILD_DIR}"
echo "Saving output to ${LOG_FILE}"
echo "Clean"
rm -rf ./build-stm32h7
CONFIG_SRC="./config/examples/${{ matrix.target }}"
# Here we should see the .config file values read and displayed:
cmake -S . -B build-stm32h7 \
-DUSE_DOT_CONFIG=ON \
-DWOLFBOOT_TARGET=stm32h7 2>&1 | tee "$LOG_FILE"
# Config dot-config mode
if grep -q -- "$KEYWORD" "$LOG_FILE"; then
echo "Keyword found: $KEYWORD"
else
echo "Keyword not found: $KEYWORD" >&2
echo "Fetch ${TARGET} example .config (source: ${CONFIG_SRC})"
if [ ! -f "${CONFIG_SRC}" ]; then
echo "Missing config file: ${CONFIG_SRC}" >&2
exit 1
fi
# Sample build
cmake --build build-stm32h7 --parallel 8
cp "${CONFIG_SRC}" ./.config
ls .config
cat .config
echo ""
echo "Clean"
rm -rf "./${BUILD_DIR}"
# Here we should see the .config file values read and displayed:
cmake -S . -B "${BUILD_DIR}" \
-DUSE_DOT_CONFIG=ON \
-DWOLFBOOT_TARGET="${TARGET}" 2>&1 | tee "${LOG_FILE}"
# Config dot-config mode
if grep -q -- "${KEYWORD}" "${LOG_FILE}"; then
echo "Keyword found: ${KEYWORD}"
else
echo "Keyword not found: ${KEYWORD}" >&2
exit 1
fi
# First: build keygen explicitly and inspect it
echo "Building keygen_build for ${TARGET}"
cmake --build "${BUILD_DIR}" --parallel 1 --target keygen_build
if [ -f "${BUILD_DIR}/keygen" ]; then
echo "Inspecting keygen:"
ls -l "${BUILD_DIR}/keygen"
file "${BUILD_DIR}/keygen" || true
else
echo "keygen not found at ${BUILD_DIR}/keygen"
fi
# Now run the normal build
echo "Running full build"
cmake --build "${BUILD_DIR}" --parallel 8

View File

@ -4,7 +4,7 @@ on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]
branches: [ "*" ]
jobs:
macos-cmake:
@ -15,7 +15,20 @@ jobs:
strategy:
fail-fast: false
matrix:
target: [stm32l4, stm32h7, stm32c0, stm32g0]
target:
# - imx-rt # Disabled, requires NXP SDK
- stm32c0
- stm32f1
- stm32f4
- stm32f7
- stm32g0
- stm32h5
- stm32h7
- stm32l0
- stm32l4
- stm32l5
- stm32u5
- stm32wb
env:
HOMEBREW_NO_AUTO_UPDATE: "1" # avoid updating taps during install

View File

@ -2,7 +2,7 @@ name: WolfBoot CMake Presets Build
on:
push:
# TODO: branches: [ 'master', 'main', 'release/**' ]
branches: [ 'master', 'main', 'release/**' ]
branches: [ '*' ]
pull_request:
branches: [ "*" ]
@ -23,9 +23,21 @@ jobs:
fail-fast: false
matrix:
target:
- stm32l4
- stm32h7
- sim
# - imx-rt # Disabled, requires NXP SDK
- stm32c0
- stm32f1
- stm32f4
- stm32f7
- stm32g0
- stm32h5
- stm32h7
- stm32l0
- stm32l4
- stm32l5
- stm32u5
- stm32wb
include:
# Optional per-target cache variables you might want to pass later.
# Keep empty for now to avoid guessing addresses.
@ -48,6 +60,7 @@ jobs:
# ARM GCC toolchain (adds the bin dir to PATH)
- name: Set up ARM none-eabi GCC 14.x
if: matrix.target != 'sim'
uses: carlosperate/arm-none-eabi-gcc-action@v1
with:
release: "14.2.Rel1" # <-- use 'release', not 'version'

View File

@ -1,14 +1,42 @@
# Tests the /tools/scripts/wolfboot_cmake_full_build.sh
# See also test-build-cmake-presets.yml
# Presets are found in /CMakePresets.json
#
name: wolfboot CMake Script
on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]
branches: [ "*" ]
jobs:
wolfboot_build_script_test:
name: Build wolfBoot (target=${{ matrix.target }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
target:
- "~No config (wolfBoot sim)"
# - imx-rt # Disabled, requires NXP SDK
- stm32c0
- stm32f1
- stm32f4
- stm32f7
- stm32g0
- stm32h5
- stm32h7
- stm32l0
- stm32l4
- stm32l5
- stm32u5
- stm32wb
# add more targets here later, e.g.:
# - stm32v8
# - sim options, etc
steps:
- uses: actions/checkout@v4
with:
@ -59,19 +87,23 @@ jobs:
echo "--- apt-mirrors.txt ---"
cat /etc/apt/apt-mirrors.txt || true
- name: Install requirements
run: |
sudo apt-get update
sudo apt-get install -y gcc-arm-none-eabi gcc-powerpc-linux-gnu cmake
- name: Run wolfboot_build script
- name: View Presets
run: |
rm -rf ./build
# Use CMake to list all presets defined in CMakePresets.json
echo "All presets:"
cmake -S . -B build --list-presets=configure
chmod +x ./tools/scripts/wolfboot_cmake_full_build.sh
./tools/scripts/wolfboot_cmake_full_build.sh --CLEAN "stm32l4"
./tools/scripts/wolfboot_cmake_full_build.sh --target "stm32l4"
- name: Run wolfboot_cmake_full_build script
run: |
rm -rf ./build
rm -rf ./build-"${{ matrix.target }}"
./tools/scripts/wolfboot_cmake_full_build.sh --CLEAN "stm32g0"
./tools/scripts/wolfboot_cmake_full_build.sh --target "stm32g0"
./tools/scripts/wolfboot_cmake_full_build.sh --CLEAN "${{ matrix.target }}"
./tools/scripts/wolfboot_cmake_full_build.sh --target "${{ matrix.target }}"

View File

@ -4,7 +4,7 @@ on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]
branches: [ "*" ]
permissions:
contents: read
@ -20,9 +20,20 @@ jobs:
fail-fast: false
matrix:
target:
- stm32l4
- stm32h7
# - imx-rt # Disabled, requires NXP SDK
- stm32c0
- stm32f1
- stm32f4
- stm32f7
- stm32g0
- stm32h5
- stm32h7
- stm32l0
- stm32l4
- stm32l5
- stm32u5
- stm32wb
include:
# Optional per-target cache variables you might want to pass later.
# Keep empty for now to avoid guessing addresses.

View File

@ -272,6 +272,20 @@ endif()
message(STATUS "Host CC: ${HOST_CC}")
message(STATUS "Host compiler treated as MSVC: ${HOST_IS_MSVC}")
if(WOLFBOOT_TARGET STREQUAL "imx_rt")
# This target depends on the NXP MCUXpresso SDK for EVKB-IMXRT1040.
# Without it, the build will fail anyway on missing fsl_* headers.
set(IMXRT_SDK_ROOT "" CACHE PATH "Path to MCUXpresso SDK for EVKB-IMXRT1040")
if(NOT IMXRT_SDK_ROOT OR NOT EXISTS "${IMXRT_SDK_ROOT}")
message(FATAL_ERROR
"WOLFBOOT_TARGET=imx_rt requires IMXRT_SDK_ROOT to point to a valid "
"MCUXpresso SDK for EVKB-IMXRT1040 (fsl_cache.h, etc.). "
"You currently do not have this SDK installed."
)
endif()
endif()
#---------------------------------------------------------------------------------------------
# Common includes/defines for host tools
#---------------------------------------------------------------------------------------------
@ -365,7 +379,35 @@ if(NOT DEFINED WOLFBOOT_SECTOR_SIZE)
endif()
if(NOT DEFINED ARM_TARGETS)
list(APPEND ARM_TARGETS cypsoc6 imx kinetis lpc54606j512 mcxa mcxw nrf52 nrf52840 nrf5340 nrf5340_net rp2350 sama5d3 same51 stm32c0 stm32f1 stm32f4 stm32f7 stm32g0 stm32h5 stm32h7 stm32l0 stm32l4 stm32l5 stm32u5 stm32wb ti zynqmp)
list(APPEND ARM_TARGETS cypsoc6
imx
imx_rt
kinetis
lpc54606j512
mcxa
mcxw
nrf52
nrf52840
nrf5340
nrf5340_net
rp2350
sama5d3
same51
stm32c0
stm32f1
stm32f4
stm32f7
stm32g0
stm32h5
stm32h7
stm32l0
stm32l4
stm32l5
stm32u5
stm32wb
ti
zynqmp
)
set(ARM_TARGETS
"${ARM_TARGETS}"
CACHE INTERNAL "")
@ -380,9 +422,9 @@ endif()
if("${WOLFBOOT_TARGET}" IN_LIST ARM_TARGETS)
set(ARCH ARM)
elseif(WOLFBOOT_TARGET STREQUAL "x86_64_efi")
elseif("${WOLFBOOT_TARGET}" STREQUAL "x86_64_efi")
set(ARCH x86_64)
elseif(WOLFBOOT_TARGET STREQUAL "sim")
elseif("${WOLFBOOT_TARGET}" STREQUAL "sim")
set(ARCH sim)
else()
message(FATAL_ERROR "Unable to configure ARCH for target ${WOLFBOOT_TARGET}")
@ -549,6 +591,7 @@ set(UPDATE_SOURCES src/update_flash.c)
# Default flash offset
if(NOT DEFINED ARCH_FLASH_OFFSET)
message(STATUS "WARNING: ARCH_FLASH_OFFSET not defined, setting to default 0x0")
set(ARCH_FLASH_OFFSET 0x0)
endif()
@ -916,21 +959,29 @@ list(TRANSFORM WOLFBOOT_SOURCES PREPEND ${WOLFBOOT_ROOT}/)
# Hash settings
#---------------------------------------------------------------------------------------------
if(HASH STREQUAL "SHA256")
list(APPEND WOLFBOOT_DEFS WOLFBOOT_HASH_SHA256)
list(APPEND WOLFBOOT_DEFS WOLFBOOT_HASH_SHA256)
list(APPEND SIGN_OPTIONS WOLFBOOT_HASH_SHA256)
message(STATUS "Using SHA256 hash")
endif()
if(HASH STREQUAL "SHA384")
list(APPEND WOLFBOOT_DEFS WOLFBOOT_HASH_SHA384)
list(APPEND WOLFBOOT_DEFS WOLFBOOT_HASH_SHA384)
list(APPEND SIGN_OPTIONS WOLFBOOT_HASH_SHA384)
list(APPEND KEYTOOL_OPTIONS --sha384)
# Note: the keygen tool in this tree does not accept a --sha384 CLI flag.
# Hash selection is controlled via WOLFBOOT_HASH_SHA384 in the image header,
# so do not append a hash option to KEYTOOL_OPTIONS here.
# list(APPEND KEYTOOL_OPTIONS --sha384)
message(STATUS "Using SHA384 hash")
endif()
if(HASH STREQUAL "SHA3")
list(APPEND WOLFBOOT_DEFS WOLFBOOT_HASH_SHA3_384)
list(APPEND WOLFBOOT_DEFS WOLFBOOT_HASH_SHA3_384)
list(APPEND SIGN_OPTIONS WOLFBOOT_HASH_SHA3_384)
list(APPEND KEYTOOL_OPTIONS --sha3)
# Note: the keygen tool in this tree does not accept a --sha3 CLI flag.
# Hash selection is controlled via WOLFBOOT_HASH_SHA3_384 in the image header,
# so do not append a hash option to KEYTOOL_OPTIONS here.
# list(APPEND KEYTOOL_OPTIONS --sha3)
message(STATUS "Using SHA3_384 hash")
endif()
#---------------------------------------------------------------------------------------------
@ -1225,26 +1276,26 @@ endif()
add_subdirectory(lib)
if (TARGET wolfcrypt)
set(WOLFSSL_TGT wolfcrypt)
elseif (TARGET wolfssl)
set(WOLFSSL_TGT wolfssl)
else()
message(FATAL_ERROR "wolfSSL submodule did not define a 'wolfcrypt' or 'wolfssl' target.")
endif()
message(STATUS "Using wolfSSL target: ${WOLFSSL_TGT}")
if(TARGET wolfcrypt)
set(WOLFSSL_TGT wolfcrypt)
elseif(TARGET wolfssl)
set(WOLFSSL_TGT wolfssl)
else()
message(FATAL_ERROR "wolfSSL submodule did not define a 'wolfcrypt' or 'wolfssl' target.")
endif()
message(STATUS "Using wolfSSL target: ${WOLFSSL_TGT}")
if (TARGET ${WOLFSSL_TGT})
if(TARGET ${WOLFSSL_TGT})
target_compile_definitions(${WOLFSSL_TGT} PRIVATE NOMINMAX WIN32_LEAN_AND_MEAN)
target_compile_options(${WOLFSSL_TGT} PRIVATE
$<$<C_COMPILER_ID:MSVC>:/Umin>
$<$<C_COMPILER_ID:MSVC>:/Umax>
$<$<C_COMPILER_ID:MSVC>:/USIGN>
$<$<C_COMPILER_ID:MSVC>:/UHASH>
$<$<C_COMPILER_ID:MSVC>:/Zc:preprocessor>
$<$<C_COMPILER_ID:MSVC>:/Umin>
$<$<C_COMPILER_ID:MSVC>:/Umax>
$<$<C_COMPILER_ID:MSVC>:/USIGN>
$<$<C_COMPILER_ID:MSVC>:/UHASH>
$<$<C_COMPILER_ID:MSVC>:/Zc:preprocessor>
)
endif()
endif() # TARGET ${WOLFSSL_TGT}
if(BUILD_TEST_APPS OR BUILD_IMAGE)
message(STATUS "Building wolfBoot image")

View File

@ -63,7 +63,17 @@
"inherits": "base_build_presetName",
"cacheVariables": {
"WOLFBOOT_CONFIG_MODE": "preset",
"WOLFBOOT_HAS_BASE_PRESET": true
"WOLFBOOT_HAS_BASE_PRESET": true,
"BUILD_TEST_APPS": "ON"
}
},
{
"name": "imx",
"hidden": true,
"generator": "Ninja",
"cacheVariables": {
"ARCH": "ARM",
"CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake"
}
},
{
@ -71,6 +81,8 @@
"hidden": true,
"generator": "Ninja",
"cacheVariables": {
"ARCH": "ARM",
"CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake"
}
},
{
@ -91,22 +103,42 @@
}
},
{
"name": "vs-debug-trace",
"displayName": "VS Debug Trace (STM32H7)",
"inherits": [
"base",
"stm32h7"
],
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_VERBOSE_MAKEFILE": "ON",
"CMAKE_FIND_DEBUG_MODE": "ON"
}
"name": "imx_rt",
"displayName": "imx_rt",
"inherits": [
"base",
"imx",
"sign_hash_config"
],
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-imx_rt",
"cacheVariables": {
"ARCH": "ARM",
"WOLFBOOT_TARGET": "imx_rt",
"MCUXSDK": "OFF",
"DEBUG": "OFF",
"CORTEX_M0": "OFF",
"NO_ASM": "OFF",
"NO_MPU": "ON",
"EXT_FLASH": "OFF",
"SPI_FLASH": "OFF",
"ALLOW_DOWNGRADE": "OFF",
"NVM_FLASH_WRITEONCE": "ON",
"WOLFBOOT_VERSION": "OFF",
"SPMATH": "ON",
"RAM_CODE": "ON",
"DUALBANK_SWAP": "OFF",
"WOLFBOOT_PARTITION_SIZE": "0x20000",
"WOLFBOOT_SECTOR_SIZE": "0x1000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x60010000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x60030000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x60050000",
"WOLFBOOT_SMALL_STACK": "ON"
}
},
{
"name": "stm32c0",
"displayName": "STM32C0",
"displayName": "stm32c0",
"inherits": [
"base",
"sign_hash_config",
@ -128,9 +160,7 @@
"WOLFBOOT_SECTOR_SIZE": "0x800",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08002800",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08005000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x08007800",
"CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake",
"BUILD_TEST_APPS": "ON"
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x08007800"
}
},
{
@ -138,7 +168,8 @@
"displayName": "stm32f1",
"inherits": [
"base",
"stm32"
"stm32",
"sign_hash_config"
],
"cacheVariables": {
"WOLFBOOT_TARGET": "stm32f1",
@ -150,9 +181,75 @@
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08009400",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x0800F800",
"WOLFBOOT_PARTITION_SIZE": "0x6400",
"WOLFBOOT_SECTOR_SIZE": "0x400",
"CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake",
"BUILD_TEST_APPS": "ON"
"WOLFBOOT_SECTOR_SIZE": "0x400"
}
},
{
"name": "stm32f4",
"displayName": "stm32f4",
"inherits": [
"base",
"stm32",
"sign_hash_config"
],
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-stm32f4",
"cacheVariables": {
"WOLFBOOT_TARGET": "stm32f4",
"NO_ASM": "OFF",
"EXT_FLASH": "OFF",
"SPI_FLASH": "OFF",
"NO_XIP": "OFF",
"UART_FLASH": "ON",
"ALLOW_DOWNGRADE": "OFF",
"NVM_FLASH_WRITEONCE": "OFF",
"WOLFBOOT_VERSION": "OFF",
"SPMATH": "ON",
"RAM_CODE": "OFF",
"WOLFBOOT_PARTITION_SIZE": "0x4000",
"WOLFBOOT_SECTOR_SIZE": "0x4000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x8000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x00000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x4000",
"WOLFBOOT_LOAD_ADDRESS": "0x200000",
"WOLFBOOT_LOAD_DTS_ADDRESS": "0x400000",
"CLOCK_SPEED": "160000000",
"STM32_PLLM": "8",
"STM32_PLLN": "336",
"STM32_PLLP": "2",
"STM32_PLLQ": "7"
}
},
{
"name": "stm32f7",
"displayName": "stm32f7",
"inherits": [
"base",
"stm32",
"sign_hash_config"
],
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-stm32f7",
"cacheVariables": {
"ARCH": "ARM",
"WOLFBOOT_TARGET": "stm32f7",
"DEBUG": "OFF",
"VTOR": "ON",
"CORTEX_M0": "OFF",
"NO_ASM": "OFF",
"EXT_FLASH": "OFF",
"SPI_FLASH": "OFF",
"ALLOW_DOWNGRADE": "OFF",
"NVM_FLASH_WRITEONCE": "OFF",
"WOLFBOOT_VERSION": "ON",
"V": "OFF",
"SPMATH": "ON",
"RAM_CODE": "ON",
"WOLFBOOT_PARTITION_SIZE": "0x60000",
"WOLFBOOT_SECTOR_SIZE": "0x20000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x8020000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x8080000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x80E0000"
}
},
{
@ -160,8 +257,8 @@
"displayName": "stm32g0",
"inherits": [
"base",
"sign_hash_config",
"stm32"
"stm32",
"sign_hash_config"
],
"cacheVariables": {
"WOLFBOOT_TARGET": "stm32g0",
@ -178,25 +275,68 @@
"WOLFBOOT_PARTITION_SIZE": "0xB000",
"WOLFBOOT_SECTOR_SIZE": "0x800",
"ARCH_FLASH_OFFSET": "0x08000000",
"WOLFBOOT_ORIGIN": "0x08000000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08008000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08013000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x0801E000",
"BUILD_TEST_APPS": "ON"
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x0801E000"
}
},
{
"name": "stm32h5",
"displayName": "stm32h5",
"inherits": [
"base",
"stm32",
"sign_hash_config"
],
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-stm32h5",
"cacheVariables": {
"BUILD_TEST_APPS": "OFF",
"ARCH": "ARM",
"TZEN": "ON",
"WOLFBOOT_TARGET": "stm32h5",
"DEBUG": "OFF",
"VTOR": "ON",
"CORTEX_M0": "OFF",
"CORTEX_M33": "ON",
"NO_ASM": "OFF",
"NO_MPU": "ON",
"EXT_FLASH": "OFF",
"SPI_FLASH": "OFF",
"ALLOW_DOWNGRADE": "OFF",
"NVM_FLASH_WRITEONCE": "ON",
"WOLFBOOT_VERSION": "ON",
"V": "OFF",
"SPMATH": "ON",
"RAM_CODE": "OFF",
"DUALBANK_SWAP": "OFF",
"WOLFBOOT_PARTITION_SIZE": "0xA0000",
"WOLFBOOT_SECTOR_SIZE": "0x2000",
"WOLFBOOT_KEYVAULT_ADDRESS": "0x0C040000",
"WOLFBOOT_KEYVAULT_SIZE": "0x1C000",
"WOLFBOOT_NSC_ADDRESS": "0x0C05C000",
"WOLFBOOT_NSC_SIZE": "0x4000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08060000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08100000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x081A0000",
"FLAGS_HOME": "OFF",
"DISABLE_BACKUP": "OFF",
"IMAGE_HEADER_SIZE": "1024",
"ARMORED": "ON"
}
},
{
"name": "stm32h7",
"displayName": "STM32H7",
"displayName": "stm32h7",
"inherits": [
"base",
"sign_hash_config",
"stm32"
"stm32",
"sign_hash_config"
],
"generator": "Ninja",
"cacheVariables": {
"WOLFBOOT_TARGET": "stm32h7",
"BUILD_TEST_APPS": "yes",
"ARCH": "ARM",
"DEBUG_UART": "OFF",
"NO_ASM": "OFF",
"EXT_FLASH": "OFF",
@ -210,25 +350,60 @@
"RAM_CODE": "OFF",
"WOLFBOOT_PARTITION_SIZE": "0xD0000",
"WOLFBOOT_SECTOR_SIZE": "0x20000",
"ARCH_FLASH_OFFSET": "0x08000000",
"WOLFBOOT_ORIGIN": "0x08000000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x8020000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x80F0000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x81C0000"
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x81C0000",
"DEBUG": "OFF",
"VTOR": "ON",
"V": "OFF",
"DUALBANK_SWAP": "OFF"
}
},
{
"name": "stm32l0",
"displayName": "stm32l0",
"inherits": [
"base",
"stm32",
"sign_hash_config"
],
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-stm32l0",
"cacheVariables": {
"ARCH": "ARM",
"WOLFBOOT_TARGET": "stm32l0",
"SIGN": "ED25519",
"NO_ASM": "OFF",
"EXT_FLASH": "OFF",
"SPI_FLASH": "OFF",
"ALLOW_DOWNGRADE": "OFF",
"NVM_FLASH_WRITEONCE": "ON",
"FLAGS_INVERT": "ON",
"WOLFBOOT_VERSION": "OFF",
"SPMATH": "ON",
"RAM_CODE": "OFF",
"WOLFBOOT_PARTITION_SIZE": "0x10000",
"WOLFBOOT_SECTOR_SIZE": "0x1000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x8000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x18000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x28000"
}
},
{
"name": "stm32l4",
"displayName": "STM32L4",
"displayName": "stm32l4",
"inherits": [
"base",
"sign_hash_config",
"stm32"
"stm32",
"sign_hash_config"
],
"environment": {
"VSCMD_DEBUG": "3"
},
"cacheVariables": {
"WOLFBOOT_TARGET": "stm32l4",
"ARCH": "ARM",
"VTOR": "ON",
"NO_ASM": "OFF",
"EXT_FLASH": "OFF",
@ -243,9 +418,114 @@
"WOLFBOOT_PARTITION_SIZE": "0x7A000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x0800A000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08084000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x080FE000",
"CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake",
"BUILD_TEST_APPS": "ON"
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x080FE000"
}
},
{
"name": "stm32l5",
"displayName": "stm32l5",
"inherits": [
"base",
"stm32",
"sign_hash_config"
],
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-stm32l5",
"cacheVariables": {
"BUILD_TEST_APPS": "OFF",
"WOLFBOOT_TARGET": "stm32l5",
"ARCH_FLASH_OFFSET": "0x08000000",
"WOLFBOOT_NSC_ADDRESS": "0x08110000",
"WOLFBOOT_NSC_SIZE": "0x00010000",
"NO_ASM": "OFF",
"NO_MPU": "ON",
"EXT_FLASH": "OFF",
"SPI_FLASH": "OFF",
"ALLOW_DOWNGRADE": "OFF",
"NVM_FLASH_WRITEONCE": "ON",
"WOLFBOOT_VERSION": "ON",
"SPMATH": "ON",
"RAM_CODE": "OFF",
"WOLFBOOT_PARTITION_SIZE": "0x30000",
"WOLFBOOT_SECTOR_SIZE": "0x2000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08010000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08110000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0xFFFFFFFF",
"IMAGE_HEADER_SIZE": "1024"
}
},
{
"name": "stm32u5",
"displayName": "stm32u5",
"inherits": [
"base",
"stm32",
"sign_hash_config"
],
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-stm32u5",
"cacheVariables": {
"ARCH": "ARM",
"TZEN": "ON",
"WOLFBOOT_TARGET": "stm32u5",
"NO_ASM": "OFF",
"NO_MPU": "ON",
"EXT_FLASH": "OFF",
"SPI_FLASH": "OFF",
"QSPI_FLASH": "OFF",
"OCTOSPI_FLASH": "OFF",
"ALLOW_DOWNGRADE": "OFF",
"NVM_FLASH_WRITEONCE": "ON",
"WOLFBOOT_VERSION": "ON",
"SPMATH": "ON",
"RAM_CODE": "OFF",
"DUALBANK_SWAP": "OFF",
"WOLFBOOT_PARTITION_SIZE": "0x1F800",
"WOLFBOOT_SECTOR_SIZE": "0x800",
"WOLFBOOT_KEYVAULT_ADDRESS": "0x0C020000",
"WOLFBOOT_KEYVAULT_SIZE": "0x18000",
"WOLFBOOT_NSC_ADDRESS": "0x0C038000",
"WOLFBOOT_NSC_SIZE": "0x8000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08040000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x805F800",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x0807F000",
"FLAGS_HOME": "OFF",
"DISABLE_BACKUP": "OFF"
}
},
{
"name": "stm32wb",
"displayName": "stm32wb",
"inherits": [
"base",
"stm32",
"sign_hash_config"
],
"generator": "Ninja",
"binaryDir": "${sourceDir}/build-stm32wb",
"cacheVariables": {
"BUILD_TEST_APPS": "OFF",
"WOLFBOOT_TARGET": "stm32wb",
"WOLFBOOT_SECTOR_SIZE": "0x1000",
"WOLFBOOT_PARTITION_SIZE": "0x20000",
"WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08008000",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08028000",
"WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x08048000",
"NVM_FLASH_WRITEONCE": "ON"
}
},
{
"name": "vs-debug-trace",
"displayName": "VS Debug Trace (STM32H7)",
"inherits": [
"base",
"stm32h7"
],
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_VERBOSE_MAKEFILE": "ON",
"CMAKE_FIND_DEBUG_MODE": "ON"
}
}
],
@ -259,6 +539,15 @@
"all"
]
},
{
"name": "imx_rt",
"configurePreset": "imx_rt",
"jobs": 4,
"verbose": true,
"targets": [
"all"
]
},
{
"name": "stm32c0",
"configurePreset": "stm32c0",
@ -277,6 +566,24 @@
"all"
]
},
{
"name": "stm32f4",
"configurePreset": "stm32f4",
"jobs": 4,
"verbose": true,
"targets": [
"all"
]
},
{
"name": "stm32f7",
"configurePreset": "stm32f7",
"jobs": 4,
"verbose": true,
"targets": [
"all"
]
},
{
"name": "stm32g0",
"configurePreset": "stm32g0",
@ -286,6 +593,15 @@
"all"
]
},
{
"name": "stm32h5",
"configurePreset": "stm32h5",
"jobs": 4,
"verbose": true,
"targets": [
"all"
]
},
{
"name": "stm32h7",
"configurePreset": "stm32h7",
@ -295,6 +611,15 @@
"all"
]
},
{
"name": "stm32l0",
"configurePreset": "stm32l0",
"jobs": 4,
"verbose": true,
"targets": [
"all"
]
},
{
"name": "stm32l4",
"configurePreset": "stm32l4",
@ -304,6 +629,33 @@
"all"
]
},
{
"name": "stm32l5",
"configurePreset": "stm32l5",
"jobs": 4,
"verbose": true,
"targets": [
"all"
]
},
{
"name": "stm32u5",
"configurePreset": "stm32u5",
"jobs": 4,
"verbose": true,
"targets": [
"all"
]
},
{
"name": "stm32wb",
"configurePreset": "stm32wb",
"jobs": 4,
"verbose": true,
"targets": [
"all"
]
},
{
"name": "vs-debug-trace",
"configurePreset": "vs-debug-trace",

View File

@ -1,4 +1,4 @@
# VS Code wolfBoot Project
# VS Code wolfBoot Project
CMake presets are support in VS Code. See also details in the [cmake/README.md](../../cmake/README).
@ -24,6 +24,32 @@ code wolfBoot.code-workspace
If all of the prerequisites are NOT installed, see the [install.sh](./install.sh) script.
## Windows
Windows users may need one of these:
- [Visual Studio 2022](https://visualstudio.microsoft.com/)
- [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/). See `C:\Program Files(x86)\Windows kits`.
The MSVC kit may be needed if VS 2022 is not installed.
Select `View` - `Command Palette`, search for CMake: Select a Compiler
See also: CMake: Delete Cache and Reconfigure
### Launch VS Code from VS 2022 Command prompt.
Delete any existing `build` or `build-[target]` directories as needed.
Open a VS 2022 Developer command prompt.
From the command prompt, open the `wolfBoot.code-workspace` VS Code workspace:
```dos
cd c:\workspace\wolfboot-%USERNAME%
code ./IDE/VSCode/wolfBoot.code-workspace
```
-----
## Additional Settings

View File

@ -46,7 +46,8 @@ echo "Starting $0 from $(pwd -P)"
# End common dir init
pwd
git clone https://github.com/gojimmypi/wolfBoot.git
git clone https://github.com/master/wolfBoot.git
cd wolfBoot
git submodule update --init

View File

@ -17,7 +17,7 @@ RAM_CODE?=1
DUALBANK_SWAP?=0
# Enable this feature for secure memory support
# Makes the flash sectors for the bootloader unaccessible from the application
# Makes the flash sectors for the bootloader inaccessible from the application
# Requires using the STM32CubeProgrammer to set FLASH_SECR -> SEC_SIZE pages
#CFLAGS_EXTRA+=-DFLASH_SECURABLE_MEMORY_SUPPORT

View File

@ -1,4 +1,4 @@
# Post-Quantum Signatures
# Post-Quantum Signatures
wolfBoot is continuously adding support for post-quantum (PQ) signature
algorithms as they mature. At present, support has been added for three NIST

View File

@ -1,4 +1,4 @@
## wolfBoot Docs and Platform-Specific Details
## wolfBoot Docs and Platform-Specific Details
See also: [wolfBoot Product Overview](https://www.wolfssl.com/products/wolfboot/) and [wolfBoot Manual](https://www.wolfssl.com/documentation/manuals/wolfboot/).

View File

@ -1,148 +0,0 @@
## wolfBoot for STM32 devices
The default [Makefile](../Makefile) needs at least the `gcc-arm-none-eabi`.
```bash
sudo apt update
sudo apt install -y build-essential gcc-arm-none-eabi binutils-arm-none-eabi
# optional (often handy): gdb-multiarch or gdb-arm-none-eabi
arm-none-eabi-gcc --version # should print the version
```
A device toolchain _also_ needs to be installed. For example without the appropriate support files,
errors like this may otherwise be encountered:
```
[CC ARM] hal/stm32l4.o
hal/stm32l4.c:24:10: fatal error: stm32l4xx_hal.h: No such file or directory
24 | #include "stm32l4xx_hal.h"
| ^~~~~~~~~~~~~~~~~
```
There are a variety of other sources for device-specific toolchains, for example:
- [arm-gnu-toolchain-downloads](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads)
- [STM32CubeIDE Software](https://www.st.com/en/development-tools/stm32cubeide.html)
- [gnutoolchains.com](https://gnutoolchains.com/)
- [IAR Embedded Workbench](https://www.iar.com/embedded-development-tools/iar-embedded-workbench)
- [keil](https://www.keil.com/download/product/)
- [llvm](https://releases.llvm.org/download.html)
wolfBoot s supported on nearly every development environment.
## Quick Start
wolfBoot can be used with either `make` or `CMake`.
Be sure to include the submodules when cloning:
```bash
git clone https://github.com/wolfssl/wolfBoot.git
cd wolfBoot
git submodule update --init
```
### make
The `make` builds use the `.config` files. See [config/examples](../config/examples)
```
## Use make
# edit your .config or copy from config/examples
make
```
### CMake
```
## Use CMake
## See wolfboot_cmake_full_build.sh script:
./tools/scripts/wolfboot_cmake_full_build.sh --CLEAN
./tools/scripts/wolfboot_cmake_full_build.sh --CLEAN stm32h7
./tools/scripts/wolfboot_cmake_full_build.sh --target stm32h7
```
## VS Code
Windows users may need one of these:
- [Visual Studio 2022](https://visualstudio.microsoft.com/)
- [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/). See `C:\Program Files(x86)\Windows kits`.
#### Launch Stand-alone VS Code
The MSVC kit may be needed if VS 2022 is not installed.
Select `View` - `Command Palette`, search for CMake: Select a Compiler
See also: CMake: Delete Cache and Reconfigure
#### Launch VS Code from VS 2022 Command prompt.
Delete any existing `build` or `build-[target]` directories as needed.
Open a VS 2022 Developer command prompt.
From the command prompt, open the `wolfBoot.code-workspace` VS Code workspace:
```dos
cd c:\workspace\wolfboot-%USERNAME%
code ./IDE/VSCode/wolfBoot.code-workspace
```
### Visual Studio IDE
For the `Select Startup Item`, leave at default. Do not select `image`, wolfboot_name[], etc.
Right click on `CMakeLists.txt` and select `Delete Cache and Reconfigure`.
Right click on `CMakeLists.txt` and select `Build`.
### Visual Studio Command Prompt
Select `View` - `Terminal` from the menu bar.
* Configure: `cmake --preset <preset name>`
* Build: `cmake --build --preset <preset name>`
```bash
# delete build directory
rmdir /s /q build-stm32l4
# configure
cmake --preset stm32l4
# build
cmake --build --preset stm32l4
```
If there are no devices listed in the `Manage Configurations` drop-down, ensure the `CMakePresets.json` is valid.
A single json syntax error will spoil the entire project.
## Your own toolchain
Create a `CMakeUserPresets.json` (ignored by git, see and rename `cmake/preset-examples/CMakeUserPresets.json.sample` ):
```json
{
"version": 3,
"configurePresets": [
{
"name": "my-arm-bin",
"inherits": "stm32l4",
"cacheVariables": {
"ARM_GCC_BIN": "C:/Tools/arm-none-eabi-14.2/bin"
}
}
],
"buildPresets": [
{
"name": "my-arm-bin",
"configurePreset": "my-arm-bin"
}
]
}
```

View File

@ -12,6 +12,8 @@ These can be built in `tools/keytools` using `make` or from the wolfBoot root us
#### Windows Visual Studio
Project files can be found in [`[WOLFBOOT_ROOT]/IDE/VisualStudio`](../IDE/VisualStudio/README.md).
Use the `wolfBootSignTool.vcxproj` Visual Studio project to build the `sign.exe` and `keygen.exe` tools for use on Windows.
If you see any error about missing `target.h` this is a generated file based on your .config using the make process. It is needed for `WOLFBOOT_SECTOR_SIZE` used in delta updates.

View File

@ -1,3 +1,59 @@
# Key Tools for signing and key generation
See documentation [here](../../docs/Signing.md).
## Sign
See [code file `./tools/keytools/sign.c`](./sign.c) and documentation in [docs/Signing.md](../../docs/Signing.md).
## KeyGen and KeyStore
See [code file `./tools/keytools/keygen.c`](./keygen.c) and documentation [docs/keystore.md](../../docs/keystore.md).
## Flash OTP Keystore Generation, Primer, Startup
See documentation [docs/flash-OTP.md](../../docs/flash-OTP.md).
### Keystore Generation
Pack public keys into a single binary (`otp.bin`) formatted the way wolfBoot expects for
provisioning the device’s OTP/NVM keystore. No signing, no encryption—just a correctly laid-out image
with a header plus fixed-size "slots" for each key.
See [code file `./tools/keytools/otp/otp-keystore-gen.c`](./otp/otp-keystore-gen.c)
### Flash OTP Primer
See [code file `./tools/keytools/otp/otp-keystore-primer.c`](./otp/otp-keystore-primer.c)
## Flash OTP Startup
See [code file `./tools/keytools/otp/startup.c`](./otp/startup.c)
## Quick Start (Linux)
```
make wolfboot_signing_private_key.der SIGN=ED25519
# or
./tools/keytools/keygen --ed25519 -g wolfboot_signing_private_key.der
```
## Debugging and Development
### `DEBUG_SIGNTOOL`
Enables additional diagnostic messages that may be useful during development and initial bring-up.
### `WOLFBOOT_SHOW_INCLUDE`
Enables compile-time verbosity to indicate which `user_settings.h` file is being used.
Unless otherwise specified the `keygen` app will create:
1. `./wolfboot_signing_private_key.der` - the private key used for signing.
2. `./keystore.der` - the public key.
3. `src/keystore.c` - the public key, converted to c array.
Common pitfalls: mismatched keystore files in different directories. There should be exactly one
instance of each of the above files in the build tree.

View File

@ -22,6 +22,16 @@ fi
set -euo pipefail
# Require a target argument, e.g. stm32h7
TARGET="${1-}"
if [ -z "$TARGET" ]; then
echo "Usage: $0 <wolfboot-target>" >&2
echo "Example: $0 stm32h7" >&2
exit 1
fi
BUILD_DIR="build-${TARGET}"
# Begin common dir init, for /tools/scripts
# Resolve this script's absolute path and its directories
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
@ -49,6 +59,7 @@ esac
# Always work from the repo root, regardless of where the script was invoked
cd -- "$REPO_ROOT_P" || { printf 'Failed to cd to: %s\n' "$REPO_ROOT_P" >&2; exit 1; }
echo "Starting $0 from $(pwd -P)"
echo "Using target: $TARGET"
# End common dir init
@ -59,9 +70,9 @@ LOG_FILE="run.log"
KEYWORD="Config mode: dot"
echo "Saving output to $LOG_FILE"
echo "Fetch stm32h7 example .config"
echo "Fetch ${TARGET} example .config"
SRC="./config/examples/stm32h7.config"
SRC="./config/examples/${TARGET}.config"
DST="./.config"
# Exit if the .config file already exists (perhaps it is valid? we will delete our copy when done here)
@ -96,7 +107,7 @@ fi
echo "OK: $DST created and verified."
cp ./config/examples/stm32h7.config ./.config
cp "./config/examples/${TARGET}.config" ./.config
ls .config
echo ""
@ -105,10 +116,10 @@ cat .config
echo ""
echo "Clean"
rm -rf ./build-stm32h7
cmake -S . -B build-stm32h7 \
-DUSE_DOT_CONFIG=ON \
-DWOLFBOOT_TARGET=stm32h7 2>&1 | tee "$LOG_FILE" >/dev/tty
rm -rf "./${BUILD_DIR}"
cmake -S . -B "${BUILD_DIR}" \
-DUSE_DOT_CONFIG=ON \
-DWOLFBOOT_TARGET="${TARGET}" 2>&1 | tee "$LOG_FILE" >/dev/tty
# Config dot-config mode
if grep -q -- "$KEYWORD" "$LOG_FILE"; then
@ -119,7 +130,6 @@ else
fi
# Sample build
cmake --build build-stm32h7 -j10
cmake --build "${BUILD_DIR}" -j10
rm .config

View File

@ -5,7 +5,12 @@
# Example:
# python3 ./tools/scripts/config2presets.py ./config/examples/stm32h7.config
import argparse, json, os, re, sys
import argparse
import json
import os
import re
import sys
import subprocess
from collections import OrderedDict
from pathlib import Path
@ -15,6 +20,17 @@ LINE_RE = re.compile(r'^([A-Za-z_][A-Za-z0-9_]*)\s*\??=\s*(.*)$')
BOOL_TRUE = {"1", "on", "true", "yes", "y"}
BOOL_FALSE = {"0", "off", "false", "no", "n"}
# Known inherited values: these are provided implicitly by presets/build
# If the .config value matches, do NOT write to cacheVariables.
# If it differs, keep it and warn that it overrides the inherited default.
KNOWN_INHERITED = {
"WOLFBOOT_CONFIG_MODE": "preset",
"CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake",
"SIGN": "ECC256",
"HASH": "SHA256",
"BUILD_TEST_APPS": "ON"
}
def normalize_bool(s: str):
v = s.strip().lower()
@ -40,6 +56,40 @@ def parse_config(path: Path):
return kv
def filter_inherited_values(kv):
"""
Remove keys whose values match KNOWN_INHERITED defaults (do not
emit them into cacheVariables), and collect messages about
inherited/overridden values.
"""
new_kv = OrderedDict()
messages = []
for k, v in kv.items():
if k in KNOWN_INHERITED:
expected = KNOWN_INHERITED[k]
v_stripped = v.strip()
if v_stripped == expected:
messages.append(
"Note: '{}' is an inherited value with default '{}'; "
"omitting from preset cacheVariables.".format(k, expected)
)
# Do not add to new_kv; rely on inherited value
continue
else:
messages.append(
"WARNING: '{}' in .config is '{}', overriding inherited "
"default '{}' in preset cacheVariables.".format(
k, v_stripped, expected
)
)
# Fall through to keep the override
new_kv[k] = v
return new_kv, messages
def choose_target(kv):
# Prefer explicit wolfBoot var; else accept TARGET if present
if "WOLFBOOT_TARGET" in kv and kv["WOLFBOOT_TARGET"]:
@ -63,13 +113,14 @@ def to_cache_vars(kv):
return cache
def ensure_base_vars(cache, toolchain_path):
# Always ensure toolchain file is set
cache.setdefault("CMAKE_TOOLCHAIN_FILE", toolchain_path)
def ensure_base_vars(cache, toolchain_value):
# These should be inherited from [base] in the JSON presets:
# Always ensure toolchain file is set using the literal value passed in
# cache.setdefault("CMAKE_TOOLCHAIN_FILE", toolchain_value)
# Typically desired
cache.setdefault("BUILD_TEST_APPS", "ON")
# cache.setdefault("BUILD_TEST_APPS", "ON")
# Force preset mode when generating from .config into presets
cache["WOLFBOOT_CONFIG_MODE"] = "preset"
# cache["WOLFBOOT_CONFIG_MODE"] = "preset"
return cache
@ -81,6 +132,32 @@ def make_binary_dir(source_dir, target):
return os.path.join(source_dir, f"build-{target}")
def validate_presets_json(presets_path: Path):
"""
If the presets file exists but is not valid JSON, print a clear message
and exit with a non-zero status instead of raising an exception.
"""
if not presets_path.exists():
return
try:
with presets_path.open("r", encoding="utf-8") as f:
json.load(f)
except json.JSONDecodeError as e:
print(
"Error: '{}' exists but is not valid JSON (CMakePresets.json is malformed).".format(
presets_path
),
file=sys.stderr,
)
print("Details: {}".format(e), file=sys.stderr)
print(
"Please fix the JSON (for example, remove any trailing commas) and rerun this script.",
file=sys.stderr,
)
sys.exit(3)
def load_existing_presets(presets_path: Path):
try:
with presets_path.open("r", encoding="utf-8") as f:
@ -89,7 +166,150 @@ def load_existing_presets(presets_path: Path):
return None
def _merge_configure_preset_list(preset_list, cfg_preset):
"""
Update or insert a configure preset.
- If a preset with the same name exists:
* Preserve all top-level keys (inherits, environment, binaryDir, etc.)
* Merge cacheVariables: existing keys plus new ones, with new values winning.
- If it does not exist:
* Insert the new preset among the non-hidden presets in a best-fit
alphabetical position, ignoring hidden presets when choosing where
to insert. Existing entries (hidden or not) are not reordered.
"""
name = cfg_preset.get("name")
# First: update existing entry if present
for idx, existing in enumerate(preset_list):
if existing.get("name") == name:
merged = existing.copy()
existing_cache = existing.get("cacheVariables", {})
new_cache = cfg_preset.get("cacheVariables", {})
merged_cache = {}
if isinstance(existing_cache, dict):
merged_cache.update(existing_cache)
if isinstance(new_cache, dict):
merged_cache.update(new_cache)
merged["cacheVariables"] = merged_cache
merged["name"] = name
preset_list[idx] = merged
return preset_list
# Only reach here if this is a new preset
if not isinstance(name, str):
# Fallback: no sensible name to compare; just append
preset_list.append(cfg_preset)
return preset_list
# Build a list of (real_index, preset_name) for NON-hidden presets
visible = []
for idx, existing in enumerate(preset_list):
# Treat missing "hidden" as visible
if existing.get("hidden") is True:
continue
existing_name = existing.get("name")
if isinstance(existing_name, str):
visible.append((idx, existing_name))
# Decide insertion point among visible presets
insert_at_real_index = None
for real_idx, existing_name in visible:
if name < existing_name:
insert_at_real_index = real_idx
break
if insert_at_real_index is None:
if visible:
# After the last visible preset
last_visible_index = visible[-1][0]
insert_at_real_index = last_visible_index + 1
else:
# No visible presets at all: append
insert_at_real_index = len(preset_list)
preset_list.insert(insert_at_real_index, cfg_preset)
return preset_list
def _merge_build_preset_list(preset_list, bld_preset):
"""
Update or insert a build preset, keeping existing entries in their
current order and placing new ones in a best-fit alphabetical position.
- If a preset with the same name exists:
* Preserve existing jobs/verbose/targets and any other fields.
* Only ensure configurePreset is set if it was missing.
- If it does not exist:
* Consider only entries whose configurePreset is NOT 'sim' when
choosing the insertion point.
* Insert the new preset before the first such entry whose name is
lexicographically greater; if none, insert after the last such entry.
"""
name = bld_preset.get("name")
# First: update existing entry if present
for idx, existing in enumerate(preset_list):
if existing.get("name") == name:
merged = existing.copy()
if "configurePreset" not in merged and "configurePreset" in bld_preset:
merged["configurePreset"] = bld_preset["configurePreset"]
merged["name"] = name
preset_list[idx] = merged
return preset_list
# Only reach here for a new preset
if not isinstance(name, str):
# No reasonable name to compare; just append
preset_list.append(bld_preset)
return preset_list
# Build list of (real_index, preset_name) for entries we care about
# Ignore any entry whose configurePreset is 'sim'.
visible = []
for idx, existing in enumerate(preset_list):
if existing.get("configurePreset") == "sim":
continue
existing_name = existing.get("name")
if isinstance(existing_name, str):
visible.append((idx, existing_name))
insert_at_real_index = None
# Find first visible preset whose name is lexicographically greater
for real_idx, existing_name in visible:
if name < existing_name:
insert_at_real_index = real_idx
break
if insert_at_real_index is None:
if visible:
# After the last visible (non-sim) preset
last_visible_index = visible[-1][0]
insert_at_real_index = last_visible_index + 1
else:
# No visible presets at all: append to the end
insert_at_real_index = len(preset_list)
preset_list.insert(insert_at_real_index, bld_preset)
return preset_list
def merge_preset(doc, cfg_preset, bld_preset):
"""
Merge a configure/build preset into an existing CMakePresets.json document.
- If doc is None, create a fresh schema v3 doc with just these presets.
- Otherwise:
* Ensure configurePresets/buildPresets arrays exist.
* Update or append the specific presets without reordering any others.
"""
if doc is None:
return {
"version": 3,
@ -97,48 +317,200 @@ def merge_preset(doc, cfg_preset, bld_preset):
"buildPresets": [bld_preset],
}
# If file has newer schema that your CMake can't handle, you can still append,
# but CMake 3.22.1 will choke. We keep the existing version as-is.
if "configurePresets" not in doc:
if "configurePresets" not in doc or not isinstance(doc["configurePresets"], list):
doc["configurePresets"] = []
if "buildPresets" not in doc:
if "buildPresets" not in doc or not isinstance(doc["buildPresets"], list):
doc["buildPresets"] = []
# Replace presets with same name
doc["configurePresets"] = [p for p in doc["configurePresets"] if p.get("name") != cfg_preset["name"]] + [cfg_preset]
doc["buildPresets"] = [p for p in doc["buildPresets"] if p.get("name") != bld_preset["name"]] + [bld_preset]
_merge_configure_preset_list(doc["configurePresets"], cfg_preset)
_merge_build_preset_list(doc["buildPresets"], bld_preset)
return doc
def extract_unused_vars(output: str):
"""
Parse CMake output and return a list of
'Manually-specified variables were not used by the project' names.
"""
lines = output.splitlines()
unused = []
capture = False
for line in lines:
if "Manually-specified variables were not used by the project:" in line:
capture = True
continue
if not capture:
continue
stripped = line.strip()
# Skip leading blank lines after the header
if stripped == "":
# If we have already collected some variables, a blank line
# means the list is over.
if unused:
break
continue
# Only take reasonably-indented lines as variable names
if line.startswith(" ") or line.startswith(" "):
unused.append(stripped)
else:
# Non-indented line once capture has started means the block is over
if unused:
break
return unused
def run_cmake_and_report_unused(preset_name: str, repo_root: Path):
"""
Run 'cmake --preset <preset_name>' from repo_root and
print any unused manually-specified variables reported.
"""
print("")
print("Running CMake configure to check for unused manually-specified variables...")
cmd = ["cmake", "--preset", preset_name]
print("Command:", " ".join(cmd))
try:
proc = subprocess.run(
cmd,
cwd=str(repo_root),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
except FileNotFoundError:
print("cmake not found on PATH; skipping unused-variable check.", file=sys.stderr)
return
combined = ""
if proc.stdout:
combined += proc.stdout
if proc.stderr:
if combined:
combined += "\n"
combined += proc.stderr
unused = extract_unused_vars(combined)
if unused:
print("")
print(
"CMake reported unused manually-specified variables for preset '{}' :".format(
preset_name
)
)
for name in unused:
print(" {}".format(name))
else:
print("")
print(
"No unused manually-specified CMake variables detected for preset '{}'.".format(
preset_name
)
)
if proc.returncode != 0:
print("")
print("Note: 'cmake --preset {}' exited with code {}.".format(
preset_name, proc.returncode
))
def check_workflow_for_preset(workflow_path: Path, preset_name: str):
"""
Best-effort check: does the given workflow YAML mention this preset/target
name anywhere? If not, print a warning so it is clear the CI matrix will
not build it.
"""
if not workflow_path.exists():
print(
"Note: workflow YAML '{}' not found; skipping workflow check.".format(
workflow_path
)
)
return
try:
text = workflow_path.read_text(encoding="utf-8")
except OSError as e:
print(
"Warning: could not read workflow YAML '{}': {}".format(
workflow_path, e
),
file=sys.stderr,
)
return
if preset_name in text:
print(
"Workflow check: preset/target '{}' is referenced in '{}'.".format(
preset_name, workflow_path
)
)
else:
print(
"WARNING: preset/target '{}' was NOT found in workflow '{}'. "
"CI will not build this target until you add it to the matrix.".format(
preset_name, workflow_path
),
file=sys.stderr,
)
def main():
ap = argparse.ArgumentParser(description="Generate or merge a CMakePresets.json from a .config file")
ap.add_argument("config",
help="Path to .config (relative to your current directory if not absolute)")
ap.add_argument("--toolchain",
default="cmake/toolchain_arm-none-eabi.cmake",
help="Path to toolchain file (relative to repo root if not absolute)")
ap.add_argument("--presets",
default="CMakePresets.json",
help="Path to CMakePresets.json to create/merge (relative to repo root if not absolute)")
ap.add_argument("--generator",
default="Ninja",
help="CMake generator")
ap.add_argument("--preset-name",
default=None,
help="Override preset name")
ap.add_argument("--binary-dir",
default=None,
help="Override binaryDir")
ap.add_argument("--display-name",
default=None,
help="Override displayName")
ap.add_argument(
"config",
help="Path to .config (relative to your current directory if not absolute)",
)
ap.add_argument(
"--toolchain",
default="cmake/toolchain_arm-none-eabi.cmake",
help="Path to toolchain file as it should appear in CMAKE_TOOLCHAIN_FILE",
)
ap.add_argument(
"--presets",
default="CMakePresets.json",
help="Path to CMakePresets.json to create/merge (relative to repo root if not absolute)",
)
ap.add_argument(
"--generator",
default="Ninja",
help="CMake generator",
)
ap.add_argument(
"--preset-name",
default=None,
help="Override preset name",
)
ap.add_argument(
"--binary-dir",
default=None,
help="Override binaryDir",
)
ap.add_argument(
"--display-name",
default=None,
help="Override displayName",
)
ap.add_argument(
"--workflow",
default=".github/workflows/test-build-cmake-presets.yml",
help="Optional GitHub Actions workflow YAML to check for this preset name",
)
args = ap.parse_args()
# Begin common dir init, for /tools/scripts
script_path = Path(__file__).resolve()
script_dir = script_path.parent.resolve()
# repo root is parent of tools/scripts → go up two levels
# repo root is parent of tools/scripts -- go up two levels
repo_root = (script_dir / ".." / "..").resolve()
caller_cwd = Path.cwd().resolve()
@ -161,50 +533,68 @@ def main():
# Resolve paths:
# - config: relative to caller's CWD (so user can pass local relative paths naturally)
# - toolchain/presets: relative to repo root (we already chdir there)
# - presets: relative to repo root (we already chdir there)
config_path = Path(args.config)
if not config_path.is_absolute():
config_path = (caller_cwd / config_path).resolve()
toolchain_path = Path(args.toolchain)
if not toolchain_path.is_absolute():
toolchain_path = (repo_root / toolchain_path).resolve()
presets_path = Path(args.presets)
if not presets_path.is_absolute():
presets_path = (repo_root / presets_path).resolve()
# Pre-validate the existing presets JSON so we can show a clear message
# instead of crashing on a JSONDecodeError later.
validate_presets_json(presets_path)
kv = parse_config(config_path)
if not kv:
print(f"No settings parsed from .config: {config_path}", file=sys.stderr)
sys.exit(2)
# Handle inherited values like SIGN/HASH before converting to cache vars
kv, inherited_messages = filter_inherited_values(kv)
target = choose_target(kv)
cache = to_cache_vars(kv)
# Use forward slashes in JSON for better CMake portability
cache = ensure_base_vars(cache, toolchain_path.as_posix())
# Use the toolchain value exactly as passed on the command line,
# but normalize backslashes for JSON/CMake friendliness.
toolchain_value = args.toolchain.replace("\\", "/")
cache = ensure_base_vars(cache, toolchain_value)
# Build preset objects
source_dir = "${sourceDir}" # CMake variable; leave literal
preset_name = args.preset_name or make_preset_name(target)
binary_dir = args.binary_dir or make_binary_dir(source_dir, target)
display_name = args.display_name or f"Linux/WSL ARM ({target})"
display_name = args.display_name or f"{target}"
cfg_preset = OrderedDict([
("name", preset_name),
("displayName", display_name),
("inherits", "base"),
("generator", args.generator),
("binaryDir", binary_dir),
("cacheVariables", cache),
])
bld_preset = OrderedDict([
("name", preset_name),
("configurePreset", preset_name),
("jobs", 4),
("verbose", True),
("targets", ["all"]),
])
# For STM32 boards, inherit like stm32g0:
# [ "base", "stm32", "sign_hash_config" ]
# For everything else, just inherit "base".
inherits_value = "base"
if isinstance(preset_name, str) and preset_name.startswith("stm32") and preset_name != "stm32":
inherits_value = ["base", "stm32", "sign_hash_config"]
cfg_preset = OrderedDict(
[
("name", preset_name),
("displayName", display_name),
("inherits", inherits_value),
("generator", args.generator),
("binaryDir", binary_dir),
("cacheVariables", cache),
]
)
bld_preset = OrderedDict(
[
("name", preset_name),
("configurePreset", preset_name),
("jobs", 4),
("verbose", True),
("targets", ["all"]),
]
)
# Ensure schema v3 unless existing file says otherwise
doc = load_existing_presets(presets_path)
@ -222,6 +612,20 @@ def main():
print(f"Updated {presets_path} with preset '{preset_name}' targeting '{target}'")
# Best-effort: check if this preset/target name appears in the workflow matrix
workflow_path = Path(args.workflow)
if not workflow_path.is_absolute():
workflow_path = (repo_root / workflow_path).resolve()
check_workflow_for_preset(workflow_path, preset_name)
if inherited_messages:
print("")
print("Inherited .config values summary:")
for msg in inherited_messages:
print(" " + msg)
# After updating presets, run cmake and show any unused variables
run_cmake_and_report_unused(preset_name, repo_root)
if __name__ == "__main__":
main()

View File

@ -2,6 +2,8 @@
# wolfboot_cmake_full_build.sh
#
# >>>>> EDIT WITH CAUTION: Used by ./github/workflow tests <<<<<
#
# ./tools/scripts/wolfboot_cmake_full_build.sh --CLEAN [your target]
# ./tools/scripts/wolfboot_cmake_full_build.sh --target [your target]
# ./tools/scripts/wolfboot_cmake_full_build.sh --flash [your target]
@ -284,6 +286,40 @@ if [ $# -gt 0 ]; then
fi
exit "$status"
fi
if [ "$THIS_OPERATION" = "--flash-unsigned" ]; then
echo "Flash Target=$TARGET"
CLI="$(find_stm32_tool STM32_Programmer_CLI)" || { echo "CLI not found"; exit 1; }
if [ -f "$CLI" ]; then
echo "Found STM32 flasher: $CLI"
else
echo "CLI=$CLI"
echo "STM32_Programmer_CLI.exe not found, exiting"
exit 2
fi
# TODO Alternative preset inherited configs may write to build directories other than build-$TARGET.
# Currently works only with base_build_presetName preset path
APP_BIN="../build-$TARGET/app.bin"
echo Checking "APP_BIN=$APP_BIN"
if [ ! -f "$APP_BIN" ]; then
echo "Missing: $APP_BIN (build first: cmake --build --preset \"$TARGET\")"
exit 2
fi
BOOT_ADDR=0x0800A000 # your wolfBoot BOOT address
BOOT_ADDR=0x08000000 # your wolfBoot BOOT address
echo "BOOT_ADDR=$BOOT_ADDR"
# SWD via ST-LINK (Windows handles the USB)
"$CLI" -c port=SWD mode=UR freq=400 -w "$APP_BIN" "$BOOT_ADDR" -v -hardRst
status=$?
if [ "$status" -eq 0 ]; then
echo "OK: command succeeded"
else
echo "Failed: command exited with status $status"
fi
exit "$status"
fi
fi
if [ "$TARGET" = "" ]; then
@ -292,6 +328,7 @@ if [ "$TARGET" = "" ]; then
echo " $0 --CLEAN [your target]"
echo " $0 --target [your target]"
echo " $0 --flash [your target]"
echo " $0 --flash-unsigned [your target]"
echo ""
cmake -S . -B build --list-presets=configure
exit 1