From eaf029fbc5c3494a635c5dc5dd1a9ad26468d5c3 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Tue, 18 Nov 2025 17:44:43 -0800 Subject: [PATCH 1/9] CMake Improvements --- .../workflows/test-build-cmake-dot-config.yml | 103 +++ .github/workflows/test-build-cmake-mac.yml | 96 ++ .../workflows/test-build-cmake-presets.yml | 101 +++ .github/workflows/test-build-cmake-script.yml | 77 ++ .../workflows/test-build-cmake-windows.yml | 128 +++ .github/workflows/test-build-cmake.yml | 60 +- .github/workflows/test-library.yml | 110 ++- .github/workflows/test-vscode.yml | 109 +++ .gitignore | 23 +- .vs/README.md | 8 + .vs/VSWorkspaceSettings.json | 69 ++ CMakeLists.txt | 817 +++++++++++++++--- CMakePresets.json | 346 ++++++++ IDE/VSCode/README.md | 91 ++ IDE/VSCode/install.sh | 76 ++ IDE/VSCode/wolfBoot.code-workspace | 168 ++++ IDE/Windows/README.md | 34 + INSTALL.md | 8 +- README.md | 111 ++- cmake/README.md | 565 ++++++++++++ cmake/config_defaults.cmake | 428 +++++++++ cmake/cube_ide_config.cmake | 436 ++++++++++ cmake/current_user.cmake | 106 +++ cmake/downloads/README.md | 21 + cmake/downloads/stm32l4.cmake | 39 + cmake/functions.cmake | 39 +- cmake/load_dot_config.cmake | 152 ++++ .../CMakeUserPresets.json.sample | 24 + cmake/preset-examples/README.md | 3 + cmake/stm32_hal_download.cmake | 197 +++++ cmake/toolchain_aarch64-none-elf.cmake | 14 +- cmake/toolchain_arm-none-eabi.cmake | 178 +++- cmake/utils.cmake | 32 +- cmake/visualgdb_config.cmake | 93 ++ cmake/vs2022_config.cmake | 176 ++++ cmake/wolfboot.cmake | 49 +- cmake/write_size.cmake | 36 + config/examples/README.md | 29 + config/examples/visualgdb-stm32l4.config | 33 + docs/CMake.md | 3 + docs/PQ.md | 4 +- docs/README.md | 33 + docs/STM32.md | 123 +++ docs/Signing.md | 2 +- docs/Windows.md | 39 + hal/stm32l4xx_hal_conf.h | 24 +- tools/scripts/cmake_dev_prompt_test.bat | 79 ++ tools/scripts/cmake_dot_config.sh | 125 +++ tools/scripts/cmake_dotconfig_test.bat | 133 +++ tools/scripts/cmake_test.bat | 81 ++ tools/scripts/cmake_test.sh | 49 ++ tools/scripts/config2presets.py | 227 +++++ tools/scripts/wolfboot_cmake_full_build.sh | 310 +++++++ 53 files changed, 6206 insertions(+), 211 deletions(-) create mode 100644 .github/workflows/test-build-cmake-dot-config.yml create mode 100644 .github/workflows/test-build-cmake-mac.yml create mode 100644 .github/workflows/test-build-cmake-presets.yml create mode 100644 .github/workflows/test-build-cmake-script.yml create mode 100644 .github/workflows/test-build-cmake-windows.yml create mode 100644 .github/workflows/test-vscode.yml create mode 100644 .vs/README.md create mode 100644 .vs/VSWorkspaceSettings.json create mode 100644 CMakePresets.json create mode 100644 IDE/VSCode/README.md create mode 100644 IDE/VSCode/install.sh create mode 100644 IDE/VSCode/wolfBoot.code-workspace create mode 100644 IDE/Windows/README.md create mode 100644 cmake/README.md create mode 100644 cmake/config_defaults.cmake create mode 100644 cmake/cube_ide_config.cmake create mode 100644 cmake/current_user.cmake create mode 100644 cmake/downloads/README.md create mode 100644 cmake/downloads/stm32l4.cmake create mode 100644 cmake/load_dot_config.cmake create mode 100644 cmake/preset-examples/CMakeUserPresets.json.sample create mode 100644 cmake/preset-examples/README.md create mode 100644 cmake/stm32_hal_download.cmake create mode 100644 cmake/visualgdb_config.cmake create mode 100644 cmake/vs2022_config.cmake create mode 100644 cmake/write_size.cmake create mode 100644 config/examples/README.md create mode 100644 config/examples/visualgdb-stm32l4.config create mode 100644 docs/CMake.md create mode 100644 docs/README.md create mode 100644 docs/STM32.md create mode 100644 docs/Windows.md create mode 100644 tools/scripts/cmake_dev_prompt_test.bat create mode 100644 tools/scripts/cmake_dot_config.sh create mode 100644 tools/scripts/cmake_dotconfig_test.bat create mode 100644 tools/scripts/cmake_test.bat create mode 100644 tools/scripts/cmake_test.sh create mode 100644 tools/scripts/config2presets.py create mode 100644 tools/scripts/wolfboot_cmake_full_build.sh diff --git a/.github/workflows/test-build-cmake-dot-config.yml b/.github/workflows/test-build-cmake-dot-config.yml new file mode 100644 index 0000000000..d34758d4f0 --- /dev/null +++ b/.github/workflows/test-build-cmake-dot-config.yml @@ -0,0 +1,103 @@ +name: wolfboot CMake (.config) +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +jobs: + wolfboot_dot_config_test: + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - 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: Install requirements + run: | + # Run system updates and install toolchain + sudo apt-get update + sudo apt-get install -y gcc-arm-none-eabi gcc-powerpc-linux-gnu cmake + + - name: Run dot-config examples + run: | + # Sample .config cmake test + + set -euo pipefail + + LOG_FILE="run.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 "Clean" + rm -rf ./build-stm32h7 + + # 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 + exit 1 + fi + + # Sample build + cmake --build build-stm32h7 --parallel 8 diff --git a/.github/workflows/test-build-cmake-mac.yml b/.github/workflows/test-build-cmake-mac.yml new file mode 100644 index 0000000000..601692d5fb --- /dev/null +++ b/.github/workflows/test-build-cmake-mac.yml @@ -0,0 +1,96 @@ +name: WolfBoot CMake Build (macOS) + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +jobs: + macos-cmake: + name: Build on macOS (CMake + Ninja) + runs-on: macos-14 + timeout-minutes: 20 + + strategy: + fail-fast: false + matrix: + target: [stm32l4, stm32h7, stm32c0, stm32g0] + + env: + HOMEBREW_NO_AUTO_UPDATE: "1" # avoid updating taps during install + HOMEBREW_NO_ANALYTICS: "1" + HOMEBREW_CURL_RETRIES: "6" # ask curl inside brew to retry + + steps: + - name: Checkout (with submodules) + uses: actions/checkout@v4 + with: + submodules: true + + - name: Cache Homebrew bottles # downloads (so retries don't redownload) + uses: actions/cache@v4 + with: + path: | + ~/Library/Caches/Homebrew + /Users/runner/Library/Caches/Homebrew + key: homebrew-${{ runner.os }}-mac14-cmake-gcc-newlib + restore-keys: | + homebrew-${{ runner.os }}- + + - name: Install toolchain and build tools + run: | + # Install with step throttle to hopefully avoid stuck jobs + + set -euxo pipefail + + throttle_delay=5 + brew update + + sleep "$throttle_delay" + brew install --force-bottle cmake + + sleep "$throttle_delay" + brew install --force-bottle ninja + + # Use cask to include headers such as + sleep "$throttle_delay" + brew install --cask gcc-arm-embedded + + - name: Probe ARM GCC (paths + smoke build) + run: | + set -euxo pipefail + + which arm-none-eabi-gcc + arm-none-eabi-gcc --version + + echo "=== GCC search dirs ===" + arm-none-eabi-gcc -print-search-dirs + + echo "=== GCC verbose include paths (preprocess only) ===" + # This prints the built-in include search order; harmless with empty stdin. + arm-none-eabi-gcc -x c -E -v - < /dev/null || true + + echo "=== Compile a freestanding object (no stdlib headers needed) ===" + cat > hello.c <<'EOF' + int main(void) { return 0; } + EOF + arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -ffreestanding -nostdlib -c hello.c -o hello.o + ls -l hello.o + + - name: Configure (STM32L4) + run: | + echo "Disabled, missing params" + # rm -rf build + # cmake -B build -G Ninja \ + # -DWOLFBOOT_CONFIG_MODE=preset \ + # -DWOLFBOOT_TARGET=stm32l4 \ + # -DBUILD_TEST_APPS=ON \ + # -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain_arm-none-eabi.cmake + + - name: Cmake Configure & Build Preset (${{ matrix.target }}) + run: | + rm -rf ./build-${{ matrix.target }} + + cmake --preset ${{ matrix.target }} + cmake --build --preset ${{ matrix.target }} diff --git a/.github/workflows/test-build-cmake-presets.yml b/.github/workflows/test-build-cmake-presets.yml new file mode 100644 index 0000000000..a0be0af3bd --- /dev/null +++ b/.github/workflows/test-build-cmake-presets.yml @@ -0,0 +1,101 @@ +name: WolfBoot CMake Presets Build + +on: + push: + # TODO: branches: [ 'master', 'main', 'release/**' ] + branches: [ '*' ] + pull_request: + branches: [ "*" ] + +permissions: + contents: read + +jobs: + ubuntu-cmake: + name: Build on Ubuntu + runs-on: ubuntu-latest + timeout-minutes: 20 + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + target: + - stm32l4 + - stm32h7 + - stm32g0 + include: + # Optional per-target cache variables you might want to pass later. + # Keep empty for now to avoid guessing addresses. + - target: stm32l4 + extra_cache: "" + - target: stm32h7 + extra_cache: "" + - target: stm32g0 + extra_cache: "" + + steps: + - name: Checkout (with submodules) + uses: actions/checkout@v4 + with: + submodules: true + + # Lock down network/runner + # See https://github.com/step-security/harden-runner/releases + # Currently only supported on Ubuntu + + # ARM GCC toolchain (adds the bin dir to PATH) + - name: Set up ARM none-eabi GCC 14.x + uses: carlosperate/arm-none-eabi-gcc-action@v1 + with: + release: "14.2.Rel1" # <-- use 'release', not 'version' + path-env-var: ARM_NONE_EABI_GCC_PATH + + + - name: List all environment variables + run: | + # Show environment settings + + echo "All environment settings" + env | sort + + - name: List Presets + run: | + # Check available presets in CMakePresets.json + + cmake -S . -B build-list --list-presets=configure + + - name: Configure Preset "${{ matrix.target }}" + run: | + # cmake runs in git bash + + cmake --preset "${{ matrix.target }}" + echo "Configured: ${{ matrix.target }}" + + - name: Build "${{ matrix.target }}" + run: | + # cmake runs in git bash + # BUILD_DIR="build-${{ matrix.target }}" + cmake --build "build-${{ matrix.target }}" --parallel + + # Optional: show interesting artifacts + - name: List build outputs + if: always() + run: | + BUILD_DIR="build-${{ matrix.target }}" + echo "=== Artifacts in $BUILD_DIR ===" + find "$BUILD_DIR" -maxdepth 3 -type f \( -name "*.elf" -o -name "*.bin" -o -name "*.hex" -o -name "bin-assemble" -o -name "keystore" \) -print || true + + # Upload binaries if present (non-fatal if none) + - name: Upload firmware/artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: wolfboot-${{ matrix.target }} + path: | + build-${{ matrix.target }}/**/*.elf + build-${{ matrix.target }}/**/*.bin + build-${{ matrix.target }}/**/*.hex + if-no-files-found: warn diff --git a/.github/workflows/test-build-cmake-script.yml b/.github/workflows/test-build-cmake-script.yml new file mode 100644 index 0000000000..9a19ba1816 --- /dev/null +++ b/.github/workflows/test-build-cmake-script.yml @@ -0,0 +1,77 @@ +name: wolfboot CMake Script +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] +jobs: + wolfboot_build_script_test: + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - 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: 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 + run: | + rm -rf ./build + 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" + + ./tools/scripts/wolfboot_cmake_full_build.sh --CLEAN "stm32g0" + ./tools/scripts/wolfboot_cmake_full_build.sh --target "stm32g0" diff --git a/.github/workflows/test-build-cmake-windows.yml b/.github/workflows/test-build-cmake-windows.yml new file mode 100644 index 0000000000..9eab7b6250 --- /dev/null +++ b/.github/workflows/test-build-cmake-windows.yml @@ -0,0 +1,128 @@ +name: WolfBoot CMake Build (Windows) + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +permissions: + contents: read + +jobs: + windows-cmake: + name: Build on Windows + runs-on: windows-latest + # Reminder default is PowerShell runner, not DOS, unless otherwise specified. + timeout-minutes: 20 + + strategy: + fail-fast: false + matrix: + target: + - stm32l4 + - stm32h7 + - stm32g0 + include: + # Optional per-target cache variables you might want to pass later. + # Keep empty for now to avoid guessing addresses. + - target: stm32l4 + extra_cache: "" + - target: stm32h7 + extra_cache: "" + - target: stm32g0 + extra_cache: "" + + steps: + - name: Checkout (with submodules) + uses: actions/checkout@v4 + with: + submodules: true + + # Lock down network/runner + # See https://github.com/step-security/harden-runner/releases + # Currently only supported on Ubuntu + + # ARM GCC toolchain (adds the bin dir to PATH) + - name: Set up ARM none-eabi GCC 14.x + uses: carlosperate/arm-none-eabi-gcc-action@v1 + with: + release: "14.2.Rel1" # <-- use 'release', not 'version' + path-env-var: ARM_NONE_EABI_GCC_PATH + + # CMake + Ninja are preinstalled on windows-latest, but verify & print versions + - name: Tool versions + shell: cmd + run: | + :: Show some key toolchain versions + + echo "Compiler versions:" + arm-none-eabi-gcc --version + echo "" + echo "CMake:" + cmake --version + echo + echo "Ninja:" + ninja --version + echo + ::echo "MSVC (via vswhere):" + ::"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.Component.MSBuild -property installationVersion + echo + echo "VS2022 Properties" + "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * + echo + + - name: List all environment variables + run: | + # Show environment settings + + echo "All environment settings" + # set + # Get-ChildItem Env: | Sort-Object Name + $env:path -split ";" + + # Get-ChildItem -Path 'C:\' -Filter stdint.h -Recurse -ErrorAction SilentlyContinue + + + - name: List Presets + shell: cmd + run: | + # Check available presets in CMakePresets.json + + cmake -S . -B build-list --list-presets=configure + + - name: Configure Preset "${{ matrix.target }}" + shell: cmd + run: | + # cmake runs in git bash + + cmake --preset "${{ matrix.target }}" + echo "Configured: ${{ matrix.target }}" + + - name: Build "${{ matrix.target }}" + shell: cmd + run: | + # cmake runs in git bash + # BUILD_DIR="build-${{ matrix.target }}" + cmake --build "build-${{ matrix.target }}" --parallel + + # Optional: show interesting artifacts + - name: List build outputs + if: always() + shell: bash + run: | + BUILD_DIR="build-${{ matrix.target }}" + echo "=== Artifacts in $BUILD_DIR ===" + find "$BUILD_DIR" -maxdepth 3 -type f \( -name "*.elf" -o -name "*.bin" -o -name "*.hex" -o -name "bin-assemble" -o -name "keystore" \) -print || true + + # Upload binaries if present (non-fatal if none) + - name: Upload firmware/artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: wolfboot-${{ matrix.target }} + path: | + build-${{ matrix.target }}/**/*.elf + build-${{ matrix.target }}/**/*.bin + build-${{ matrix.target }}/**/*.hex + if-no-files-found: warn diff --git a/.github/workflows/test-build-cmake.yml b/.github/workflows/test-build-cmake.yml index eb41a92e26..9b52fcac6d 100644 --- a/.github/workflows/test-build-cmake.yml +++ b/.github/workflows/test-build-cmake.yml @@ -1,5 +1,7 @@ -name: Wolfboot CMake Build +name: Wolfboot CMake Build (Ubuntu) on: + push: + branches: [ 'master', 'main', 'release/**' ] pull_request: branches: [ '*' ] jobs: @@ -12,9 +14,54 @@ jobs: with: submodules: true + - 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: Install requirements run: | - sudo sed -i 's|http://azure.archive.ubuntu.com/ubuntu/|http://mirror.arizona.edu/ubuntu/|g' /etc/apt/sources.list sudo apt-get update sudo apt-get install -y gcc-arm-none-eabi gcc-powerpc-linux-gnu cmake @@ -22,6 +69,7 @@ jobs: run: | rm -rf ./build cmake -B build -DWOLFBOOT_TARGET=stm32u5 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x08100000 -DWOLFBOOT_SECTOR_SIZE=0x2000 -DWOLFBOOT_PARTITION_SIZE=0x20000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x817F000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81FE000 -DNO_MPU=yes + - name: Build wolfBoot run: make -C build @@ -59,3 +107,11 @@ jobs: cmake -B build -DWOLFBOOT_TARGET=nrf52 -DWOLFBOOT_PARTITION_SIZE=0x8000 -DWOLFBOOT_SECTOR_SIZE=0x1000 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x27000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x2F000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x37000 - name: Build wolfBoot run: make -C build + + - name: Run wolfbuild script + run: | + rm -rf ./build + 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" diff --git a/.github/workflows/test-library.yml b/.github/workflows/test-library.yml index 2b9323f232..8bf760dee9 100644 --- a/.github/workflows/test-library.yml +++ b/.github/workflows/test-library.yml @@ -41,6 +41,7 @@ jobs: steps: - uses: actions/checkout@v4 with: + clean: true submodules: true - name: make clean @@ -54,10 +55,23 @@ jobs: HASH: ${{ matrix.hash }} MATH: ${{ matrix.math }} run: | + # Test various library parameters + + export MAKE_SIGN="${ASYM^^}" + export MAKE_HASH="${HASH^^}" + export MAKE_MATH='${{ matrix.math }}' # e.g., "SPMATH=1 WOLFBOOT_SMALL_STACK=1" + export PRIVATE_KEY="wolfboot_signing_private_key.der" + + echo "This MAKE_SIGN=$MAKE_SIGN" + echo "This MAKE_HASH=$MAKE_HASH" + echo "This MAKE_MATH=$MAKE_MATH" + # Sample build build_once() { # Convert asym and hash to upper case, optionally add additional param - make -j test-lib SIGN=${ASYM^^} HASH=${HASH^^} ${MATH} "$@" + echo "Build test-lib..." + echo "make -j1 test-lib SIGN=${MAKE_SIGN} HASH=${MAKE_HASH} ${MATH} \"$@\"" + make -j1 test-lib SIGN=${MAKE_SIGN} HASH=${MAKE_HASH} ${MATH} "$@" } set -euo pipefail @@ -65,17 +79,65 @@ jobs: # Get the reference config cp config/examples/library.config .config + # peek + echo "Existing files?" + if [ -f "src/keystore.c" ]; then + echo "WARNING: Found unexpected src/keystore.c" + fi + if [ -f "include/target.h" ]; then + echo "WARNING: Found unexpected include/target.h" + fi + if [ -f "keystore.der" ]; then + echo "WARNING: Found unexpected keystore.der" + fi + if [ -f "wolfboot_signing_private_key.der" ]; then + echo "WARNING: Found unexpected wolfboot_signing_private_key.der" + fi + if [ -f "./tools/keytools/keystore.der" ]; then + echo "WARNING: Found unexpected ./tools/keytools/keystore.der" + fi + if [ -f "./tools/keytools/wolfboot_signing_private_key.der" ]; then + echo "WARNING: Found unexpected ./tools/keytools/wolfboot_signing_private_key.der" + fi + # Keytools - make keytools - ./tools/keytools/keygen --${ASYM} -g wolfboot_signing_private_key.der + echo "" + echo "make -j1 keytools SIGN=\"${MAKE_SIGN}\" HASH=\"${MAKE_HASH}\" $MATH" + make -j1 keytools SIGN="${MAKE_SIGN}" HASH="${MAKE_HASH}" $MATH + + # Generate keys + echo "" + echo "./tools/keytools/keygen --${ASYM} -g wolfboot_signing_private_key.der" + ./tools/keytools/keygen --${ASYM} -g wolfboot_signing_private_key.der + + # Force fresh files + # peek + echo "Existing files?" + if [ -f "src/keystore.c" ]; then + echo "Found unexpected src/keystore.c" + fi + if [ -f "include/target.h" ]; then + echo "Found unexpected include/target.h" + fi + if [ -f "keystore.der" ]; then + echo "Found unexpected keystore.der" + fi + if [ -f "wolfboot_signing_private_key.der" ]; then + echo "Found unexpected wolfboot_signing_private_key.der" + fi # Sign + echo "" echo "Test" > test.bin - ./tools/keytools/sign --${ASYM} --${HASH} test.bin wolfboot_signing_private_key.der 1 + echo "Sign test.bin" + echo "./tools/keytools/sign --${ASYM} --${HASH} test.bin wolfboot_signing_private_key.der 1" + ./tools/keytools/sign --${ASYM} --${HASH} test.bin wolfboot_signing_private_key.der 1 # First attempt if build_once >build.out 2>build.err; then echo "Success on first attempt, WOLFBOOT_HUGE_STACK not applied." + cat build.out + cat build.err exit 0 fi @@ -90,12 +152,16 @@ jobs: build_once WOLFBOOT_HUGE_STACK=1 else echo "Build failed for another reason:" + cat build.out cat build.err exit 1 fi - name: Run test-lib run: | + # Check test_v1_signed.bin + + echo "./test-lib test_v1_signed.bin" ./test-lib test_v1_signed.bin ./test-lib test_v1_signed.bin 2>&1 | grep "Firmware Valid" @@ -103,6 +169,36 @@ jobs: run: | # Corrupt signed binary truncate -s -1 test_v1_signed.bin - echo "A" >> test_v1_signed.bin - ./test-lib test_v1_signed.bin - ./test-lib test_v1_signed.bin 2>&1 | grep "Failure" + printf "A" >> test_v1_signed.bin + + # Run once, capture output and status (temporarily disable errexit) + set +e + output=$(./test-lib test_v1_signed.bin 2>&1) + status=$? + set -e + + echo "$output" + + # TODO hal/library.c does not currently return an error code during failure + # Test only looks for the word "Failure" + # See https://github.com/wolfSSL/wolfBoot/pull/625 + + # If the tool printed "Failure", treat it as a failure regardless of exit code + if echo "$output" | grep -F "Failure" >/dev/null; then + status=1 + fi + + # Must have failed (non-zero exit) + if [ "$status" -eq 0 ]; then + echo "Expected failure, but exit code was 0" + exit 1 + fi + + # Must include the expected Failure message + if ! echo "$output" | grep -F "Failure" >/dev/null; then + echo "Expected 'Failure' not found in output" + exit 1 + fi + + echo "Got expected non-zero exit and 'Failure' message." + diff --git a/.github/workflows/test-vscode.yml b/.github/workflows/test-vscode.yml new file mode 100644 index 0000000000..1808a04c3c --- /dev/null +++ b/.github/workflows/test-vscode.yml @@ -0,0 +1,109 @@ +name: wolfBoot VSCode + +on: + push: + # TODO: branches: [ 'master', 'main', 'release/**' ] + branches: [ '*' ] + pull_request: + branches: [ '*' ] + workflow_dispatch: + inputs: + workspace_path: + description: "Path to the .code-workspace file" + required: true + default: "IDE/VSCode/wolfBoot.code-workspace" + cmake_list_presets: + description: "Also run 'cmake --list-presets'" + required: true + default: "true" + +jobs: + check: + runs-on: ubuntu-latest + # Provide fallbacks when not workflow_dispatch + env: + WORKSPACE_PATH: ${{ github.event_name == 'workflow_dispatch' && inputs.workspace_path || 'IDE/VSCode/wolfBoot.code-workspace' }} + CMAKE_LIST: ${{ github.event_name == 'workflow_dispatch' && inputs.cmake_list_presets || 'true' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Python and CMake deps + run: | + sudo apt-get update + sudo apt-get install -y python3 python3-pip ninja-build + cmake --version + ninja --version + + - name: Validate workspace JSONC and folder paths + shell: python3 {0} + env: + WORKSPACE_PATH: ${{ env.WORKSPACE_PATH }} + run: | + import os, sys, re, json, pathlib + print("pwd:", pathlib.Path(".").resolve()) + ws_rel = os.environ.get("WORKSPACE_PATH", "").strip() + print("WORKSPACE_PATH:", ws_rel or "") + + if not ws_rel: + print("WORKSPACE_PATH input is required", file=sys.stderr) + sys.exit(2) + + ws = pathlib.Path(ws_rel) + if not ws.exists(): + print(f"Workspace file not found: {ws}", file=sys.stderr) + sys.exit(3) + + txt = ws.read_text(encoding="utf-8", errors="replace") + # strip /* */ and // comments (JSONC -> JSON) + txt = re.sub(r"/\*.*?\*/", "", txt, flags=re.S) + txt = re.sub(r"//.*", "", txt) + try: + data = json.loads(txt) + except Exception: + print("Failed to parse workspace as JSON after removing comments.", file=sys.stderr) + raise + + folders = data.get("folders", []) + if not isinstance(folders, list) or not folders: + print("No 'folders' defined in workspace.", file=sys.stderr) + sys.exit(4) + + ws_dir = ws.parent.resolve() + errors = 0 + for idx, item in enumerate(folders): + if not isinstance(item, dict): + print(f"folders[{idx}] is not an object", file=sys.stderr) + errors += 1 + continue + path = item.get("path"); uri = item.get("uri") + if path is None and uri is None: + print(f"folders[{idx}] missing 'path' or 'uri'", file=sys.stderr) + errors += 1 + continue + if path is not None: + if not isinstance(path, str): + print(f"folders[{idx}].path is not a string", file=sys.stderr) + errors += 1 + else: + resolved = (ws_dir / path).resolve() + print(f"[ok] folders[{idx}] path='{path}' -> '{resolved}'") + if not resolved.exists(): + print(f"[warn] resolved path does not exist on runner: {resolved}", file=sys.stderr) + if uri is not None: + print(f"[info] folders[{idx}] uses 'uri': {uri}") + + if errors: + sys.exit(5) + + settings = data.get("settings", {}) + if settings and not isinstance(settings, dict): + print("settings is not an object", file=sys.stderr) + sys.exit(6) + + print("Workspace JSONC and folder paths look sane.") + + - name: List CMake presets (optional) + if: ${{ env.CMAKE_LIST == 'true' }} + run: | + cmake --list-presets || true diff --git a/.gitignore b/.gitignore index 27d625b76c..6e4b4dc3b3 100644 --- a/.gitignore +++ b/.gitignore @@ -66,6 +66,10 @@ src/rsa4096_pub_key.c /**/wolfboot_signing_private_key.der /**/keystore.der +# Converted from generated files +/**/keystore_spki.der +/**/keystore_spki.pem + # Renesas key data files include/key_data.* include/enckey_data.* @@ -134,7 +138,6 @@ tools/squashelf/** # Generated configuration files .config -.vs *.filters *.user @@ -270,18 +273,26 @@ language.settings.xml *.bak # Any Visual Studio / VisualGDB -/**/.vs -/**/.visualgdb/* +/**/.vs/** +/**/.visualgdb/** + +# --- Whitelist specific files in the *root* .vs folder --- +# Allow Git to descend into the root .vs directory +!/.vs/ # Defaults are set in files otherwise excluded: -!/.vs/README.md -!/.vs/VSWorkspaceState.json -!/.vs/VSWorkspaceSettings.json +!**/.vs/README.md +!**/.vs/VSWorkspaceSettings.json + # Any build directories /**/build /**/build-** +# User config +# See cmake/config_defaults_user.cmake.sample +/**/cmake/config_defaults_user.cmake + # Eclipse .cproject .project diff --git a/.vs/README.md b/.vs/README.md new file mode 100644 index 0000000000..b717b34b5a --- /dev/null +++ b/.vs/README.md @@ -0,0 +1,8 @@ +# Visual Studio Workspace Files + +Normally excluded from source control, but here for a Visual Studio CMake project workaround: + +## VSWorkspaceSettings.json + +Without the `ExcludedItems` listed in this file, Visual Studio tries top be "helpful" +and set the default startup item to some project file found in the directory tree. This is undesired. diff --git a/.vs/VSWorkspaceSettings.json b/.vs/VSWorkspaceSettings.json new file mode 100644 index 0000000000..25bf0093f0 --- /dev/null +++ b/.vs/VSWorkspaceSettings.json @@ -0,0 +1,69 @@ +{ + "Description": "Items to exclude from Debug Targets", + "ExcludedItems": [ + "tools/keytools/**/*.sln", + "tools/keytools/**/*.vcxproj", + "tools/keytools/**/*.vcxproj.filters", + "tools/keytools/**/*.vcxproj.user", + "tools/keytools/**/*.csproj", + "tools/keytools/**/*.csproj.filters", + "tools/keytools/**/*.csproj.user", + + "IDE/VisualGDB/**/*.sln", + "IDE/VisualGDB/**/*.vcxproj", + "IDE/VisualGDB/**/*.vcxproj.filters", + "IDE/VisualGDB/**/*.vcxproj.user", + "IDE/VisualGDB/**/*.csproj", + "IDE/VisualGDB/**/*.csproj.filters", + "IDE/VisualGDB/**/*.csproj.user", + + "IDE/VisualStudio/**/*.sln", + "IDE/VisualStudio/**/*.vcxproj", + "IDE/VisualStudio/**/*.vcxproj.filters", + "IDE/VisualStudio/**/*.vcxproj.user", + "IDE/VisualStudio/**/*.csproj", + "IDE/VisualStudio/**/*.csproj.filters", + "IDE/VisualStudio/**/*.csproj.user", + + "IDE/VisualStudio.cmake/**/*.sln", + "IDE/VisualStudio.cmake/**/*.vcxproj", + "IDE/VisualStudio.cmake/**/*.vcxproj.filters", + "IDE/VisualStudio.cmake/**/*.vcxproj.user", + "IDE/VisualStudio.cmake/**/*.csproj", + "IDE/VisualStudio.cmake/**/*.csproj.filters", + "IDE/VisualStudio.cmake/**/*.csproj.user", + + "lib/wolfssl/**/*.sln", + "lib/wolfssl/**/*.vcxproj", + "lib/wolfssl/**/*.vcxproj.filters", + "lib/wolfssl/**/*.vcxproj.user", + "lib/wolfssl/**/*.csproj", + "lib/wolfssl/**/*.csproj.filters", + "lib/wolfssl/**/*.csproj.user", + "lib/wolfssl/wrapper/CSharp/**", + + "lib/wolfssl/**/*.sln", + "lib/wolfssl/**/*.vcxproj", + "lib/wolfssl/**/*.vcxproj.filters", + "lib/wolfssl/**/*.vcxproj.user", + "lib/wolfssl/**/*.csproj", + "lib/wolfssl/**/*.csproj.filters", + "lib/wolfssl/**/*.csproj.user", + + "lib/wolfPKCS11/**/*.sln", + "lib/wolfPKCS11/**/*.vcxproj", + "lib/wolfPKCS11/**/*.vcxproj.filters", + "lib/wolfPKCS11/**/*.vcxproj.user", + "lib/wolfPKCS11/**/*.csproj", + "lib/wolfPKCS11/**/*.csproj.filters", + "lib/wolfPKCS11/**/*.csproj.user", + + "lib/wolfTPM/**/*.sln", + "lib/wolfTPM/**/*.vcxproj", + "lib/wolfTPM/**/*.vcxproj.filters", + "lib/wolfTPM/**/*.vcxproj.user", + "lib/wolfTPM/**/*.csproj", + "lib/wolfTPM/**/*.csproj.filters", + "lib/wolfTPM/**/*.csproj.user" + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 108b23d249..bb325acb71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,25 +28,331 @@ # -DWOLFBOOT_PARTITION_SIZE= -DWOLFBOOT_PARTITION_UPDATE_ADDRESS= # -DWOLFBOOT_PARTITION_SWAP_ADDRESS= -DBUILD_TEST_APPS=yes .. # $ cmake --build . +# +# Windows builds: Never use NODEFAULTLIB; problems with CRT auto-linking and cause mainCRTStartup to go missing. + +message(STATUS "Begin [WOLFBOOT_ROOT]/CmakeLists.txt") + +message(STATUS "wolfBoot target: ${WOLFBOOT_TARGET}") +message(STATUS "CMake version: ${CMAKE_VERSION}") +message(STATUS "Generator: ${CMAKE_GENERATOR}") +message(STATUS "Source dir: ${CMAKE_SOURCE_DIR}") +message(STATUS "Binary dir: ${CMAKE_BINARY_DIR}") cmake_minimum_required(VERSION 3.16) +include(cmake/config_defaults.cmake) + +#--------------------------------------------------------------------------------------------- +# Initial environment checks +#--------------------------------------------------------------------------------------------- if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") message( FATAL_ERROR - "In-source builds are not allowed.\ + "In-source builds are not allowed for wolfBoot.\ Run cmake from a separate directory from where CMakeLists.txt lives.\ NOTE: cmake will now create CMakeCache.txt and CMakeFiles/*.\ You must delete them, or cmake will refuse to work.") endif() +# This must appear before project(wolfBoot) +if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) + if(DEFINED WOLFBOOT_TARGET AND + NOT WOLFBOOT_TARGET STREQUAL "x86_64_efi" AND + NOT WOLFBOOT_TARGET STREQUAL "sim") + set(CMAKE_TOOLCHAIN_FILE + "${CMAKE_CURRENT_LIST_DIR}/cmake/toolchain_arm-none-eabi.cmake" + CACHE FILEPATH "" FORCE) + endif() +endif() + +if(NOT DEFINED PREFERRED_HOST_CC_NAME_LIST OR PREFERRED_HOST_CC_NAME_LIST STREQUAL "") + # set(PREFERRED_HOST_CC_NAME_LIST gcc clang cl) + if(CMAKE_HOST_WIN32) + set(PREFERRED_HOST_CC_NAME_LIST gcc clang cl) + else() + set(PREFERRED_HOST_CC_NAME_LIST gcc clang cl) + endif() + message(STATUS "Setting preferred order for HOST_CC:${PREFERRED_HOST_CC_NAME_LIST}") +else() + message(STATUS "Found preferred order for HOST_CC:${PREFERRED_HOST_CC_NAME_LIST}") +endif() + +#--------------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- project(wolfBoot) +#--------------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- + +# Simulator target is POSIX-only (uses sys/mman.h, etc.) +if(MSVC AND (DEFINED WOLFBOOT_TARGET) AND (WOLFBOOT_TARGET STREQUAL "sim")) + message(FATAL_ERROR "TARGET_sim is POSIX-only. Use a device preset (e.g. stm32h7) or build the sim on Linux/WSL/MinGW.") +endif() -include(cmake/utils.cmake) include(cmake/functions.cmake) +include(cmake/utils.cmake) + +# Windows users may prefer VisualGDB +if(DETECT_VISUALGDB) + message(STATUS "VisualGDB detection active: cmake/visualgdb_config.cmake") + include(cmake/visualgdb_config.cmake) +endif() + +# Some OS-specific checks and configs +if(CMAKE_HOST_WIN32 AND DETECT_VS2022) + message(STATUS "Visual Studio 2022 detection active: make/vs2022_config.cmake") + include(cmake/vs2022_config.cmake) +endif() + +# If not VisualGDB, perhaps ST CubeIDE? +if(DETECT_CUBEIDE AND NOT FOUND_HAL_BASE) + include(cmake/cube_ide_config.cmake) +endif() + +# If still not found, download: +if(NOT FOUND_HAL_BASE AND ENABLE_HAL_DOWNLOAD) + if(WOLFBOOT_TARGET MATCHES "^stm32") + include(cmake/stm32_hal_download.cmake) + else() + message(STATUS "WARNING: HAL not found and download not available for ${WOLFBOOT_TARGET}") + endif() +endif() + +if(USE_DOT_CONFIG) + message(STATUS "USE_DOT_CONFIG is enabled") + include(cmake/load_dot_config.cmake) +else() + message(STATUS "No .config files will be read; USE_DOT_CONFIG is disabled") +endif() -include_directories(include) -include_directories(lib/wolfssl) +# Edit to stop CMake from appending any "standard" C include paths that it thinks your toolchain/platform needs +# Brute force, not recommended, ymmv. +if(false) + set(CMAKE_C_STANDARD_INCLUDE_DIRECTORIES "" CACHE STRING "" FORCE) +endif() + +#------------------- Host compiler (for native tools only) ----------------------------------- +#--------------------------------------------------------------------------------------------- +# Build-time tools (bin-assemble/sign/keygen) must compile for the HOST. +if (CMAKE_HOST_WIN32) + # Prefer gcc/clang on Windows so POSIX-y headers (unistd.h) are available. + message(STATUS "Tip: If find_program cannot find HOST_CC (not in path?), try launching from VS2022 dev prompt or edit path.") + message(STATUS "ARM_GCC_BIN=${ARM_GCC_BIN}") + if(DEFINED HOST_CC AND EXISTS "${HOST_CC}") + message(STATUS "HOST_CC already defined, not using HOST_CC_HINT_DIRECTORIES") + message(STATUS "Using preset HOST_CC: ${HOST_CC}") + else() + unset(HOST_CC CACHE) + message(STATUS "HOST_CC not defined, will attempt to find...") + message(STATUS "HOST_CC_HINT_DIRECTORIES contents:") + foreach(_hint_item IN LISTS HOST_CC_HINT_DIRECTORIES) + if(IS_DIRECTORY "${_hint_item}") + set(_hint_status "(ok)") + else() + set(_hint_status "NOT FOUND:") + endif() + message("-- ${_hint_status} ${_hint_item}") + endforeach() + find_program(HOST_CC + NAMES ${PREFERRED_HOST_CC_NAME_LIST} REQUIRED + HINTS ${HOST_CC_HINT_DIRECTORIES} + ) + endif() + message(STATUS "HOST_CC=${HOST_CC}") + get_filename_component(_host_name "${HOST_CC}" NAME) + message(STATUS "Detected HOST_CC executable: ${_host_name}") + message(STATUS "CMAKE_C_COMPILER=${CMAKE_C_COMPILER}") + + # Not with LLVM, nor GCC: + set(HOST_LINK_FLAG "") + + if (HOST_CC MATCHES [[(^|[/\\])cl(\.exe)?$]] OR (HOST_CC MATCHES [[(^|[/\\])clang-cl(\.exe)?$]])) + # DOS/Windows detected by ".exe" extension, not to be confused with WSL and/or WinGW + message(STATUS "Found CMAKE_HOST_WIN32 and .exe in HOST_CC: Setting HOST_IS_MSVC") + #------------------------------------------------------------------------------------- + set(HOST_IS_MSVC TRUE) + #------------------------------------------------------------------------------------- + # Are we running in Visual Studio 2022 or VSCode from VS2022 command prompt? + print_env(VSCMD_VER) + print_env(VCToolsInstallDir) + print_env(VCINSTALLDIR) + print_env(WindowsSdkDir) + set(HOST_EXE ".exe") + set(HOST_O2 /O2) + set(HOST_I /I) + set(HOST_D /D) + set(HOST_OUT /Fe:) + # Put .obj files in a private folder to avoid collisions & root litter: + set(HOST_OBJDIR "${CMAKE_CURRENT_BINARY_DIR}/obj") + file(MAKE_DIRECTORY "${HOST_OBJDIR}") + set(HOST_FO "/Fo$") + set(HOST_WARN "") # MSVC warnings already noisy; keep simple + # Detect pointer size -> host arch name (x64/x86) + if (HOST_CC MATCHES [[Hostx64[/\\]x64]] OR CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "AMD64|x86_64") + set(HOST_ARCH x64) + set(HOST_MACHINE_FLAG /MACHINE:X64) + else() + set(HOST_ARCH x86) + set(HOST_MACHINE_FLAG /MACHINE:X86) + endif() + message(STATUS "HOST_CC suggests HOST_ARCH=${HOST_ARCH}") + if(USE_32BIT_LIBS AND NOT ("${HOST_ARCH}" STREQUAL "x86")) + message(STATUS "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + MESSAGE(STATUS "USE_32BIT_LIBS set to true but HOST_ARCH=${HOST_ARCH}") + message(STATUS "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + endif() + if(USE_64BIT_LIBS AND NOT ("${HOST_ARCH}" STREQUAL "x64")) + message(STATUS "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + MESSAGE(STATUS "USE_64BIT_LIBS set to true but HOST_ARCH=${HOST_ARCH}") + message(STATUS "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + endif() + + # Gather Windows SDK & MSVC libpaths from env (vcvarsall sets these) + set(HOST_WINSDK_UCRT "") + set(HOST_WINSDK_UM "") + set(HOST_MSVC_LIB "") + + if (DEFINED ENV{WindowsSdkDir} AND DEFINED ENV{WindowsSDKLibVersion}) + set(HOST_WINSDK_UCRT "$ENV{WindowsSdkDir}/Lib/$ENV{WindowsSDKLibVersion}/ucrt/${HOST_ARCH}") + set(HOST_WINSDK_UM "$ENV{WindowsSdkDir}/Lib/$ENV{WindowsSDKLibVersion}/um/${HOST_ARCH}") + endif() + + if (DEFINED ENV{VCToolsInstallDir}) + set(HOST_MSVC_LIB "$ENV{VCToolsInstallDir}/lib/${HOST_ARCH}") + endif() + + # Prefer dynamic CRT explicitly (avoid stale tool defaults) + set(HOST_RUNTIME_FLAG /MD) # or /MT if you want static CRT + + # Set link flag only for Microsoft compilers + set(HOST_LINK_FLAG /link) + + # wolfSSL random on Windows needs Advapi32: + set(HOST_LINK_LIBS Advapi32.lib) + else() + # gcc or clang + #------------------------------------------------------------------------------------- + set(HOST_IS_MSVC FALSE) + #------------------------------------------------------------------------------------- + set(HOST_EXE "") + set(HOST_O2 -O2) + set(HOST_I -I) + set(HOST_D -D) + set(HOST_OUT -o) + set(HOST_FO "") # gcc/clang handle objs internally here + set(HOST_WARN -Wall -Wextra -Werror) + # set(HOST_LINK_LIBS "") # not needed with MinGW/clang on Windows + set(HOST_LINK_LIBS -ladvapi32) + set(HOST_RUNTIME_FLAG "") + endif() + + # On Windows, binaries should end with .exe regardless of flag style + set(HOST_EXE ".exe") +else() + # POSIX hosts + foreach(_hint_item IN LISTS HOST_CC_HINT_DIRECTORIES) + message("-- ${_hint_item}") + endforeach() + message(STATUS "PREFERRED_HOST_CC_NAME_LIST=${PREFERRED_HOST_CC_NAME_LIST}") + find_program(HOST_CC NAMES ${PREFERRED_HOST_CC_NAME_LIST} REQUIRED) + set(HOST_IS_MSVC FALSE) + set(HOST_EXE "") + set(HOST_O2 -O2) + set(HOST_I -I) + set(HOST_D -D) + set(HOST_OUT -o) + set(HOST_FO "") + set(HOST_WARN -Wall -Wextra -Werror) + + set(HOST_LINK_FLAG "") + set(HOST_LINK_LIBS "") + set(HOST_RUNTIME_FLAG "") +endif() + +message(STATUS "Host CC: ${HOST_CC}") +message(STATUS "Host compiler treated as MSVC: ${HOST_IS_MSVC}") + +#--------------------------------------------------------------------------------------------- +# Common includes/defines for host tools +#--------------------------------------------------------------------------------------------- +set(HOST_INCLUDES + ${HOST_I}$ + ${HOST_I}$ + ${HOST_I}$ + ${HOST_I}$ # Reminder target.h typically gets generated here +) + +if(NOT DEFINED IMAGE_HEADER_SIZE) + set(IMAGE_HEADER_SIZE 256) +endif() + +set(HOST_DEFS + ${HOST_D}WOLFSSL_USER_SETTINGS + ${HOST_D}IMAGE_HEADER_SIZE=${IMAGE_HEADER_SIZE} + ${HOST_D}DELTA_UPDATES +) + +# --- Hard-pin the algorithms the host tools must support (only for host tools) --- +# This guarantees sign.c compiles with these on MSVC even if SIGN_OPTIONS plumbing misses. + +list(APPEND HOST_DEFS + ${HOST_D}WOLFBOOT_SIGN_ED25519 + ${HOST_D}WOLFBOOT_HASH_SHA256) + + +# --- Windows unistd.h shim for MSVC host builds --- +if(CMAKE_HOST_WIN32 AND (HOST_IS_MSVC OR HOST_CC MATCHES [[(^|[/\\])clang(\.exe)?$]])) + set(HOST_SHIM_DIR "${CMAKE_CURRENT_BINARY_DIR}/host_shims") + file(MAKE_DIRECTORY "${HOST_SHIM_DIR}") + + # Minimal shims; extend if bin-assemble needs more. + file(WRITE "${HOST_SHIM_DIR}/unistd.h" [=[ +#ifndef _WIN32 +# error "This shim is for Windows/MSVC only" +#endif +#include +#include +#include +#include + +#ifndef ssize_t +# ifdef _WIN64 + typedef long long ssize_t; +# else + typedef int ssize_t; +# endif +#endif + +#ifndef unlink +# define unlink _unlink +#endif +#ifndef close +# define close _close +#endif +#ifndef read +# define read _read +#endif +#ifndef write +# define write _write +#endif +#ifndef access +# define access _access +#endif +]=]) + + # Prepend shim include so it is found first + list(INSERT HOST_INCLUDES 0 ${HOST_I}$) +endif() # Windows Host Shim + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl +) + +if ("${WOLFBOOT_TARGET}" STREQUAL "") + message(STATUS "Setting WOLFBOOT_TARGET from TARGET=${TARGET}") + set(WOLFBOOT_TARGET "${TARGET}") +endif() if(NOT DEFINED WOLFBOOT_TARGET) message(FATAL_ERROR "WOLFBOOT_TARGET must be defined") @@ -59,7 +365,7 @@ 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 stm32l5 stm32u5 stm32wb ti zynqmp) + 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) set(ARM_TARGETS "${ARM_TARGETS}" CACHE INTERNAL "") @@ -145,7 +451,7 @@ if(NOT DEFINED PULL_LINKER_DEFINES AND NOT DEFINED BUILD_TEST_APPS) message(FATAL_ERROR "WOLFBOOT_PARTITION_SIZE must be defined") endif() - if(NOT DEFINED WOLFBOOT_PARTITION_BOOT_ADDRESS) + if((NOT DEFINED WOLFBOOT_PARTITION_BOOT_ADDRESS) OR ("${WOLFBOOT_PARTITION_BOOT_ADDRESS}" STREQUAL "")) message(FATAL_ERROR "WOLFBOOT_PARTITION_BOOT_ADDRESS must be defined") endif() @@ -158,7 +464,7 @@ if(NOT DEFINED PULL_LINKER_DEFINES AND NOT DEFINED BUILD_TEST_APPS) endif() endif() -# unset cache variables Variables that need to be accessed by the gen_wolfboot_platform_target cmake +# unset cache variables variables that need to be accessed by the gen_wolfboot_platform_target cmake # function called from the parent cmake project are added to the cache so that they can be accessed # anywhere in the project unset(WOLFBOOT_DEFS CACHE) @@ -173,44 +479,72 @@ unset(SIGN_TOOL CACHE) unset(SIGN_OPTIONS CACHE) unset(KEYTOOL_OPTIONS CACHE) unset(BINASSEMBLE CACHE) -unset(ARCH_FLASH_OFFSET CACHE) unset(WOLFBOOT_VERSION CACHE) +unset(ARCH_FLASH_OFFSET CACHE) if(EXTRA_DEFS) string(REPLACE " " ";" WOLFBOOT_EXTRA_DEFS ${EXTRA_DEFS}) list(APPEND WOLFBOOT_DEFS ${WOLFBOOT_EXTRA_DEFS}) endif() -set(WOLFBOOT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) +# Ensure WOLFBOOT_ROOT is set. Prefer env var, else default to "." +# WOLFBOOT_ROOT is typically a lib directory in wolfBoot and contains: +# wolfHSM, wolfPKCS11, wolfssl, wolfTPM, and perhaps others. +if(NOT DEFINED WOLFBOOT_ROOT OR WOLFBOOT_ROOT STREQUAL "") + if(DEFINED ENV{WOLFBOOT_ROOT} AND NOT "$ENV{WOLFBOOT_ROOT}" STREQUAL "") + message(STATUS "Setting WOLFBOOT_ROOT from environment variable") + set(WOLFBOOT_ROOT "$ENV{WOLFBOOT_ROOT}" CACHE PATH "Path to wolfBoot lib root") + else() + message(STATUS "Setting WOLFBOOT_ROOT to default current directory.") + set(WOLFBOOT_ROOT ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Path to wolfBoot lib root") + endif() +endif() +message(STATUS "WOLFBOOT_ROOT=${WOLFBOOT_ROOT}") +set(SIZE_SCRIPT "${WOLFBOOT_ROOT}/cmake/write_size.cmake") + list(APPEND WOLFBOOT_DEFS __WOLFBOOT) -set(WOLFBOOT_SOURCES include/loader.h include/image.h src/string.c src/image.c) +set(WOLFBOOT_SOURCES "include/loader.h" + "include/image.h" + "src/string.c" + "src/image.c" + "src/loader.c") -list(APPEND WOLFBOOT_SOURCES src/loader.c) +# build bin-assemble tool Windows +set(BINASSEMBLE ${CMAKE_CURRENT_BINARY_DIR}/bin-assemble${HOST_EXE}) +set(BINASSEMBLE_OBJDIR "${CMAKE_CURRENT_BINARY_DIR}/obj_bin_assemble") -# build bin-assemble tool -set(BINASSEMBLE ${CMAKE_CURRENT_BINARY_DIR}/bin-assemble) add_custom_command( - OUTPUT ${BINASSEMBLE} - COMMAND gcc tools/bin-assemble/bin-assemble.c -o ${BINASSEMBLE} - WORKING_DIRECTORY ${WOLFBOOT_ROOT} - COMMENT "Generating bin-assemble tool") + OUTPUT "${BINASSEMBLE}" + COMMAND "${CMAKE_COMMAND}" -E make_directory ${BINASSEMBLE_OBJDIR} + COMMAND "${HOST_CC}" ${HOST_O2} ${HOST_WARN} ${HOST_RUNTIME_FLAG} + ${HOST_INCLUDES} # <-- needed for unistd.h shim + ${HOST_FO} # /Fo$ # isolate objs + ${HOST_OUT}$ + $ + ${HOST_LINK_FLAG} ${HOST_LINK_LIBS} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + COMMENT "Building bin-assemble tool" +) add_custom_target(binAssemble DEPENDS ${BINASSEMBLE}) -# ----------------------------------------------------------------------------- +#----------------------------------------------------------------------------------------- # Toolchain Specifications -# ----------------------------------------------------------------------------- - -if(ARCH STREQUAL "ARM") - include(cmake/toolchain_arm-none-eabi.cmake) -elseif(ARCH STREQUAL "AARCH64") - include(cmake/toolchain_aarch64-none-elf.cmake) +#----------------------------------------------------------------------------------------- +if(NOT CMAKE_C_COMPILER) + # Ensure include only once + if(ARCH STREQUAL "ARM") + include(cmake/toolchain_arm-none-eabi.cmake) + elseif(ARCH STREQUAL "AARCH64") + include(cmake/toolchain_aarch64-none-elf.cmake) + endif() endif() -# ----------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------------------- # Architecture/CPU configuration -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- set(UPDATE_SOURCES src/update_flash.c) # Default flash offset @@ -263,7 +597,8 @@ if(ARCH STREQUAL "ARM") ) endif() - if(${WOLFBOOT_TARGET} STREQUAL "stm32u5") + # TODO move these to presets + if(${WOLFBOOT_TARGET} STREQUAL "stm32g0") set(ARCH_FLASH_OFFSET 0x08000000) set(WOLFBOOT_ORIGIN ${ARCH_FLASH_OFFSET}) endif() @@ -272,6 +607,11 @@ if(ARCH STREQUAL "ARM") set(ARCH_FLASH_OFFSET 0x08000000) set(WOLFBOOT_ORIGIN ${ARCH_FLASH_OFFSET}) endif() + if(${WOLFBOOT_TARGET} STREQUAL "stm32u5") + set(ARCH_FLASH_OFFSET 0x08000000) + set(WOLFBOOT_ORIGIN ${ARCH_FLASH_OFFSET}) + endif() + endif() if(ARCH STREQUAL "AARCH64") @@ -301,9 +641,9 @@ if(${WOLFBOOT_TARGET} STREQUAL "x86_64_efi") set(UPDATE_SOURCES src/update_ram.c) endif() -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- # DSA Settings -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- if(SIGN STREQUAL "NONE") list(APPEND KEYTOOL_OPTIONS --no-sign) message(STATUS "Image signing disabled") @@ -320,10 +660,6 @@ else() set(WOLFBOOT_SIGNING_PRIVATE_KEY ${CMAKE_CURRENT_BINARY_DIR}/wolfboot_signing_private_key.der) endif() -if(NOT DEFINED IMAGE_HEADER_SIZE) - set(IMAGE_HEADER_SIZE 256) -endif() - if(WOLFBOOT_SMALL_STACK) list(APPEND USER_SETTINGS WOLFBOOT_SMALL_STACK) list(APPEND WOLFBOOT_DEFS XMALLOC_USER) @@ -477,7 +813,15 @@ list(APPEND WOLFBOOT_DEFS IMAGE_HEADER_SIZE=${IMAGE_HEADER_SIZE}) # Append sign options to compile definitions list(APPEND WOLFBOOT_DEFS ${SIGN_OPTIONS}) -list(APPEND WOLFBOOT_COMPILE_OPTIONS -Wstack-usage=${STACK_USAGE} -Wno-unused) +# Turn SIGN_OPTIONS (plain symbols) into real compiler -D flags for host tools +set(SIGN_DEFS "") +foreach(_opt IN LISTS SIGN_OPTIONS) + list(APPEND SIGN_DEFS ${HOST_D}${_opt}) +endforeach() + +#--------------------------------------------------------------------------------------------- +# Settings +#--------------------------------------------------------------------------------------------- if(PULL_LINKER_DEFINES) list(APPEND WOLFBOOT_DEFS PULL_LINKER_DEFINES) @@ -568,27 +912,30 @@ list(APPEND WOLFBOOT_SOURCES ${UPDATE_SOURCES}) list(TRANSFORM WOLFBOOT_SOURCES PREPEND ${WOLFBOOT_ROOT}/) -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- # Hash settings -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- if(HASH STREQUAL "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 SIGN_OPTIONS WOLFBOOT_HASH_SHA384) list(APPEND KEYTOOL_OPTIONS --sha384) endif() if(HASH STREQUAL "SHA3") list(APPEND WOLFBOOT_DEFS WOLFBOOT_HASH_SHA3_384) + list(APPEND SIGN_OPTIONS WOLFBOOT_HASH_SHA3_384) list(APPEND KEYTOOL_OPTIONS --sha3) endif() -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- # wolfboot HAL -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- # Default SPI driver name set(SPI_TARGET ${WOLFBOOT_TARGET}) @@ -654,23 +1001,251 @@ target_compile_definitions(user_settings INTERFACE ${USER_SETTINGS} ${SIGN_OPTIO add_library(wolfboothal) target_sources(wolfboothal PRIVATE include/hal.h hal/${WOLFBOOT_TARGET}.c ${WOLFBOOT_FLASH_SOURCES} ${PARTITION_SOURCE}) -target_link_libraries(wolfboothal target user_settings) + + +#--------------------------------------------------------------------------------------------- +# --- HAL for STM32L4 (only the pieces we need) --- +#--------------------------------------------------------------------------------------------- +# TODO move this to preset and/or cmake dir +if(WOLFBOOT_TARGET STREQUAL "stm32l4") + message(STATUS "HAL_DRV=${HAL_DRV}") + add_library(stm32l4_hal STATIC + ${HAL_DRV}/Src/stm32l4xx_hal.c + ${HAL_DRV}/Src/stm32l4xx_hal_flash.c + ${HAL_DRV}/Src/stm32l4xx_hal_flash_ex.c + ${HAL_DRV}/Src/stm32l4xx_hal_cortex.c + # add more modules later if you get missing symbols, e.g. RCC/GPIO/etc: + # ${HAL_DRV}/Src/stm32l4xx_hal_rcc.c + # ${HAL_DRV}/Src/stm32l4xx_hal_gpio.c + ) + + target_include_directories(stm32l4_hal BEFORE PUBLIC + ${WOLFBOOT_ROOT}/hal + ${HAL_DRV}/Inc + ${HAL_CMSIS_DEV} + ${HAL_CMSIS_CORE} + ${HAL_TEMPLATE_INC} + ) + + target_compile_definitions(stm32l4_hal PUBLIC + USE_HAL_DRIVER + STM32L475xx + # If your stm32l4xx_hal_conf.h doesn't enable FLASH, you can force it: + # HAL_FLASH_MODULE_ENABLED + ) + + # Link HAL into the HAL wrapper lib so the final image pulls symbols from a single archive + target_link_libraries(wolfboothal PUBLIC target user_settings stm32l4_hal) +else() + target_link_libraries(wolfboothal target user_settings) +endif() + target_compile_definitions(wolfboothal PRIVATE ${WOLFBOOT_DEFS}) target_include_directories(wolfboothal PRIVATE ${WOLFBOOT_ROOT} include) target_compile_options(wolfboothal PRIVATE ${WOLFBOOT_COMPILE_OPTIONS} ${EXTRA_COMPILE_OPTIONS}) message(STATUS "Using C Keytools") -set(SIGN_TOOL ${CMAKE_CURRENT_BINARY_DIR}/sign) -set(KEYGEN_TOOL ${CMAKE_CURRENT_BINARY_DIR}/keygen) + +#--------------------------------------------------------------------------------------------- +# define sources/flags BEFORE the custom commands that use them +#--------------------------------------------------------------------------------------------- +list( + APPEND + KEYTOOL_SOURCES + src/delta.c + lib/wolfssl/wolfcrypt/src/asn.c + lib/wolfssl/wolfcrypt/src/aes.c + lib/wolfssl/wolfcrypt/src/ecc.c + lib/wolfssl/wolfcrypt/src/coding.c + lib/wolfssl/wolfcrypt/src/chacha.c + lib/wolfssl/wolfcrypt/src/ed25519.c + lib/wolfssl/wolfcrypt/src/ed448.c + lib/wolfssl/wolfcrypt/src/fe_operations.c + lib/wolfssl/wolfcrypt/src/ge_operations.c + lib/wolfssl/wolfcrypt/src/fe_448.c + lib/wolfssl/wolfcrypt/src/ge_448.c + lib/wolfssl/wolfcrypt/src/hash.c + lib/wolfssl/wolfcrypt/src/logging.c + lib/wolfssl/wolfcrypt/src/memory.c + lib/wolfssl/wolfcrypt/src/random.c + lib/wolfssl/wolfcrypt/src/rsa.c + lib/wolfssl/wolfcrypt/src/sp_int.c + lib/wolfssl/wolfcrypt/src/sp_c32.c + lib/wolfssl/wolfcrypt/src/sp_c64.c + lib/wolfssl/wolfcrypt/src/sha3.c + lib/wolfssl/wolfcrypt/src/sha256.c + lib/wolfssl/wolfcrypt/src/sha512.c + lib/wolfssl/wolfcrypt/src/tfm.c + lib/wolfssl/wolfcrypt/src/wc_port.c + lib/wolfssl/wolfcrypt/src/wolfmath.c + lib/wolfssl/wolfcrypt/src/dilithium.c + lib/wolfssl/wolfcrypt/src/wc_lms.c + lib/wolfssl/wolfcrypt/src/wc_lms_impl.c + lib/wolfssl/wolfcrypt/src/wc_xmss.c + lib/wolfssl/wolfcrypt/src/wc_xmss_impl.c +) + +set(KEYTOOL_SOURCES_ABS ${KEYTOOL_SOURCES}) +list(TRANSFORM KEYTOOL_SOURCES_ABS PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/) + +list(APPEND KEYTOOL_FLAGS + -Wall -Wextra -Werror + -I$ + -DWOLFSSL_USER_SETTINGS + -I$ + -I$ + -I$ + -O2 + -DIMAGE_HEADER_SIZE=${IMAGE_HEADER_SIZE} + -DDELTA_UPDATES +) + + +#--------------------------------------------------------------------------------------------- +# sign tool +#--------------------------------------------------------------------------------------------- +set(SIGN_TOOL ${CMAKE_CURRENT_BINARY_DIR}/sign${HOST_EXE}) + +# Give VS a debuggable, runnable target that points to the produced exe +add_executable(sign_host IMPORTED GLOBAL) +set_target_properties(sign_host PROPERTIES + IMPORTED_LOCATION "${SIGN_TOOL}" + VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + # VS_DEBUGGER_COMMAND_ARGUMENTS "test.bin wolfboot_signing_private_key.der 1 --ed25519 --sha256" +) + +# Ensure the exe is (re)built before F5 +add_dependencies(sign_host keytools) + +# Optional: make F5 pick this by default +set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT sign_host) + +set(SIGN_OBJDIR "${CMAKE_CURRENT_BINARY_DIR}/obj_sign") +if(HOST_IS_MSVC) + # isolate objs only for Windows (.exe) + set(HOST_FO_SIGN "/Fo$") + set(HOST_UNDEF /Umin /Umax /USIGN /UHASH /TC) # /TC = compile as C +else() + set(HOST_FO_SIGN "") # No /Fo for most environments + + # Optional strict mode (-std=c11) fails on WSL, missing include files + # set(HOST_UNDEF -Umin -Umax -USIGN -UHASH -std=c11) + message(STATUS "Setting -std=gnu11 for HOST_CC=${HOST_CC}") + set(HOST_UNDEF -Umin -Umax -USIGN -UHASH -std=gnu11) +endif() + +# After you set HOST_IS_MSVC / HOST_CC, add: +if(true) + if (HOST_IS_MSVC) + set(HOST_UNDEF /Umin /Umax /USIGN /UHASH /TC) # /TC = compile as C + else() + # Optional strict mode (-std=c11) fails on WSL, missing include files + # set(HOST_UNDEF -Umin -Umax -USIGN -UHASH -std=c11) + message(STATUS "Setting -std=gnu11 for HOST_CC=${HOST_CC}") + set(HOST_UNDEF -Umin -Umax -USIGN -UHASH -std=gnu11) + endif() +endif() + add_custom_command( + OUTPUT ${SIGN_TOOL} + COMMAND "${CMAKE_COMMAND}" -E make_directory ${SIGN_OBJDIR} + COMMAND "${HOST_CC}" ${HOST_O2} ${HOST_WARN} ${HOST_RUNTIME_FLAG} + ${HOST_INCLUDES} ${HOST_DEFS} ${HOST_UNDEF} ${SIGN_DEFS} + ${HOST_FO_SIGN} + $ + ${KEYTOOL_SOURCES_ABS} + ${HOST_OUT}$ + ${HOST_LINK_FLAG} ${HOST_LINK_LIBS} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + COMMENT "Building signing tool" + ) + +add_custom_target(keytools ALL DEPENDS ${SIGN_TOOL} ${KEYGEN_TOOL}) + +set_target_properties(sign_host PROPERTIES + IMPORTED_LOCATION_DEBUG "${SIGN_TOOL}" + IMPORTED_LOCATION_RELEASE "${SIGN_TOOL}" +) + + +set(SIGN_TOOL ${SIGN_TOOL} CACHE INTERNAL "") + +#--------------------------------------------------------------------------------------------- +# keygen +#--------------------------------------------------------------------------------------------- +set(KEYGEN_TOOL ${CMAKE_CURRENT_BINARY_DIR}/keygen${HOST_EXE}) +set(KEYGEN_OBJDIR "${CMAKE_CURRENT_BINARY_DIR}/obj_keygen") +if (HOST_IS_MSVC) + set(HOST_FO_KEYGEN "/Fo$") +else() + set(HOST_FO_KEYGEN "") +endif() + +add_custom_command( + OUTPUT ${KEYGEN_TOOL} + COMMAND "${CMAKE_COMMAND}" -E make_directory ${KEYGEN_OBJDIR} + COMMAND "${HOST_CC}" ${HOST_O2} ${HOST_WARN} ${HOST_RUNTIME_FLAG} + ${HOST_INCLUDES} ${HOST_DEFS} ${HOST_UNDEF} ${SIGN_DEFS} + ${HOST_FO_KEYGEN} + $ + ${KEYTOOL_SOURCES_ABS} + ${HOST_OUT}$ + ${HOST_LINK_FLAG} ${HOST_LINK_LIBS} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Building keygen tool" +) + +add_custom_target(keygen_build DEPENDS ${KEYGEN_TOOL}) +add_dependencies(keytools keygen_build) +set(KEYGEN_TOOL ${KEYGEN_TOOL} CACHE INTERNAL "") list(APPEND WOLFBOOT_INCLUDE_DIRS ${WOLFBOOT_ROOT} ${WOLFBOOT_ROOT}/include) # set default linker script set(WOLFBOOT_LSCRIPT_TEMPLATE hal/${WOLFBOOT_TARGET}.ld) +#--------------------------------------------------------------------------------------------- # wolfcrypt +#--------------------------------------------------------------------------------------------- +# ---- MUST be placed before add_subdirectory(lib) ---- +# Globally sanitize MSVC builds so wolfSSL sources don't inherit bad macros. +# ---- MUST be placed before add_subdirectory(lib) ---- +# Make each option a SEPARATE list element; one genex per option. +if (MSVC) + add_compile_options( + $<$:/Zc:preprocessor> + $<$:/Umin> + $<$:/Umax> + $<$:/USIGN> + $<$:/UHASH> + ) + add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN) +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 ${WOLFSSL_TGT}) + target_compile_definitions(${WOLFSSL_TGT} PRIVATE NOMINMAX WIN32_LEAN_AND_MEAN) + target_compile_options(${WOLFSSL_TGT} PRIVATE + $<$:/Umin> + $<$:/Umax> + $<$:/USIGN> + $<$:/UHASH> + $<$:/Zc:preprocessor> + ) + endif() + if(BUILD_TEST_APPS OR BUILD_IMAGE) message(STATUS "Building wolfBoot image") add_subdirectory(test-app) @@ -727,100 +1302,45 @@ configure_file(include/target.h.in ${CMAKE_CURRENT_BINARY_DIR}/target.h @ONLY) add_library(target INTERFACE) target_compile_definitions(target INTERFACE ${WOLFBOOT_DEFS}) -target_include_directories(target BEFORE INTERFACE ${CMAKE_CURRENT_BINARY_DIR} lib/wolfssl) - -set(KEYSTORE ${CMAKE_CURRENT_BINARY_DIR}/keystore.c) - -list( - APPEND - KEYTOOL_SOURCES - src/delta.c - lib/wolfssl/wolfcrypt/src/asn.c - lib/wolfssl/wolfcrypt/src/aes.c - lib/wolfssl/wolfcrypt/src/ecc.c - lib/wolfssl/wolfcrypt/src/coding.c - lib/wolfssl/wolfcrypt/src/chacha.c - lib/wolfssl/wolfcrypt/src/ed25519.c - lib/wolfssl/wolfcrypt/src/ed448.c - lib/wolfssl/wolfcrypt/src/fe_operations.c - lib/wolfssl/wolfcrypt/src/ge_operations.c - lib/wolfssl/wolfcrypt/src/fe_448.c - lib/wolfssl/wolfcrypt/src/ge_448.c - lib/wolfssl/wolfcrypt/src/hash.c - lib/wolfssl/wolfcrypt/src/logging.c - lib/wolfssl/wolfcrypt/src/memory.c - lib/wolfssl/wolfcrypt/src/random.c - lib/wolfssl/wolfcrypt/src/rsa.c - lib/wolfssl/wolfcrypt/src/sp_int.c - lib/wolfssl/wolfcrypt/src/sp_c32.c - lib/wolfssl/wolfcrypt/src/sp_c64.c - lib/wolfssl/wolfcrypt/src/sha3.c - lib/wolfssl/wolfcrypt/src/sha256.c - lib/wolfssl/wolfcrypt/src/sha512.c - lib/wolfssl/wolfcrypt/src/tfm.c - lib/wolfssl/wolfcrypt/src/wc_port.c - lib/wolfssl/wolfcrypt/src/wolfmath.c - lib/wolfssl/wolfcrypt/src/dilithium.c - lib/wolfssl/wolfcrypt/src/wc_lms.c - lib/wolfssl/wolfcrypt/src/wc_lms_impl.c - lib/wolfssl/wolfcrypt/src/wc_xmss.c - lib/wolfssl/wolfcrypt/src/wc_xmss_impl.c -) - -list( - APPEND - KEYTOOL_FLAGS - -Wall - -Wextra - -Werror - -Itools/keytools - -DWOLFSSL_USER_SETTINGS - -Ilib/wolfssl/ - -Iinclude - -I${CMAKE_CURRENT_BINARY_DIR} - -O2 - -DIMAGE_HEADER_SIZE=${IMAGE_HEADER_SIZE} - -DDELTA_UPDATES) - -add_custom_command( - OUTPUT ${SIGN_TOOL} - COMMAND gcc -o ${CMAKE_CURRENT_BINARY_DIR}/sign tools/keytools/sign.c ${KEYTOOL_SOURCES} - ${KEYTOOL_FLAGS} - WORKING_DIRECTORY ${WOLFBOOT_ROOT} - COMMENT "Building signing tool") - -add_custom_command( - OUTPUT ${KEYGEN_TOOL} - COMMAND gcc -o ${CMAKE_CURRENT_BINARY_DIR}/keygen tools/keytools/keygen.c ${KEYTOOL_SOURCES} - ${KEYTOOL_FLAGS} - WORKING_DIRECTORY ${WOLFBOOT_ROOT} - COMMENT "Building keygen tool") +target_include_directories(target BEFORE INTERFACE + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/lib/wolfssl) -add_custom_target(keytools ALL DEPENDS ${SIGN_TOOL} ${KEYGEN_TOOL}) +#--------------------------------------------------------------------------------------------- +# keystore +#--------------------------------------------------------------------------------------------- +set(KEYSTORE ${CMAKE_CURRENT_BINARY_DIR}/keystore.c) if(NOT SIGN STREQUAL "NONE") - add_custom_target(keystore DEPENDS ${SIGN_TOOL} ${KEYGEN_TOOL} ${KEYSTORE}) - - # generate keystore if it does not already exist - if(NOT EXISTS ${KEYSTORE}) - add_custom_command( - OUTPUT ${KEYSTORE} ${WOLFBOOT_SIGNING_PRIVATE_KEY} - COMMAND ${KEYGEN_TOOL} ${KEYTOOL_OPTIONS} -g ${WOLFBOOT_SIGNING_PRIVATE_KEY} - -keystoreDir ${CMAKE_CURRENT_BINARY_DIR} - WORKING_DIRECTORY ${WOLFBOOT_ROOT} - COMMENT "Generating keystore.c and signing private key") - - add_custom_command( - OUTPUT ${KEYSTORE} ${WOLFBOOT_SIGNING_PRIVATE_KEY} - DEPENDS ${KEYGEN_TOOL} - APPEND) - endif() + add_custom_target(keystore DEPENDS ${KEYGEN_TOOL} ${KEYSTORE}) + + # generate keystore.c if it does not already exist + message(STATUS "Will generate fresh: ${KEYSTORE}") + message(STATUS " with KEYGEN_TOOL: ${KEYGEN_TOOL}") + message(STATUS " and options: ${KEYTOOL_OPTIONS}") + message(STATUS " with key file: ${WOLFBOOT_SIGNING_PRIVATE_KEY}") + + add_custom_command( + OUTPUT ${KEYSTORE} ${WOLFBOOT_SIGNING_PRIVATE_KEY} + COMMAND "${KEYGEN_TOOL}" ${KEYTOOL_OPTIONS} + --no-overwrite + -g ${WOLFBOOT_SIGNING_PRIVATE_KEY} + -keystoreDir ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${KEYGEN_TOOL} + WORKING_DIRECTORY ${WOLFBOOT_ROOT} + COMMENT "Generating keystore.c and signing private key" + VERBATIM + ) add_library(public_key) - target_sources(public_key PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/keystore.c) + target_sources(public_key PRIVATE ${KEYSTORE}) target_compile_definitions(public_key PRIVATE ${WOLFBOOT_DEFS}) target_include_directories(public_key PRIVATE include) target_link_libraries(public_key target) + + # Ensure the tool exists before anything tries to build public_key, + # and also make the explicit custom target a dependency if you like: + add_dependencies(public_key keygen_build keystore) endif() # generate libwolfboot @@ -829,7 +1349,44 @@ target_sources(wolfboot PRIVATE src/libwolfboot.c ${WOLFBOOT_FLASH_SOURCES}) target_compile_definitions(wolfboot PUBLIC ${WOLFBOOT_DEFS}) target_compile_options(wolfboot PUBLIC ${EXTRA_COMPILE_OPTIONS}) target_include_directories(wolfboot PUBLIC ${WOLFBOOT_INCLUDE_DIRS}) -target_link_libraries(wolfboot wolfboothal target wolfcrypt) +target_link_libraries(wolfboot wolfboothal target ${WOLFSSL_TGT}) + +if(HOST_IS_MSVC) # Some VS2022 helpers + message(STATUS "==============================================================================") + message(STATUS "Begin sign host") + message(STATUS "==============================================================================") + foreach(_t IN ITEMS wolfssl wolfcrypt) + if (TARGET ${_t}) + set_target_properties(${_t} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib + ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/lib/Debug + ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/lib/Release + DEBUG_POSTFIX "" + ) + endif() + endforeach() + + message(STATUS "WOLFSSL_TGT=${WOLFSSL_TGT}") + add_dependencies(sign_host ${WOLFSSL_TGT}) + add_dependencies(sign_host keytools) + + if(MSVC) + message(STATUS "Found MSVC") + else() + message(STATUS "Did not find MSVC") + endif() + message(STATUS "CMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}") + message(STATUS "CMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}") + message(STATUS "CMAKE_C_COMPILER_FRONTEND_VARIANT=${CMAKE_C_COMPILER_FRONTEND_VARIANT}") + message(STATUS "CMAKE_CXX_COMPILER_FRONTEND_VARIANT=${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}") + message(STATUS "MSVC var = ${MSVC}") + + target_compile_options(wolfboot PRIVATE ${SIM_COMPILE_OPTIONS}) + + set_property(TARGET sign_host PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS + "test.bin wolfboot_signing_private_key.der 1 --ed25519 --sha256") + set_property(TARGET sign_host PROPERTY VS_DEBUGGER_WORKING_DIRECTORY + "${CMAKE_CURRENT_BINARY_DIR}") +endif() # HOST_IS_MSVC VS2022 helpers -# dont warn on unused code -target_compile_options(wolfboot PRIVATE -Wno-unused ${SIM_COMPILE_OPTIONS}) +message(STATUS "End [WOLFBOOT_ROOT]/CmakeLists.txt") diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000000..909104110a --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,346 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 22, + "patch": 0 + }, + "configurePresets": [ + { + "name": "sign_hash_config", + "displayName": "Common Sign and Hash command-line params", + "hidden": true, + "cacheVariables": { + "SIGN": "ED25519", + "HASH": "SHA256" + } + }, + { + "name": "sim", + "displayName": "~No config selected", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-sim", + "cacheVariables": { + "SIGN": "ED25519", + "HASH": "SHA256", + "WOLFBOOT_TARGET": "sim", + "WOLFBOOT_SECTOR_SIZE": "256", + "WOLFBOOT_CONFIG_MODE": "preset", + "WOLFBOOT_HAS_BASE_PRESET": true, + "ARCH": "HOST", + "SPMATH": "ON", + "DISABLE_BACKUP": "OFF", + "NVM_FLASH_WRITEONCE": "ON", + "BUILD_TEST_APPS": "ON", + "WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08003000", + "WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08009400", + "WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x0800F800", + "WOLFBOOT_PARTITION_SIZE": "0x6400" + } + }, + { + "name": "base_build", + "description": "Basic build directory", + "hidden": true, + "binaryDir": "${sourceDir}/build" + }, + { + "name": "base_build_presetName", + "description": "Device specific build directory", + "hidden": true, + "binaryDir": "${sourceDir}/build-${presetName}" + }, + { + "name": "base_build_env_presetName", + "description": "Device and environment specific build directory", + "hidden": true, + "binaryDir": "${sourceDir}/build-$env{TERM_PROGRAM}$env{VSCMD_VER}$env{WSL_DISTRO_NAME}-${presetName}" + }, + { + "name": "base", + "description": "Edit the build directory inherits setting for all presets.", + "hidden": true, + "inherits": "base_build_presetName", + "cacheVariables": { + "WOLFBOOT_CONFIG_MODE": "preset", + "WOLFBOOT_HAS_BASE_PRESET": true + } + }, + { + "name": "stm32", + "hidden": true, + "generator": "Ninja", + "cacheVariables": { + "ST_CMSIS_CORE_TAG": "5.9.0" + } + }, + { + "name": "_template-target", + "displayName": "_sample - target - template", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-template", + "environment": { + "PATH": "$penv{LOCALAPPDATA}/Microsoft/WinGet/Links;C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/14.2 rel1/bin;$penv{PATH}" + }, + "cacheVariables": { + "ENV_REMINDER": "use env for cache, penv elsewhere", + "WOLFBOOT_CONFIG_MODE": "preset", + "VISUALGDB": "ON", + "CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake", + "WOLFBOOT_TARGET": "stm32l4" + } + }, + { + "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": "stm32c0", + "displayName": "STM32C0", + "inherits": [ + "base", + "sign_hash_config", + "stm32" + ], + "cacheVariables": { + "WOLFBOOT_TARGET": "stm32c0", + "ST_HAL_TAG": "v1.4.0", + "ST_CMSIS_TAG": "v1.3.0", + "ARCH": "ARM", + "DEBUG": "OFF", + "VTOR": "ON", + "CORTEX_M0": "ON", + "NO_ASM": "OFF", + "NO_MPU": "ON", + "EXT_FLASH": "OFF", + "SPI_FLASH": "OFF", + "ALLOW_DOWNGRADE": "OFF", + "NVM_FLASH_WRITEONCE": "ON", + "WOLFBOOT_VERSION": "OFF", + "V": "OFF", + "SPMATH": "ON", + "DUALBANK_SWAP": "OFF", + "RAM_CODE": "OFF", + "WOLFBOOT_PARTITION_SIZE": "0x2000", + "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" + } + }, + { + "name": "stm32f1", + "displayName": "stm32f1", + "inherits": [ + "base", + "stm32" + ], + "cacheVariables": { + "WOLFBOOT_TARGET": "stm32f1", + "ARCH": "ARM", + "VTOR": "OFF", + "SPMATH": "ON", + "DISABLE_BACKUP": "OFF", + "NVM_FLASH_WRITEONCE": "ON", + "WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08003000", + "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" + } + }, + { + "name": "stm32g0", + "displayName": "stm32g0", + "inherits": [ + "base", + "sign_hash_config", + "stm32" + ], + "cacheVariables": { + "WOLFBOOT_TARGET": "stm32g0", + "ARCH": "ARM", + "DEBUG": "OFF", + "VTOR": "ON", + "CORTEX_M0": "ON", + "NO_ASM": "OFF", + "EXT_FLASH": "OFF", + "SPI_FLASH": "OFF", + "ALLOW_DOWNGRADE": "OFF", + "NVM_FLASH_WRITEONCE": "ON", + "WOLFBOOT_VERSION": "OFF", + "V": "OFF", + "SPMATH": "ON", + "RAM_CODE": "ON", + "DUALBANK_SWAP": "OFF", + "WOLFBOOT_PARTITION_SIZE": "0xB000", + "WOLFBOOT_SECTOR_SIZE": "0x800", + "ARCH_FLASH_OFFSET": "0x08000000", + "WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08008000", + "WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08013000", + "WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x0801E000", + "CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake", + "BUILD_TEST_APPS": "ON" + } + }, + { + "name": "stm32h7", + "displayName": "STM32H7", + "inherits": [ + "base", + "sign_hash_config", + "stm32" + ], + "generator": "Ninja", + "cacheVariables": { + "ST_HAL_TAG": "v1.10.6", + "ST_CMSIS_TAG": "v1.7.4", + "CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake", + "WOLFBOOT_TARGET": "stm32h7", + "BUILD_TEST_APPS": "yes", + "ARCH": "ARM", + "DEBUG": "OFF", + "DEBUG_UART": "OFF", + "VTOR": "ON", + "NO_ASM": "OFF", + "EXT_FLASH": "OFF", + "SPI_FLASH": "OFF", + "QSPI_FLASH": "OFF", + "OCTOSPI_FLASH": "OFF", + "ALLOW_DOWNGRADE": "OFF", + "NVM_FLASH_WRITEONCE": "OFF", + "WOLFBOOT_VERSION": "ON", + "V": "OFF", + "SPMATH": "ON", + "RAM_CODE": "OFF", + "DUALBANK_SWAP": "OFF", + "WOLFBOOT_PARTITION_SIZE": "0xD0000", + "WOLFBOOT_SECTOR_SIZE": "0x20000", + "WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x8020000", + "WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x80F0000", + "WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x81C0000" + } + }, + { + "name": "stm32l4", + "displayName": "STM32L4", + "inherits": [ + "base", + "sign_hash_config", + "stm32" + ], + "environment": { + "VSCMD_DEBUG": "3" + }, + "cacheVariables": { + "WOLFBOOT_TARGET": "stm32l4", + "WOLFBOOT_DOWNLOADS_CMAKE": "${sourceDir}/cmake/downloads/stm32l4.cmake", + "STM32L4_PART": "STM32L475xx", + "BOARD": "B-L475E-IOT01A", + "ARCH": "ARM", + "DEBUG": "OFF", + "VTOR": "ON", + "CORTEX_M0": "OFF", + "NO_ASM": "OFF", + "EXT_FLASH": "OFF", + "SPI_FLASH": "OFF", + "ALLOW_DOWNGRADE": "OFF", + "NVM_FLASH_WRITEONCE": "ON", + "WOLFBOOT_VERSION": "OFF", + "V": "OFF", + "SPMATH": "ON", + "RAM_CODE": "OFF", + "DUALBANK_SWAP": "OFF", + "IMAGE_HEADER_SIZE": "256", + "WOLFBOOT_SECTOR_SIZE": "0x1000", + "WOLFBOOT_PARTITION_SIZE": "0x7A000", + "WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x0800A000", + "WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08084000", + "WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x080FE000", + "WOLFTPM": "OFF", + "CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake", + "BUILD_TEST_APPS": "ON" + } + } + ], + "buildPresets": [ + { + "name": "~No config (wolfBoot sim)", + "configurePreset": "sim", + "jobs": 4, + "verbose": true, + "targets": [ + "all" + ] + }, + { + "name": "stm32c0", + "configurePreset": "stm32c0", + "jobs": 4, + "verbose": true, + "targets": [ + "all" + ] + }, + { + "name": "stm32f1", + "configurePreset": "stm32f1", + "jobs": 4, + "verbose": true, + "targets": [ + "all" + ] + }, + { + "name": "stm32g0", + "configurePreset": "stm32g0", + "jobs": 4, + "verbose": true, + "targets": [ + "all" + ] + }, + { + "name": "stm32h7", + "configurePreset": "stm32h7", + "jobs": 4, + "verbose": true, + "targets": [ + "all" + ] + }, + { + "name": "stm32l4", + "configurePreset": "stm32l4", + "jobs": 4, + "verbose": true, + "targets": [ + "all" + ] + }, + { + "name": "vs-debug-trace", + "configurePreset": "vs-debug-trace", + "jobs": 4, + "verbose": true, + "targets": [ + "all" + ] + } + ] +} diff --git a/IDE/VSCode/README.md b/IDE/VSCode/README.md new file mode 100644 index 0000000000..c0442319ce --- /dev/null +++ b/IDE/VSCode/README.md @@ -0,0 +1,91 @@ +# VS Code wolfBoot Project + +CMake presets are support in VS Code. See also details in the [cmake/README.md](../../cmake/README). + +Open the `WOLFBOOT_ROOT`[wolfBoot.code-workspace](../../wolfBoot.code-workspace) in VSCode. + +For example, select `STM32L4` wait for CMake to finish, then click `build`. The `output` pane might be not visible. Grab frame to expand up: + +image

+ +----- + +## Quick Start + +If all of the prerequisites (see below) are already installed: + +```bash +git clone https://github.com/wolfssl/wolfBoot.git +cd wolfBoot/IDE/VSCode +git submodule update --init + +code wolfBoot.code-workspace +``` + +If all of the prerequisites are NOT installed, see the [install.sh](./install.sh) script. + +----- + +## Additional Settings + +See the [cmake/config_defaults.cmake](../../cmake/config_defaults.cmake) file. Of particular interest +are some environment configuration settings: + +```cmake +# Environments are detected in this order: +set(DETECT_VISUALGDB true) +set(DETECT_CUBEIDE true) +set(DETECT_VS2022 true) + +# Enable HAL download only implemented for TMS devices at this time. +# See [WOLFBOOT_ROOT]/cmake/stm32_hal_download.cmake +# and [WOLFBOOT_ROOT]/cmake/downloads/stm32_hal_download.cmake +set(ENABLE_HAL_DOWNLOAD true) +set(FOUND_HAL_BASE false) + +# optionally use .config files; See CMakePresets.json instead +set(USE_DOT_CONFIG false) +``` + +----- + +## Requirements + +### VS Code extensions + +- [CMake Tools (ms-vscode.cmake-tools)](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) +- C/C++ (ms-vscode.cpptools) +- Cortex-Debug (marus25.cortex-debug) + +### Build tools + +#### WSL path: + +cmake, ninja-build, gcc-arm-none-eabi, openocd + +#### Windows path: + +Windows path: CMake, Ninja, Arm GNU Toolchain, OpenOCD (or ST’s OpenOCD) + +Install via PowerShell (will need to restart VSCode): + +```ps +winget install --id Ninja-build.Ninja -e + + +# winget install -e --id Arm.GnuArmEmbeddedToolchain + +winget install -e --id Arm.GnuArmEmbeddedToolchain --override "/S /D=C:\Tools\arm-gnu-toolchain-14.2.rel1" +# reopen VS / terminal so PATH refreshes + +# Confirm +ninja --version + +Get-Command arm-none-eabi-gcc +``` + +If already installed, uninstall: + +``` +winget uninstall -e --id Arm.GnuArmEmbeddedToolchain +``` diff --git a/IDE/VSCode/install.sh b/IDE/VSCode/install.sh new file mode 100644 index 0000000000..e61b4213bf --- /dev/null +++ b/IDE/VSCode/install.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +# From an already-cloned wolfBoot: +# +# ./IDE/VSCode/install.sh +# +# or +# cd IDE/VSCode +# ./install.sh +# +# VSCode can be installed: +# +# https://code.visualstudio.com/download +# +# Or: +# +# sudo snap install --classic code + +# Begin common dir init, for [WOLFBOOT_ROOT]/IDE/VSCode +# Resolve this script's absolute path and its directories +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_PATH="${SCRIPT_DIR}/$(basename -- "${BASH_SOURCE[0]}")" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" + +# Normalize to physical paths (no symlinks, no trailing slashes) +# SCRIPT_DIR_P="$(cd -- "$SCRIPT_DIR" && pwd -P)" +REPO_ROOT_P="$(cd -- "$REPO_ROOT" && pwd -P)" +CALLER_CWD_P="$(pwd -P)" # where the user ran the script from + +# Print only if caller's cwd is neither REPO_ROOT nor REPO_ROOT/scripts +case "$CALLER_CWD_P" in + "$REPO_ROOT_P" | "$REPO_ROOT_P"/scripts) + : # silent + ;; + *) + echo "Script paths:" + echo "-- SCRIPT_PATH =$SCRIPT_PATH" + echo "-- SCRIPT_DIR =$SCRIPT_DIR" + echo "-- REPO_ROOT =$REPO_ROOT" + ;; +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)" +# End common dir init + +pwd +exit 0 + + +git clone https://github.com/gojimmypi/wolfBoot.git +cd wolfBoot + + +sudo apt-get update +sudo apt-get install -y pass gnupg2 +sudo apt-get install -y autoconf automake libtool +sudo apt-get install -y make +sudo apt-get install -y g++ +sudo apt-get install -y gawk +sudo apt-get install -y build-essential clang clang-tidy +sudo apt-get install -y cppcheck shellcheck valgrind +sudo apt-get install -y pcre2-utils # provides pcre2grep +sudo apt-get install -y qemu-user qemu-system-x86 +sudo apt-get install -y wine # or wine64 on 64-bit + +sudo apt-get install cmake +sudo apt-get install ninja-build + +cd IDE/VSCode + +sudo apt-get install -y snapd +sudo snap install --classic code + +code wolfBoot.code-workspace diff --git a/IDE/VSCode/wolfBoot.code-workspace b/IDE/VSCode/wolfBoot.code-workspace new file mode 100644 index 0000000000..9c32d7d739 --- /dev/null +++ b/IDE/VSCode/wolfBoot.code-workspace @@ -0,0 +1,168 @@ +/* [WOLFBOOT_ROOT]/IDE/VSCode/wolfBoot.code-workspace + * + * 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 + */ +{ + "folders": [ + { + "name": "wolfBoot", + + /* This workspace is found two directories deep in [WOLFBOOT_ROOT]/IDE/VSCode */ + "path": "../.." + } + ], + + /* Extension expected */ + "extensions": { + "recommendations": [ + "ms-vscode.cmake-tools", + "ms-vscode.cpptools", + "marus25.cortex-debug" + ] + }, + + /* Alternative to [WOLFBOOT_ROOT]/.vscode/settings.json */ + "settings": { + /* Pick a default config to work immediately upon opening project */ + "cmake.defaultConfigurePreset": "stm32l4", + "cmake.defaultBuildPreset": "stm32l4", + + /* current, unified switch. Enables using all presets from CMakePresets.json file: + * configure, build, test, package, workflow - and drives the UI accordingly. */ + "cmake.useCMakePresets": "always", + + /* This is a legacy setting for older versions */ + "cmake.useConfigurePresets": "always", + + "cmake.configureOnOpen": true, + + /* Ensure Status Bar icons are enabled. The default is "hidden". + * + * Ctrl-Shift-P CMake:Open CMake Tools Extension Settings + * + * Status Bar Visibility: + * + * @ext:ms-vscode.cmake-tools stat + * + * See also CMake icon (3D Triangle with Wrench) + */ + "cmake.options.statusBarVisibility": "visible", + + "cmake.loggingLevel": "info", + + /* Make the project root the source dir no matter where VS Code is opened */ + "cmake.sourceDirectory": "${workspaceFolder:wolfBoot}", + + /* One build dir per preset under the repo root */ + "cmake.buildDirectory": "${workspaceFolder:wolfBoot}/build-vsc-${buildPresetName}", + + "cmake.preferredGenerators": [ + "Ninja", + "Ninja Multi-Config", + "Unix Makefiles", + "Visual Studio 17 2022" + ], + + "cmake.generator": "Ninja", + + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "files.encoding": "utf8", + "files.eol": "\n" + }, + + /* Alternative to [WOLFBOOT_ROOT]/.vscode/tasks.json */ + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "CMake: Configure (active)", + "command": "cmake", + "args": [ + "--preset", + "${command:cmake.activeConfigurePresetName}" + ], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "problemMatcher": [] + }, + { + "label": "CMake: Build (active)", + "command": "cmake", + "args": [ + "--build", + "--preset", + "${command:cmake.activeBuildPresetName}" + ], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "group": "build", + "problemMatcher": "$gcc" + }, + { + "label": "CMake: Clean (active)", + "command": "cmake", + "args": [ + "--build", + "--preset", + "${command:cmake.activeBuildPresetName}", + "--target", + "clean" + ], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "problemMatcher": [] + }, + { + "label": "OpenOCD: Flash wolfBoot (active)", + "type": "shell", + "command": "openocd", + "args": [ + "-f", + "interface/stlink-dap.cfg", + "-f", + "target/stm32l4x.cfg", + "-c", + "program ${command:cmake.buildDirectory}/wolfboot.elf verify reset exit" + ], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "problemMatcher": [] + } + ] + }, + + /* Alternative to [WOLFBOOT_ROOT]/.vscode/launch.json */ + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "STM32L4 - OpenOCD (active preset)", + "type": "cortex-debug", + "request": "launch", + "servertype": "openocd", + "cwd": "${workspaceFolder:wolfBoot}", + "device": "STM32L475VG", + "svdFile": "${workspaceFolder:wolfBoot}/hal/stm32l4/STM32L4x.svd", + "executable": "${command:cmake.buildDirectory}/wolfboot.elf", + "configFiles": [ + "interface/stlink-dap.cfg", + "target/stm32l4x.cfg" + ], + "runToMain": true, + "preLaunchTask": "CMake: Build (active)" + } + ] + } +} diff --git a/IDE/Windows/README.md b/IDE/Windows/README.md new file mode 100644 index 0000000000..86f08489b2 --- /dev/null +++ b/IDE/Windows/README.md @@ -0,0 +1,34 @@ +# wolfboot for Windows + +A variety of Windows-based solutions exist. Here are notes for a no-IDE build on Windows from a DOS prompt. + +See also: + +- [VS Code](../VSCode/README.md) +- [CMake docs](../../CMake.md) +- [Compile docs](../../compile.md) +- [Windows docs](../../Windows.md) +- [Other docs](../../README.md) + +# Example + +See the [`[WOLFBOOT_ROOT]/tools/scripts/cmake_test.bat`](../../tools/scripts/cmake_test.bat) using cmake: + +```dos +rmdir /s /q build-stm32l4 + +cmake --preset stm32l4 +cmake --build --preset stm32l4 +``` + +## Troubleshooting + +#### cannot access the file + +This error is typically caused by anti-virus software locking a file during build. + +Consider excluding the build directory or executable from anti-virus scan. + +```test +build-stm32l4\bin-assemble.exe - The process cannot access the file because it is being used by another process. +``` diff --git a/INSTALL.md b/INSTALL.md index 4ebe75a880..133fa1a89c 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,4 +1,4 @@ -# wolfBoot Setup Instructions +# wolfBoot Setup Instructions ## Gathering Sources @@ -40,7 +40,7 @@ wolfBoot -> src -> image.c (crypto verify/hash) -> loader.c (main) - -> libwolfboot.c (User application API’s) + -> libwolfboot.c (User application API's) -> update_*.c (flash/ram wolfBoot_start) -> test-app (example applications) -> tools @@ -68,14 +68,14 @@ The signing key used goes into wolfBoot root (example `rsa4096.der`). make ``` -The “make [target]” +The `make [target]` * `keytools`: Build the C version of the key tools * `wolfboot.bin`: Build the .elf and .bin version of the bootloader only * `test-app/image.bin`: Builds the test application * `test-app/image_v1_signed.bin`: Builds the test application signed with version 1 * `factory.bin`: Builds bootloader and test application signed and appended together -Note: Default is “factory.bin” +Note: Default is `factory.bin` ## Building with Cross Compile diff --git a/README.md b/README.md index d07c084a7f..084040f21b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# wolfBoot +# wolfBoot -wolfSSL Secure Bootloader ([Home page](https://www.wolfssl.com/products/wolfboot/)) +wolfSSL Secure Bootloader ([Home page](https://www.wolfssl.com/products/wolfboot/), [Manual](https://www.wolfssl.com/documentation/manuals/wolfboot/), [wolfBoot-examples](https://github.com/wolfSSL/wolfBoot-examples)) wolfBoot is a portable, OS-agnostic, secure bootloader solution for 32-bit microcontrollers, relying on wolfCrypt for firmware authentication, providing firmware update mechanisms. @@ -39,6 +39,12 @@ The bootloader consists of the following components: - The core bootloader - A small application library used by the application to interact with the bootloader [src/libwolfboot.c](src/libwolfboot.c) +## Requirements + +### Linux + +Ensure the proper toolchain is installed. See the [docs](./docs/README.md) for platform-specific details. + ## Integrating wolfBoot in an existing project ### Required steps @@ -120,7 +126,57 @@ make keytools make ``` -### CMake +### CMake - Presets + +This section explains how to build wolfBoot using CMake Presets. +Presets let you keep repeatable build settings in a single JSON file ([CMakePresets.json](./CMakePresets.json)) so +you can configure and build with short, memorable commands like: + +``` +cmake --list-presets +cmake --preset stm32l4 +cmake --build --preset stm32l4 +``` + +See the `WOLFBOOT_ROOT`/[config_defaults.cmake](./config_defaults.cmake) file. + +#### Convert existing `.config` to CMake Presets + +The [tools/scripts/config2presets.py](./tools/scripts/config2presets.py) script cam +convert existing [config/examples](./config/examples) to CMake presets. + +For example: + +```python +python3 ./tools/scripts/config2presets.py ./config/examples/stm32h7.config +``` + +#### Tips & Gotchas + +Out-of-source enforced: wolfBoot’s CMakeLists.txt blocks in-source builds; +presets default to `build-${presetName}` anyway. + +Toolchain auto-select: If `WOLFBOOT_TARGET` is not x86_64_efi or sim, +CMAKE_TOOLCHAIN_FILE defaults to `cmake/toolchain_arm-none-eabi.cmake`. + +Windows host tools: When HOST_CC is `cl.exe`, CMakeLists.txt creates a +lightweight `unistd.h` shim and adjusts flags—no manual changes needed. + +`$penv` vs `$env`: Use `$penv{VAR}` in environment to append to the existing +process environment (keeps your PATH). `$env{VAR}` replaces it. + +Visual Studio / VS Code: Both detect presets automatically; +select the preset from the status bar or CMake menu, then build. + +`--fresh`: Re-configure from scratch without deleting the build directory. + +For further details, see the [cmake/README](./cmake/README.md) + +### CMake - Read .config file + +See [cmake/README](./cmake/README.md#build-with-cmake-using-config-files). + +### CMake - Command-line Settings To build using CMake, create a `build` directory and run `cmake` with the target platform as well as values for the partition size and address variables. To build the test-apps, run with `-DBUILD_TEST_APPS=yes`. To use the wolfCrypt-py keytools, run @@ -241,12 +297,12 @@ options to configuring wolfBoot, add `-LAH` to your cmake command, along with th $ cmake -DWOLFBOOT_TARGET=stm32h7 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x8020000 -DWOLFBOOT_SECTOR_SIZE=0x20000 -DWOLFBOOT_PARTITION_SIZE=0xD0000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80F0000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81C0000 -LAH .. ``` -##### stm32f4 +#### stm32f4 ``` $ cmake -DWOLFBOOT_TARGET=stm32f4 -DWOLFBOOT_PARTITION_SIZE=0x20000 -DWOLFBOOT_SECTOR_SIZE=0x20000 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x08020000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x08040000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x08060000 .. ``` -##### stm32u5 +#### stm32u5 ``` $ cmake -DWOLFBOOT_TARGET=stm32u5 -DBUILD_TEST_APPS=yes -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x08100000 -DWOLFBOOT_SECTOR_SIZE=0x2000 -DWOLFBOOT_PARTITION_SIZE=0x20000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x817F000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81FE000 -DNO_MPU=yes .. ``` @@ -256,7 +312,6 @@ $ cmake -DWOLFBOOT_TARGET=stm32u5 -DBUILD_TEST_APPS=yes -DWOLFBOOT_PARTITION_BOO $ cmake -DWOLFBOOT_TARGET=stm32l0 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x8000 -DWOLFBOOT_SECTOR_SIZE=0x1000 -DWOLFBOOT_PARTITION_SIZE=0x10000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x18000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x28000 -DNVM_FLASH_WRITEONCE=yes .. ``` - ## Troubleshooting 1. Python errors when signing a key: @@ -297,6 +352,44 @@ The error `Key algorithm mismatch. Remove old keys via 'make keysclean'` indicat Use `make keysclean` to delete keys and regenerate. +3. Cannot open compiler generated file ... Permission denied + +This may occur due to multiple environments being opened concurrently, or anti-virus software. +Try manually deleting the respective build directories and/or restarting your IDE. + +```text +sp_c32.c : fatal error C1083: Cannot open compiler generated file: '... sp_c32.obj': Permission denied +``` + +4. unresolved external symbol __imp____acrt_iob_fun + +``` +unresolved external symbol __imp____acrt_iob_func referenced in function _main +``` + +5. expected expression before ';' around WOLFBOOT_PARTITION_BOOT_ADDRESS + +Search for `#define WOLFBOOT_PARTITION_BOOT_ADDRESS` with no value. +Sometimes a failed config will generate a bad file. (typically `target.h`) + +Rename the file with a `.bak` extension and let the build process generate a fresh one. +Consider also deleting the entire build directory. + +``` +/src/libwolfboot.c:724:64: error: expected expression before ';' token + 724 | address = (uint32_t)WOLFBOOT_PARTITION_BOOT_ADDRESS; +``` + +6. 'stdint.h': No such file or directory + +Check the compiler order in `PREFERRED_HOST_CC_NAME_LIST`, See `HOST_CC` in the logs. + +For Visual Studio, the developer command prompt will need to be activated. + +``` +\wolfBoot\tools\keytools\sign.c(33): fatal error C1083: Cannot open include file: 'stdio.h': No such file or directory +``` + ## Release Notes ### v1.0 (2018-12-04) @@ -690,12 +783,12 @@ Use `make keysclean` to delete keys and regenerate. * RP2350 (Raspberry Pi Pico 2, ARM Cortex-M33 with TrustZone) * NXP MCXA153 * NXP MCXW716 - * STM32F1 series (STM32F103 “Blue Pill” board) + * STM32F1 series (STM32F103 "Blue Pill" board) * Improvements to supported targets * Xilinx UltraScale+ (ZynqMP) * Added hardware-accelerated SHA3 hashing via the CSU engine * Added support for enabling JTAG at runtime when `CSU_DEBUG` is set - * Introduced support for the device’s PUF (Physically Unclonable Function) for unique key generation and secure key storage (requires eFuses) + * Introduced support for the device's PUF (Physically Unclonable Function) for unique key generation and secure key storage (requires eFuses) * Renesas RX * Added option for TSIP hardware crypto engine * Infineon TriCore (AURIX TC3xx) @@ -725,7 +818,7 @@ Use `make keysclean` to delete keys and regenerate. * Added support for x509 auth with wolfHSM in server mode * Added support for encrypted updates on Renesas RX (also via TSIP) * Added support for assembly optimizations for PowerPC 32bit (SHA, AES) - * STM32F4: new clock configuration to support all models, added support for STM32F411 + * STM32F4: new clock configuration to support all models, added support for STM32F411 * Bugfixes: * Fixed unaligned access in Cortex-A5 * Fixed compile flags to properly run code from RAM on ARM diff --git a/cmake/README.md b/cmake/README.md new file mode 100644 index 0000000000..7f6ca47c90 --- /dev/null +++ b/cmake/README.md @@ -0,0 +1,565 @@ +# wolfBoot Cmake + +Review the [Keystore Docs](../docs/keystore.md) and [Signing Docs](../docs/Signing.md) +regarding backup and storage of the generated `src/keystore.c` file. This file +is excluded from source in `.gitignore`). + +**Save to a safe place outside of the wolfBoot tree.** + +See the local [config_defaults.cmake](./config_defaults.cmake) file. Of particular interest +are some environment configuration settings: + +```cmake +# Environments are detected in this order: +set(DETECT_VISUALGDB true) +set(DETECT_CUBEIDE true) +set(DETECT_VS2022 true) + +# Enable HAL download only implemented for TMS devices at this time. +# See [WOLFBOOT_ROOT]/cmake/stm32_hal_download.cmake +# and [WOLFBOOT_ROOT]/cmake/downloads/stm32_hal_download.cmake +set(ENABLE_HAL_DOWNLOAD true) +set(FOUND_HAL_BASE false) + +# optionally use .config files; See CMakePresets.json instead +set(USE_DOT_CONFIG false) +``` + +## cmake Directory Overview + +- [`WOLFBOOT_ROOT`/CMakeLists.txt](../CMakeLists.txt) - Top-level CMake entry that configures the wolfBoot build. +Used to initialize the project, include cmake/wolfboot.cmake, set options, and define targets. +This file is where `project()` is declared and where toolchain logic or preset imports begin. + +- [`WOLFBOOT_ROOT`/CMakePresets.json](../CMakePresets.json) - OS-agnostic CMake preset definitions. +Used by `cmake --preset {name}` and `cmake --build --preset {name}` to apply consistent settings. +Centralizes toolchain paths, target names, build directories, and key cache variables such as: +`{ "CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake", "WOLFBOOT_TARGET": "stm32l4" }`. + +- [`WOLFBOOT_ROOT`/CMakeSettings.json](../CMakeSettings.json) - Visual Studio integration file. +Maps Visual Studio configurations (Debug, Release) to existing CMake presets. +Controls IntelliSense, environment variables, and the preset shown in the VS CMake toolbar. + +- [preset-examples/CMakeUserPresets.json.sample](./preset-examples/CMakeUserPresets.json.sample) - Example local overrides for user-specific paths and options. Copy to `CMakeUserPresets.json` in the `WOLFBOOT_ROOT` directory and customize. Not committed. Copy to `WOLFBOOT_ROOT` and remove the `.sample` suffix. + +- [config_defaults.cmake](./config_defaults.cmake) - Default cache values and feature toggles used when presets or .config do not provide them. + +- [cube_ide_config.cmake](./cube_ide_config.cmake) - Optional STM32CubeIDE integration. Maps CubeIDE variables or project layout into CMake context. + +- [current_user.cmake](./current_user.cmake) - Cross-platform detection of the current user for path composition and cache hints. + +- [downloads](./downloads) - Series-specific scripts and docs for fetching STM32 HAL and CMSIS artifacts on demand. + +- [functions.cmake](./functions.cmake) - Reusable helper functions for path checks, argument validation, status output, and small build utilities. + +- [load_dot_config.cmake](./load_dot_config.cmake) - Imports legacy `.config` values from Makefile-based builds into modern CMake cache variables. + +- [stm32_hal_download.cmake](./stm32_hal_download.cmake) - Common download logic used by downloads/stm32*.cmake modules to fetch HAL and CMSIS. + +- [toolchain_aarch64-none-elf.cmake](./toolchain_aarch64-none-elf.cmake) - Bare-metal AArch64 toolchain configuration for 64-bit ARM targets. + +- [toolchain_arm-none-eabi.cmake](./toolchain_arm-none-eabi.cmake) - Main Cortex-M cross toolchain config. Disables try-run, standardizes flags, and sets compilers. + +- [utils.cmake](./utils.cmake) - Lightweight utilities shared by other modules. Path normalization, small helpers, and logging wrappers. + +- [visualgdb_config.cmake](./visualgdb_config.cmake) - VisualGDB quality-of-life settings for Windows builds that use Sysprogs BSPs. + +- [vs2022_config.cmake](./vs2022_config.cmake) - Visual Studio 2022 integration hints. Keeps generator and environment consistent with VS CMake. + +- [wolfboot.cmake](./wolfboot.cmake) - wolfBoot CMake glue: targets, include directories, compile definitions, and link rules. + +- [downloads/README.md](./downloads/README.md) - Notes for the downloads subsystem and expected directory layout. + +- [downloads/stm32l4.cmake](./downloads/stm32l4.cmake) - STM32L4 fetch script for HAL and CMSIS. + +- [`WOLFBOOT_ROOT`/.vs/VSWorkspaceSettings.json](../.vs/VSWorkspaceSettings.json) - Exclusion directories: Visual Studio tries to be "helpful" and open a solution file. This is undesired when opening a directory as a CMake project. +--- + +### Build with cmake using `.config` files + +Presets are preferred instead of `.config`, see below. + +To use `.config` files instead of presets, + +```bash +# cd your [WOLFBOOT_ROOT] + +# Backup current config +mv ./.config ./.config.bak + +# Get an example config +cp ./config/examples/stm32h7.config ./.config + +# Call cmake with -DUSE_DOT_CONFIG=ON +cmake -S . -B build-stm32h7 -DUSE_DOT_CONFIG=ON + +# Sample build +cmake --build build-stm32h7 -j +``` + +The output should look contain text like this: + +```text +-- Found a .config file, will parse +-- Config mode: dot (.config cache) +-- Loading config from: /mnt/c/workspace/wolfBoot-gojimmypi +-- Reading config file: /mnt/c/workspace/wolfBoot-gojimmypi/.config +-- -- Parsing lines from config file... +-- -- Found line: ARCH?=ARM +-- -- Parsed key: ARCH +-- -- Parsed op: ? +-- -- Parsed val: ARM +-- -- Assignment: ARCH=ARM +-- -- Found line: TARGET?=stm32h7 +-- -- Parsed key: TARGET +-- -- Parsed op: ? +-- -- Parsed val: stm32h7 +-- -- Assignment: TARGET=stm32h7 +-- -- Found line: SIGN?=ECC256 +-- -- Parsed key: SIGN +-- -- Parsed op: ? +-- -- Parsed val: ECC256 + ...etc... +``` + +Calling `cmake` with an existing `.config` file will default to dot-config mode. + +```bash +ls .config +cmake -S . -B build-stm32h7 +``` + +Specify additional directories, for example the STM32L4: + +```bash +cmake -S . -B build-stm32l4 -DUSE_DOT_CONFIG=ON \ + -DHAL_DRV="${VG_BASE}/Drivers/STM32L4xx_HAL_Driver" \ + -DHAL_CMSIS_DEV="${VG_BASE}/Drivers/CMSIS/Device/ST/STM32L4xx/Include" \ + -DHAL_CMSIS_CORE="${VG_BASE}/Drivers/CMSIS/Include" \ + -DHAL_TEMPLATE_INC="${VG_BASE}/Drivers/STM32L4xx_HAL_Driver/Inc" + +cmake --build build-stm32l4 -j +``` + +### Build presets + +Each configure preset has a matching build preset with jobs=4, verbose=true, and targets=["all"]. + +Example commands: + +```bash +cmake --preset stm32l4 +cmake --build --preset stm32l4 + +cmake --preset stm32h7 +cmake --build --preset stm32h7 +``` + +### CMake User Presets. + +See the [preset-examples/CMakeUserPresets.json.sample(./preset-examples/CMakeUserPresets.json.sample). +Copy the file to `WOLFBOOT_ROOT` and remove the`.sample` suffix: `CMakeUserPresets.json`. + +It is critically important that none the names of a user preset do not conflict with regular presets. + +For instance, the sample extends and overrides some of the `stm32l4` settings, +using LLVM clang on Windows, and prefixes ALL the names with `my-`: + +```json +{ + "version": 3, + "configurePresets": [ + { + "name": "my-stm32l4", + "displayName": "my STM32L4", + "inherits": [ + "stm32l4" + ], + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-my-stm32l4", + "cacheVariables": { + "ARM_GCC_BIN": "C:/SysGCC/arm-eabi/bin", + "HOST_CC": "C:/Program Files/LLVM/bin/clang.exe" + } + } + ], + "buildPresets": [ + { + "name": "my-stm32l4", + "configurePreset": "my-stm32l4" + } + ] +} +``` + + +From the [docs for CMake Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html): + +>"Added in version 3.19. +> +>One problem that CMake users often face is sharing settings with other people for common ways to configure +a project. This may be done to support CI builds, or for users who frequently use the same build. CMake +supports two main files, `CMakePresets.json` and `CMakeUserPresets.json`, that allow users to specify common +configure options and share them with others. CMake also supports files included with the include field. +> +>`CMakePresets.json` and` CMakeUserPresets.json` live in the project's root directory. They both have +exactly the same format, and both are optional (though at least one must be present if `--preset` is +specified). `CMakePresets.json` is meant to specify project-wide build details, while `CMakeUserPresets.json` +is meant for developers to specify their own local build details. +> +>CMakePresets.json may be checked into a version control system, and `CMakeUserPresets.json` should NOT be +checked in. For example, if a project is using Git, `CMakePresets.json` may be tracked, and +`CMakeUserPresets.json` should be added to the .gitignore." + +## Troubleshooting + +The wrong toolchain is being used, or a target was not specified: + +``` +Error: no such instruction: `isb' +``` + +### Other log files + +Windows users may find cmake log files in this directory helpful: + +``` +C:\Users\%USERNAME%\AppData\Local\CMakeTools +``` + +## CMake Logic Flow + +Simplified Diagram: + +```mermaid +flowchart TD + +S[Start] --> B0{In-source build?} +B0 -- yes --> BX[FATAL_ERROR no in-source builds] +B0 -- no --> T0{Toolchain file set?} +T0 -- no --> T1{Target set and not x86_64_efi or sim?} +T1 -- yes --> T2[Set toolchain arm-none-eabi] +T1 -- no --> PRJ[project wolfBoot] +T0 -- yes --> PRJ + +PRJ --> CFG{Config source} +CFG -- dot --> C1[load dotconfig] +CFG -- preset --> C2[use presets] +CFG -- neither --> C3[use cache or CLI] + +C1 --> TA +C2 --> TA +C3 --> TA +TA{Target and sector size set?} +TA -- no --> TEe[FATAL_ERROR required vars] +TA -- yes --> AR{Resolve ARCH} + +AR --> PARTQ{Need partition vars} +PARTQ --> PART{not PULL_LINKER_DEFINES and not BUILD_TEST_APPS} +PART -- yes --> PV{All partition vars set} +PV -- no --> PVe[FATAL_ERROR partition vars] +PV -- yes --> OK1[OK] +PART -- no --> OK1 + +OK1 --> HOST[Detect host compiler and flags] +HOST --> TOOLS[Build sign keygen bin-assemble] +TOOLS --> X0{Cross compiler set} +X0 -- no --> XSEL{ARCH} +XSEL -- ARM --> XARM[include ARM toolchain] +XSEL -- AARCH64 --> XA64[include AARCH64 toolchain] +XSEL -- x86_64 or sim --> XNONE[no cross include] +X0 -- yes --> XNONE + +XNONE --> A0{ARCH specifics} +A0 -- ARM --> A1[boot_arm freestanding stm32 tweaks] +A0 -- x86_64 --> A2[boot_x86_64] +A0 -- AARCH64 --> A3[aarch64 sources and defs] + +A0 --> EFIQ{Target is x86_64_efi} +EFIQ -- yes --> EFI[GNU EFI settings update via RAM] +EFIQ -- no --> UDF[Default update via flash] + +UDF --> SIGN{SIGN algorithm} +EFI --> SIGN +SIGN --> S1[Apply sign options header size stack] +S1 --> FEAT{Feature flags} +FEAT --> FLASH[EXT SPI QSPI UART] +FEAT --> ENC[AES128 AES256 CHACHA] +FEAT --> MISC[ALLOW_DOWNGRADE NO_MPU FLAGS_HOME FLAGS_INVERT] +FEAT --> DELTA[DELTA_UPDATES optional] +FEAT --> ARMOR[ARMORED optional] + +ARMOR --> HASH{HASH} +DELTA --> HASH +MISC --> HASH +ENC --> HASH +FLASH --> HASH +HASH --> H1[Add hash defs and keytool flags] + +H1 --> HAL[Select SPI UART drivers DEBUG_UART] +HAL --> MATH{Math options} +MATH --> LIBS[Build user_settings wolfboothal wolfcrypt] +LIBS --> IMG{Build image or tests} +IMG -- yes --> TAPP[add test app] +IMG -- no --> VARS[configure target header cache vars] +TAPP --> VARS +VARS --> KEY{SIGN not none} +KEY -- yes --> KEYGEN[keystore and public key] +KEY -- no --> WL +KEYGEN --> WL +WL[Build wolfboot and link] --> DONE[Done] + +``` + +---- + +In more detail: + +```mermaid +flowchart TD + %% wolfBoot CMake Build Logic Flow (conservative syntax for VS 2022) + + %% ================================ + %% 0) Initial checks & toolchain + %% ================================ + S["Start (cmake 3.16+)\ninclude(cmake/config_defaults.cmake)"] --> I1{"In-source build?"} + I1 -- "yes" --> I1E["FATAL_ERROR:\nIn-source builds are not allowed"] + I1 -- "no" --> T0{"CMAKE_TOOLCHAIN_FILE defined?"} + T0 -- "no" --> T1{"WOLFBOOT_TARGET is set\nand not x86_64_efi or sim?"} + T1 -- "yes" --> T2["Set CMAKE_TOOLCHAIN_FILE:\ncmake/toolchain_arm-none-eabi.cmake"] + T1 -- "no" --> PRJ + T0 -- "yes" --> PRJ + + %% ================================ + %% 1) Project & host env discovery + %% ================================ + PRJ["project(wolfBoot)"] --> INC["include: cmake/functions.cmake\ninclude: cmake/utils.cmake"] + INC --> IDE0{"DETECT_VISUALGDB?"} + IDE0 -- "yes" --> IDE1["include(cmake/visualgdb_config.cmake)"] + IDE0 -- "no" --> VS0{"Windows host and DETECT_VS2022\nand NOT FOUND_HAL_BASE?"} + VS0 -- "yes" --> VS1["include(cmake/vs2022_config.cmake)"] + VS0 -- "no" --> CUBE0{"DETECT_CUBEIDE and NOT FOUND_HAL_BASE?"} + CUBE0 -- "yes" --> CUBE1["include(cmake/cube_ide_config.cmake)"] + CUBE0 -- "no" --> HALD0{"NOT FOUND_HAL_BASE and ENABLE_HAL_DOWNLOAD?"} + HALD0 -- "yes" --> HALD1{"WOLFBOOT_TARGET matches ^stm32?"} + HALD1 -- "yes" --> HALD2["include(cmake/stm32_hal_download.cmake)"] + HALD1 -- "no" --> HALWARN["WARNING:\nHAL not found and download not available"] + HALD0 -- "no" --> CFGSRC + + %% ================================ + %% 2) Config source (dot vs preset) + %% ================================ + CFGSRC{"USE_DOT_CONFIG?"} -- "yes" --> DOTINC["include(cmake/load_dot_config.cmake)"] + CFGSRC -- "no" --> DOTDIS["Info:\nNo .config files will be read"] + + DOTINC --> DOTX{"Found file ./.config?"} + DOTX -- "yes" --> DOTLOAD["WOLFBOOT_CONFIG_MODE=dot\nload_dot_config(.config)"] + DOTX -- "no" --> NODOT["Info:\nNo .config file found"] + + DOTDIS --> PRESETQ{"WOLFBOOT_CONFIG_MODE equals preset?"} + PRESETQ -- "yes" --> PRESETOK["Use cacheVariables from CMakePresets.json"] + PRESETQ -- "no" --> PRESETNONE["Info:\nNot using .config nor CMakePresets.json"] + + %% ================================ + %% 3) Target, arch, partitions + %% ================================ + subgraph TGT["Target, Arch, Partitions"] + direction TB + TGT0{"WOLFBOOT_TARGET empty?"} + TGT0 -- "yes" --> TGT1["Set WOLFBOOT_TARGET from TARGET cache var"] + TGT0 -- "no" --> TGT2["Status:\nBuilding for WOLFBOOT_TARGET"] + TGT2 --> SEC0{"WOLFBOOT_SECTOR_SIZE defined?"} + SEC0 -- "no" --> SECERR["FATAL_ERROR:\nWOLFBOOT_SECTOR_SIZE must be defined"] + SEC0 -- "yes" --> AT0["Init ARM_TARGETS list"] + AT0 --> ASEL{"Target in ARM_TARGETS?"} + ASEL -- "yes" --> ARCH_ARM["ARCH = ARM"] + ASEL -- "no" --> AX86{"Target equals x86_64_efi?"} + AX86 -- "yes" --> ARCH_X86["ARCH = x86_64"] + AX86 -- "no" --> ASIM{"Target equals sim?"} + ASIM -- "yes" --> ARCH_SIM["ARCH = sim"] + ASIM -- "no" --> AERR["FATAL_ERROR:\nUnable to configure ARCH"] + + PART0{"PULL_LINKER_DEFINES or BUILD_TEST_APPS set?"} + PART0 -- "no" --> PART1{"Require partition vars:\nPARTITION_SIZE\nBOOT_ADDRESS\nUPDATE_ADDRESS\nSWAP_ADDRESS"} + PART1 -- "no" --> PARTERR["FATAL_ERROR:\nMissing partition vars"] + PART1 -- "yes" --> PARTOK["OK:\nPartition vars present"] + PART0 -- "yes" --> PARTLK["OK:\nAddresses come from linker or tests"] + end + + %% ================================ + %% 4) Host compiler & Windows shim + %% ================================ + ARCH_ARM --> HOST + ARCH_X86 --> HOST + ARCH_SIM --> HOST + HOST["Detect HOST_CC (gcc or clang or cl)\nSet HOST flags and HOST_IS_MSVC"] --> SHIM{"Windows host and HOST_IS_MSVC?"} + SHIM -- "yes" --> SHIMON["Generate minimal unistd.h shim\nPrepend to HOST_INCLUDES"] + SHIM -- "no" --> SHIMOFF["No shim"] + + %% ================================ + %% 5) Helper tools (native) + %% ================================ + SHIMON --> TOOLS + SHIMOFF --> TOOLS + TOOLS["Build native tools with HOST_CC:\n- bin-assemble (custom)\n- sign (tools/keytools/sign.c)\n- keygen (tools/keytools/keygen.c)\nDefine KEYTOOL_SOURCES and flags"] --> TOOLSDONE["keytools ALL depends on sign and keygen"] + + %% ================================ + %% 6) Cross toolchain include (once) + %% ================================ + TOOLSDONE --> XTC{"CMAKE_C_COMPILER already set?"} + XTC -- "no" --> XTCSEL{"ARCH selection"} + XTCSEL -- "ARM" --> XARM["include(cmake/toolchain_arm-none-eabi.cmake)"] + XTCSEL -- "AARCH64" --> XA64["include(cmake/toolchain_aarch64-none-elf.cmake)"] + XTCSEL -- "x86_64 or sim" --> XNONE["No cross toolchain include"] + XTC -- "yes" --> XNONE + + %% ================================ + %% 7) Arch-specific sources and options + %% ================================ + XNONE --> ARCHO{"Which ARCH?"} + ARCHO -- "x86_64" --> AX86S["Add src/boot_x86_64.c\nIf DEBUG then add WOLFBOOT_DEBUG_EFI"] + ARCHO -- "ARM" --> AARMS["Add src/boot_arm.c\nAdd ARCH_ARM\nAdd -ffreestanding -nostartfiles -fomit-frame-pointer"] + ARCHO -- "AARCH64" --> AA64S["Add aarch64 sources\nAdd ARCH_AARCH64 NO_QNX WOLFBOOT_DUALBOOT MMU\nIf SPMATH then add sp_c32.c"] + + AX86S --> UPDS["UPDATE_SOURCES = src/update_flash.c (default)"] + AARMS --> ARMSTMS{"WOLFBOOT_TARGET specifics"} + ARMSTMS --> ARMf4{"Target stm32f4?"} + ARMf4 -- "yes" --> ARMf4set["ARCH_FLASH_OFFSET=0x08000000\nRequire CLOCK_SPEED and PLL vars\nAdd compile definitions"] + ARMSTMS --> ARMu5{"Target stm32u5?"} + ARMu5 -- "yes" --> ARMu5set["ARCH_FLASH_OFFSET=0x08000000"] + ARMSTMS --> ARMh7{"Target stm32h7?"} + ARMh7 -- "yes" --> ARMh7set["ARCH_FLASH_OFFSET=0x08000000"] + ARMSTMS --> ARMl0{"Target stm32l0?"} + ARMl0 -- "yes" --> ARMl0inv["Set FLAGS_INVERT=ON"] + AA64S --> UPDS + + UPDS --> EFIQ{"Target equals x86_64_efi?"} + EFIQ -- "yes" --> EFICONF["Set GNU EFI crt0 and lds paths\nAdd TARGET_X86_64_EFI\nSet shared linker flags\nUPDATE_SOURCES = src/update_ram.c"] + EFIQ -- "no" --> ARCHOFF["Continue"] + + %% ================================ + %% 8) DSA / signing, header size, stack + %% ================================ + ARCHOFF --> DSA{"SIGN algorithm"} + DSA -- "NONE" --> S_NONE["No signing; stack by hash\nAdd WOLFBOOT_NO_SIGN"] + DSA -- "ECC256" --> S_ECC256["KEYTOOL --ecc256; add WOLFBOOT_SIGN_ECC256\nStack depends; header >= 256"] + DSA -- "ECC384" --> S_ECC384["KEYTOOL --ecc384; add WOLFBOOT_SIGN_ECC384\nStack depends; header >= 512"] + DSA -- "ECC521" --> S_ECC521["KEYTOOL --ecc521; add WOLFBOOT_SIGN_ECC521\nStack depends; header >= 512"] + DSA -- "ED25519" --> S_ED25519["KEYTOOL --ed25519; add WOLFBOOT_SIGN_ED25519\nStack default 5000; header >= 256"] + DSA -- "ED448" --> S_ED448["KEYTOOL --ed448; add WOLFBOOT_SIGN_ED448\nStack 1024 or 4376; header >= 512"] + DSA -- "RSA2048" --> S_RSA2048["KEYTOOL --rsa2048; add WOLFBOOT_SIGN_RSA2048\nStack varies; header >= 512"] + DSA -- "RSA4096" --> S_RSA4096["KEYTOOL --rsa4096; add WOLFBOOT_SIGN_RSA4096\nStack varies; header >= 1024"] + + S_NONE --> DSA_APPLY + S_ECC256 --> DSA_APPLY + S_ECC384 --> DSA_APPLY + S_ECC521 --> DSA_APPLY + S_ED25519 --> DSA_APPLY + S_ED448 --> DSA_APPLY + S_RSA2048 --> DSA_APPLY + S_RSA4096 --> DSA_APPLY + + DSA_APPLY["Append IMAGE_HEADER_SIZE and SIGN_OPTIONS to WOLFBOOT_DEFS\nAdd -Wstack-usage and -Wno-unused"] --> FLAGS + + %% ================================ + %% 9) Feature flags and encryption + %% ================================ + FLAGS{"Apply feature toggles"} --> F_PULL["If PULL_LINKER_DEFINES then add def"] + FLAGS --> F_RAM["If RAM_CODE then add def"] + FLAGS --> F_FHOME["If FLAGS_HOME then add FLAGS_HOME=1"] + FLAGS --> F_FINV["If FLAGS_INVERT then add WOLFBOOT_FLAGS_INVERT=1"] + FLAGS --> F_SPI["If SPI_FLASH or QSPI_FLASH or OCTOSPI_FLASH or UART_FLASH\nthen set EXT_FLASH and add sources"] + FLAGS --> F_ENC{"ENCRYPT enabled?"} + F_ENC -- "yes" --> F_ENCSEL{"Select AES128 or AES256 or CHACHA"} + F_ENCSEL --> F_AES128["Add ENCRYPT_WITH_AES128; EXT_ENCRYPTED=1"] + F_ENCSEL --> F_AES256["Add ENCRYPT_WITH_AES256; EXT_ENCRYPTED=1"] + F_ENCSEL --> F_CHACHA["Default CHACHA; add ENCRYPT_WITH_CHACHA and HAVE_CHACHA\nEXT_ENCRYPTED=1"] + FLAGS --> F_DOWN["If ALLOW_DOWNGRADE then add def"] + FLAGS --> F_WO["If NVM_FLASH_WRITEONCE then add def"] + FLAGS --> F_NOBKP["If DISABLE_BACKUP then add def"] + FLAGS --> F_NOMPU["If NO_MPU then add WOLFBOOT_NO_MPU"] + FLAGS --> F_VER{"WOLFBOOT_VERSION defined?"} + F_VER -- "no" --> F_VERSET["Set WOLFBOOT_VERSION=1"] + F_VER -- "yes" --> F_VEROK["Keep version"] + + %% ================================ + %% 10) Delta updates and armored + %% ================================ + F_VEROK --> DELTA{"DELTA_UPDATES enabled?"} + F_VERSET --> DELTA + DELTA -- "yes" --> DELTAON["Add src/delta.c and DELTA_UPDATES\nIf DELTA_BLOCK_SIZE defined then add def"] + DELTA -- "no" --> ARMOR{"ARMORED enabled?"} + ARMOR -- "yes" --> ARMORON["Add WOLFBOOT_ARMORED"] + ARMOR -- "no" --> NEXT0 + + DELTAON --> NEXT0 + ARMORON --> NEXT0 + + %% ================================ + %% 11) Hash selection + %% ================================ + NEXT0 --> HASH{"HASH selection"} + HASH -- "SHA256" --> H256["Add WOLFBOOT_HASH_SHA256"] + HASH -- "SHA384" --> H384["Add WOLFBOOT_HASH_SHA384; KEYTOOL --sha384"] + HASH -- "SHA3" --> H3["Add WOLFBOOT_HASH_SHA3_384; KEYTOOL --sha3"] + + %% ================================ + %% 12) HAL and drivers + %% ================================ + H256 --> HAL + H384 --> HAL + H3 --> HAL + HAL["SPI_TARGET and UART_TARGET default to WOLFBOOT_TARGET\nIf target is STM32 in list then SPI_TARGET=stm32"] --> HALDRV{"Drivers enabled?"} + HALDRV -- "SPI_FLASH" --> DSPIS["Add spi driver and src/spi_flash.c"] + HALDRV -- "QSPI_FLASH" --> DQSPIS["Add spi driver and src/qspi_flash.c"] + HALDRV -- "UART_FLASH" --> DUART["Add uart driver and src/uart_flash.c"] + HALDRV -- "none" --> HALNEXT["No external flash drivers"] + HALDRV --> DBGQ{"DEBUG_UART enabled?"} + DBGQ -- "yes" --> DBGON["Add DEBUG_UART and uart driver path"] + DBGQ -- "no" --> DBGOFF["No debug uart"] + + %% ================================ + %% 13) Math options (wolfSSL) + %% ================================ + DBGOFF --> MATH + DBGON --> MATH + MATH{"SPMATH / SPMATHALL"} --> MALL["If SPMATHALL then add WOLFSSL_SP_MATH_ALL"] + MATH --> MFAST["If neither then add USE_FAST_MATH"] + MATH --> MNONE["If only SPMATH then no extra def"] + + %% ================================ + %% 14) Build HAL libs and wolfcrypt + %% ================================ + MALL --> LIBS0 + MFAST --> LIBS0 + MNONE --> LIBS0 + LIBS0["add_library(user_settings INTERFACE)\nadd_library(wolfboothal)"] --> STM32L4Q{"Target equals stm32l4?"} + STM32L4Q -- "yes" --> L4HAL["Create stm32l4_hal subset\nLink into wolfboothal"] + STM32L4Q -- "no" --> L4SKIP["Skip stm32l4 subset"] + L4HAL --> CRYPT + L4SKIP --> CRYPT + CRYPT["add_subdirectory(lib) for wolfcrypt"] --> BUILDIMG{"BUILD_TEST_APPS or BUILD_IMAGE?"} + BUILDIMG -- "yes" --> ADDAPP["Print status and add_subdirectory(test-app)"] + BUILDIMG -- "no" --> VARS + + %% ================================ + %% 15) Cache vars, target.h, target iface + %% ================================ + ADDAPP --> VARS + VARS["Set INTERNAL cache vars\nconfigure_file target.h\nadd_library(target INTERFACE)"] --> KEYGENQ{"SIGN is not NONE?"} + + %% ================================ + %% 16) Keystore generation and public key lib + %% ================================ + KEYGENQ -- "yes" --> KEYGEN["add_custom_target(keystore)\nIf keystore.c missing then run keygen"] + KEYGENQ -- "no" --> KEYGENSKIP["Skip keystore and public_key"] + KEYGEN --> PUBKEY["add_library(public_key)\nUse generated keystore.c\nLink target"] + KEYGENSKIP --> WBLIB + + %% ================================ + %% 17) Final libraries + %% ================================ + PUBKEY --> WBLIB + WBLIB["add_library(wolfboot)\nAdd src/libwolfboot.c and flash sources\nApply WOLFBOOT_DEFS and include dirs\nLink wolfboothal target wolfcrypt\nAdd -Wno-unused and SIM_COMPILE_OPTIONS"] --> DONE["Done"] + +``` diff --git a/cmake/config_defaults.cmake b/cmake/config_defaults.cmake new file mode 100644 index 0000000000..0e34fd710d --- /dev/null +++ b/cmake/config_defaults.cmake @@ -0,0 +1,428 @@ +# wolfboot/cmake/config_defaults.cmake +# +# 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 +# + +# This is NOT a place for device-specific project settings. For that, see CMakePresets.json + +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake + if(DEFINED CONFIG_DEFAULTS_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() + +# Config is either from config_defaults.cmake or optional config_defaults_user.cmake (if present) +set(USER_CONFIG_FILE "${CMAKE_CURRENT_LIST_DIR}/config_defaults_user.cmake") +#--------------------------------------------------------------------------------------------- +message(STATUS "Looking for ${USER_CONFIG_FILE} file...") +if(EXISTS "${USER_CONFIG_FILE}") + # Excluded by default from wolfBoot .gitignore: + include(${USER_CONFIG_FILE}) +else() + message(STATUS "============================================================================") + message(STATUS "Using standard config defaults: ${CMAKE_CURRENT_LIST_FILE}") + message(STATUS "============================================================================") + # Environments are detected in this order: + set(DETECT_VISUALGDB false) + set(DETECT_MINGW false) + set(DETECT_CUBEIDE true) + set(DETECT_VS2022 true) + set(DETECT_LLVM false) + + set(_host_arch "$ENV{VSCMD_ARG_HOST_ARCH}") + string(TOLOWER "${_host_arch}" _host_arch) + string(STRIP "${_host_arch}" _host_arch) + # Although you CAN select both 32 and 64 bit, it is best to pick ONE: + if(_host_arch STREQUAL "x86") + message(STATUS "Detected x86 architecture for hints") + set(USE_32BIT_LIBS true) + set(USE_64BIT_LIBS false) + elseif(_host_arch STREQUAL "x64") + message(STATUS "Detected x64 architecture for hints") + set(USE_32BIT_LIBS false) + set(USE_64BIT_LIBS true) + else() + message(STATUS "Did not detect architecture for hints, assume x86") + # Likely a non-Microsoft environment, so no hints at all + set(USE_32BIT_LIBS false) + set(USE_64BIT_LIBS true) + endif() + + # Enable HAL download only implemented for STM devices at this time. + # See [WOLFBOOT_ROOT]/cmake/stm32_hal_download.cmake + # and [WOLFBOOT_ROOT]/cmake/downloads/stm32_hal_download.cmake + set(ENABLE_HAL_DOWNLOAD true) + + # optionally use .config files; See CMakePresets.json instead + set(USE_DOT_CONFIG false) +endif() +# Summary of user or standard config: +message(STATUS " DETECT_VISUALGDB: ${DETECT_VISUALGDB}") +message(STATUS " DETECT_MINGW: ${DETECT_MINGW}") +message(STATUS " DETECT_CUBEIDE: ${DETECT_CUBEIDE}") +message(STATUS " DETECT_VS2022: ${DETECT_VS2022}") +message(STATUS " DETECT_LLVM: ${DETECT_LLVM}") +message(STATUS " USE_32BIT_LIBS: ${USE_32BIT_LIBS}") +message(STATUS " USE_64BIT_LIBS: ${USE_64BIT_LIBS}") +message(STATUS " USE_DOT_CONFIG: ${USE_DOT_CONFIG}") +#--------------------------------------------------------------------------------------------- + + +# Init +SET(HOST_CC_HINT_DIRECTORIES "") +set(FOUND_HAL_BASE false) # init now, search later, see ENABLE_HAL_DOWNLOAD + +include(cmake/current_user.cmake) +get_current_user(CURRENT_USER) +message(STATUS "Current user detected: ${CURRENT_USER}") + + +# We're in [WOLFBOOT_ROOT]/cmake for this file, ensure there are no stray target.h files +# See wolfBoot CMakeLists.txt that generates ${CMAKE_CURRENT_BINARY_DIR}/target.h +if(EXISTS "../include/target.h") + # This can really spoil the day, not very intuitive: + message(FATAL_ERROR "unexpected include/target.h") +else() + message(STATUS "Confirmed no stray include/target.h") +endif() + + +if (false ) # TODO detect MSVS, not defined until much later +# include(CheckIncludeFile) +# check_include_file(stdint.h HAVE_STDINT_H) +# if(NOT HAVE_STDINT_H) +# message(FATAL_ERROR +# "MSVC environment not initialized (stdint.h not found). " +# "Use a preset with environmentSetupScript or the VS generator, " +# "or launch VS Code from the x64 Native Tools prompt.") +# endif() + + if (NOT HOST_WINSDK_UCRT OR NOT HOST_WINSDK_UM OR NOT HOST_MSVC_LIB) + message(WARNING + "MSVC host build: Windows SDK/MSVC libpaths not found. " + "Open an 'x64 Native Tools Command Prompt for VS 2022' (or run vcvarsall.bat) " + "so /LIBPATH points at the right ${HOST_ARCH} libraries.") + endif() +endif() + +if(USE_32BIT_LIBS AND USE_64BIT_LIBS) + message(STATUS "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + message(STATUS "Warning: Both 32Bit and 64Bit libraries enabled.") + message(STATUS "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") +endif() + +# Requires CMake 3.19 (or newer for string(JSON); --format=json is available on recent CMake (VS is 3.31). +function(preset_exists name out_var) + # Use the same cmake that is running this configure + set(_cmake "${CMAKE_COMMAND}") + + # Be explicit about the source dir (important in some IDE invocations) + execute_process( + COMMAND "${_cmake}" -S "${CMAKE_SOURCE_DIR}" --list-presets=configure --format=json + OUTPUT_VARIABLE _json + ERROR_VARIABLE _err + RESULT_VARIABLE _rc + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE + ) + message(STATUS "list-presets rc=${_rc}") + if(_rc) + message(STATUS "list-presets stderr: ${_err}") + endif() + set(_found OFF) + if(_rc EQUAL 0 AND _json) + # Parse JSON: get length and scan for matching .name + string(JSON _len LENGTH "${_json}" presets) + if(_len GREATER 0) + math(EXPR _last "${_len} - 1") + foreach(i RANGE 0 ${_last}) + string(JSON _nm GET "${_json}" presets ${i} name) + if(_nm STREQUAL "${name}") + set(_found ON) + break() + endif() + endforeach() + endif() + endif() + set(${out_var} ${_found} PARENT_SCOPE) +endfunction() + + +if(NOT EXISTS "${CMAKE_SOURCE_DIR}/CMakePresets.json") + message(WARNING "No CMakePresets.json found at ${CMAKE_SOURCE_DIR}") +endif() +set(_has_var "HAS_${WOLFBOOT_TARGET}") +# preset_exists("${WOLFBOOT_TARGET}" HAS_${WOLFBOOT_TARGET}) +# message(STATUS "Has preset ${WOLFBOOT_TARGET}: ${${_has_var}}") +#--------------------------------------------------------------------------------------------- +# There are different configuration modes: +# +# - Using CMake Presets. (preferred, use cacheVariables from CMakePresets.json, optional CMakeUserPresets.json) +# - Using a .config file. See load_dot_config() +# - Command-line options; can also be used to supplement above configurations. +#--------------------------------------------------------------------------------------------- + +# Where should configuration values come from? +# dot : parse .config via load_dot_config() +# preset : use cacheVariables from CMakePresets.json +if( EXISTS "./.config") + message(STATUS "Found a .config file, will parse") + set(WOLFBOOT_CONFIG_MODE "dot" CACHE STRING "Config source: dot or preset") + set_property(CACHE WOLFBOOT_CONFIG_MODE PROPERTY STRINGS dot preset) +else() + message(STATUS "No .config file found.") +endif() + +if(WOLFBOOT_CONFIG_MODE STREQUAL "dot") + message(STATUS "Config mode: dot (.config cache)") + include(cmake/load_dot_config.cmake) + message(STATUS "Loading config from: ${CMAKE_SOURCE_DIR}") + load_dot_config("${CMAKE_SOURCE_DIR}/.config") + +elseif(WOLFBOOT_CONFIG_MODE STREQUAL "preset") + message(STATUS "Config mode: preset (using cacheVariables; skipping .config)") + +else() + message(STATUS "Not using .config nor CMakePresets.json for WOLFBOOT_CONFIG_MODE.") +endif() + + + +# The ST CubeIDE location is searched in cmake/cube_ide_config.cmake +# Want to specify your specific STCubeIDE? Uncomment and set it here: +# set(STM32CUBEIDE_DIR "/your/path") +if(NOT WOLFBOOT_HAS_BASE_PRESET AND (NOT "${WOLFBOOT_CONFIG_MODE}" STREQUAL "dot")) + message(STATUS "See preset for wolfBoot target: ${WOLFBOOT_TARGET}") + message(STATUS "-- WOLFBOOT_HAS_BASE_PRESET not found. All presets must inherit base config.") +endif() + +# set(ARM_GCC_BIN "") +if (CMAKE_HOST_WIN32) + # Optional: derive MSVC bin dirs from environment (if a VS Dev Prompt was used) + set(_VC_HINTS "") + + #----------------------------------------------------------------------------------------- + # Always add 64 bit options first + #----------------------------------------------------------------------------------------- + if(USE_64BIT_LIBS AND DEFINED ENV{VCToolsInstallDir}) + message(STATUS "Found VCToolsInstallDir=$ENV{VCToolsInstallDir}") + message(STATUS "Appending _VC_HINTS") + list(APPEND _VC_HINTS + "$ENV{VCToolsInstallDir}/bin/Hostx64/x64" + "$ENV{VCToolsInstallDir}/bin/Hostx86/x64" + ) + endif() + + # Visual Studio VisualGDB + MinGW Hints + if(DETECT_VISUALGDB AND DETECT_MINGW AND USE_64BIT_LIBS) + message(STATUS "Appending VisualGDB Hints") + list(APPEND HOST_CC_HINT_DIRECTORIES + # VisualGDB / SysGCC MinGW (common system-wide) + "C:/SysGCC/mingw64/bin" + "C:/SysGCC/MinGW64/bin" + + # VisualGDB user-local toolchains + "$ENV{LOCALAPPDATA}/VisualGDB/Toolchains/mingw64/bin" + "$ENV{LOCALAPPDATA}/VisualGDB/Toolchains/MinGW64/bin" + ) + endif() + + # Regular MinGW (Non-VisualGDB) + if(DETECT_MINGW AND USE_64BIT_LIBS) + message(STATUS "Appending VisualGDB Hints") + list(APPEND HOST_CC_HINT_DIRECTORIES + "C:/mingw64/bin" + "C:/msys64/usr/bin" + ) + endif() + + # Prefer environment if available (works from VS Dev Prompt / VS CMake) + if (CMAKE_HOST_WIN32 AND DEFINED ENV{VCINSTALLDIR} AND DEFINED ENV{VCToolsVersion} AND USE_64BIT_LIBS) + file(TO_CMAKE_PATH "$ENV{VCINSTALLDIR}" _VCINSTALLDIR) + set(_VCTOOLS "$_VCINSTALLDIR/Tools/MSVC/$ENV{VCToolsVersion}") + list(APPEND HOST_CC_HINT_DIRECTORIES + "${_VCTOOLS}/bin/Hostx64/x64" + "${_VCTOOLS}/bin/Hostx86/x64" + ) + endif() + + set(_VSWHERE "C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe") + if (EXISTS "${_VSWHERE}") + execute_process(COMMAND "${_VSWHERE}" -latest -requires Microsoft.Component.MSBuild -property installationPath + OUTPUT_VARIABLE _VS_PATH OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (_VS_PATH) + # Find all versioned MSVC toolsets under this install, pick highest (natural sort) + file(GLOB _MSVC_DIRS LIST_DIRECTORIES TRUE "${_VS_PATH}/VC/Tools/MSVC/*") + list(SORT _MSVC_DIRS COMPARE NATURAL ORDER DESCENDING) + list(GET _MSVC_DIRS 0 _MSVC_TOOLS) + if(USE_64BIT_LIBS) + list(APPEND HOST_CC_HINT_DIRECTORIES + "${_MSVC_TOOLS}/bin/Hostx64/x64" + "${_MSVC_TOOLS}/bin/Hostx86/x64" + ) + endif() + endif() + endif() + + foreach(_root + "C:/Program Files/Microsoft Visual Studio/2022" + "C:/Program Files (x86)/Microsoft Visual Studio/2022") + file(GLOB _editions LIST_DIRECTORIES TRUE "${_root}/*") # Enterprise/Professional/Community + foreach(_ed ${_editions}) + message(STATUS "Found edition: ${_ed}") + file(GLOB _msvc LIST_DIRECTORIES TRUE "${_ed}/VC/Tools/MSVC/*") + list(SORT _msvc COMPARE NATURAL ORDER DESCENDING) + foreach(_ver ${_msvc}) + message(STATUS "Appending Visual Studio Version ${_ver} hint files") + if(USE_64BIT_LIBS) + list(APPEND HOST_CC_HINT_DIRECTORIES + "${_ver}/bin/Hostx64/x64" + "${_ver}/bin/Hostx86/x64" + ) + endif() + endforeach() # version + endforeach() # edition + endforeach() # root + + # LLVM Hints (listed last in 64 bit section: 32 or 64 bit?) + if(DETECT_LLVM) + message(STATUS "Appending LLVM Hints") + list(APPEND HOST_CC_HINT_DIRECTORIES + # LLVM + "C:/Program Files/LLVM/bin" + + # TODO include file code? + ) + endif() + + #----------------------------------------------------------------------------------------- + # Next, add 32 bit + #----------------------------------------------------------------------------------------- + if(USE_32BIT_LIBS AND DEFINED ENV{VCToolsInstallDir}) + message(STATUS "Found VCToolsInstallDir=$ENV{VCToolsInstallDir}") + message(STATUS "Appending _VC_HINTS") + list(APPEND _VC_HINTS + "$ENV{VCToolsInstallDir}/bin/Hostx64/x86" + "$ENV{VCToolsInstallDir}/bin/Hostx86/x86" + ) + endif() + + # Visual Studio VisualGDB + MinGW Hints, 32-Bit x86 only + if(DETECT_VISUALGDB AND DETECT_MINGW AND USE_32BIT_LIBS) + message(STATUS "Appending VisualGDB Hints") + list(APPEND HOST_CC_HINT_DIRECTORIES + # VisualGDB / SysGCC MinGW (common system-wide) + "C:/SysGCC/mingw32/bin" + "C:/SysGCC/MinGW32/bin" + + # VisualGDB user-local toolchains + "$ENV{LOCALAPPDATA}/VisualGDB/Toolchains/mingw32/bin" + "$ENV{LOCALAPPDATA}/VisualGDB/Toolchains/MinGW32/bin" + ) + endif() + + # Visual Studio hints + if(DETECT_VS2022 AND USE_32BIT_LIBS) + message(STATUS "Appending Visual Studio 2022 Hints") + list(APPEND HOST_CC_HINT_DIRECTORIES + # Environment-derived VS bin dirs if present + ${_VC_HINTS} + + # Visual Studio 2022 (all editions) + "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Tools/MSVC/bin/Hostx64/x86" + "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/bin/Hostx64/x86" + "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/bin/Hostx64/x86" + "C:/Program Files (x86)/Microsoft Visual Studio/2022/Enterprise/VC/Tools/MSVC/bin/Hostx64/x86" + "C:/Program Files (x86)/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/bin/Hostx64/x86" + "C:/Program Files (x86)/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/bin/Hostx64/x86" + ) + endif() + + # Prefer environment if available (works from VS Dev Prompt / VS CMake) + if (CMAKE_HOST_WIN32 AND DEFINED ENV{VCINSTALLDIR} AND DEFINED ENV{VCToolsVersion} AND USE_32BIT_LIBS) + file(TO_CMAKE_PATH "$ENV{VCINSTALLDIR}" _VCINSTALLDIR) + set(_VCTOOLS "$_VCINSTALLDIR/Tools/MSVC/$ENV{VCToolsVersion}") + list(APPEND HOST_CC_HINT_DIRECTORIES + "${_VCTOOLS}/bin/Hostx64/x86" + "${_VCTOOLS}/bin/Hostx86/x86" + ) + endif() + + set(_VSWHERE "C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe") + if (EXISTS "${_VSWHERE}") + execute_process(COMMAND "${_VSWHERE}" -latest -requires Microsoft.Component.MSBuild -property installationPath + OUTPUT_VARIABLE _VS_PATH OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (_VS_PATH) + # Find all versioned MSVC toolsets under this install, pick highest (natural sort) + file(GLOB _MSVC_DIRS LIST_DIRECTORIES TRUE "${_VS_PATH}/VC/Tools/MSVC/*") + list(SORT _MSVC_DIRS COMPARE NATURAL ORDER DESCENDING) + list(GET _MSVC_DIRS 0 _MSVC_TOOLS) + if(USE_32BIT_LIBS) + list(APPEND HOST_CC_HINT_DIRECTORIES + "${_MSVC_TOOLS}/bin/Hostx64/x86" + "${_MSVC_TOOLS}/bin/Hostx86/x86" + ) + endif() + endif() + endif() + + foreach(_root + "C:/Program Files/Microsoft Visual Studio/2022" + "C:/Program Files (x86)/Microsoft Visual Studio/2022") + file(GLOB _editions LIST_DIRECTORIES TRUE "${_root}/*") # Enterprise/Professional/Community + foreach(_ed ${_editions}) + message(STATUS "Found edition: ${_ed}") + file(GLOB _msvc LIST_DIRECTORIES TRUE "${_ed}/VC/Tools/MSVC/*") + list(SORT _msvc COMPARE NATURAL ORDER DESCENDING) + foreach(_ver ${_msvc}) + message(STATUS "Appending Visual Studio Version ${_ver} hint files") + if(USE_32BIT_LIBS) + list(APPEND HOST_CC_HINT_DIRECTORIES + "${_ver}/bin/Hostx64/x86" + "${_ver}/bin/Hostx86/x86" + ) + endif() + endforeach() # version + endforeach() # edition + endforeach() # root + + #----------------------------------------------------------------------------------------- + message(STATUS "Assembled HOST_CC_HINT_DIRECTORIES contents:") + #----------------------------------------------------------------------------------------- + foreach(_hint_item IN LISTS HOST_CC_HINT_DIRECTORIES) + if(IS_DIRECTORY "${_hint_item}") + set(_hint_status "(ok)") + else() + set(_hint_status "NOT FOUND:") + endif() + + message(STATUS " ${_hint_status} ${_hint_item}") + endforeach() # Hint directory +else() + message(STATUS "HOST_CC_HINT_DIRECTORIES not set, assuming tools in path. See wolfboot/cmake/config_defaults.cmake") + set(HOST_CC_HINT_DIRECTORIES "") +endif() + +set(CONFIG_DEFAULTS_CMAKE_INCLUDED TRUE) diff --git a/cmake/cube_ide_config.cmake b/cmake/cube_ide_config.cmake new file mode 100644 index 0000000000..9dd5c1148a --- /dev/null +++ b/cmake/cube_ide_config.cmake @@ -0,0 +1,436 @@ +# wolfboot/cmake/cube_ide_config.cmake +# +# 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 +# + +# Some logic to find the ST Cube IDE in various directories on various systems +# See also https://www.st.com/resource/en/application_note/an5952-how-to-use-cmake-in-stm32cubeide-stmicroelectronics.pdf + +# Usage: +# set(STM32CUBEIDE_DIR "C:/ST/STM32CubeIDE_1.15.0" CACHE PATH "Hint to STM32CubeIDE root") +# find_package(STM32CubeIDE REQUIRED) +# message(STATUS "STM32CubeIDE: ${STM32CUBEIDE_EXECUTABLE} (root: ${STM32CUBEIDE_ROOT}, ver: ${STM32CUBEIDE_VERSION})") + +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake + if(DEFINED CUBE_IDE_CONFIG_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() + +if(DEFINED FUNCTIONS_CMAKE_INCLUDED) + message(STATUS "Found required functions.cmake") +else() + message(FATL_ERROR "Missing required functions.cmake") +endif() + +# Exclude entire file unless DETECT_CUBEIDE is set to true +if(DETECT_CUBEIDE) + +message(STATUS "Begin cube_ide_config.cmake") +unset(STM32CUBEIDE_ROOT CACHE) +unset(STM32CUBEIDE_FOUND CACHE) +unset(STM32CUBEIDE_VERSION CACHE) +unset(STM32CUBEIDE_EXECUTABLE CACHE) + +function(_stm32cubeide_set_from_exec PARAM_EXE) + if(NOT EXISTS "${PARAM_EXE}") + return() + endif() + set(STM32CUBEIDE_EXECUTABLE "${PARAM_EXE}" PARENT_SCOPE) + # Root: up two dirs works for Linux default; handle macOS bundle separately below. + get_filename_component(_dir "${PARAM_EXE}" DIRECTORY) + if(CMAKE_HOST_APPLE AND _dir MATCHES "\\.app/Contents/MacOS$") + get_filename_component(_root "${_dir}/../.." REALPATH) + else() + get_filename_component(_root "${_dir}/.." REALPATH) + endif() + + message(STATUS "Found STM32CUBEIDE_ROOT=${_root}") + set(STM32CUBEIDE_ROOT "${_root}" PARENT_SCOPE) + + # Version extract from directory names like STM32CubeIDE_1.15.0 + file(TO_CMAKE_PATH "${_root}" _root_norm) + get_filename_component(_leaf "${_root_norm}" NAME) # e.g. "STM32CubeIDE_1.14.1" + + set(_ver "") + set(_mark "STM32CubeIDE_") + string(FIND "${_leaf}" "${_mark}" _pos) + if(NOT _pos EQUAL -1) + string(LENGTH "${_mark}" _mlen) + math(EXPR _start "${_pos} + ${_mlen}") + string(SUBSTRING "${_leaf}" ${_start} -1 _ver_raw) + string(STRIP "${_ver_raw}" _ver) + endif() + + if(_ver) # e.g. "1.14.1" + # set both locally and in parent scope for immediate logging + export + set(STM32CUBEIDE_VERSION "${_ver}") + set(STM32CUBEIDE_VERSION "${_ver}" PARENT_SCOPE) + message(NOTICE "Found STM32CUBEIDE_VERSION=${_ver}") + else() + message(VERBOSE "Could not derive version (leaf='${_leaf}', root='${_root_norm}')") + endif() +endfunction() + +# Finds the newest STM32Cube L4 firmware folder under the standard Repository path. +# Usage: +# find_newest_stm32cube_fw_l4(OUT_DIR OUT_VER) +# After the call: +# OUT_DIR = full path to the newest STM32Cube_FW_L4_Vx.y.z directory +# OUT_VER = version string x.y.z +# +# Optional inputs that you may predefine before calling: +# CURRENT_USER Used only on Windows if USERPROFILE is not set +# STM32CUBE_REPO_HINT Override the Repository root folder if you know it already +# +# Examples: +# find_newest_stm32cube_fw_l4(STM32CUBE_L4_ROOT STM32CUBE_L4_VERSION) +# message(STATUS "STM32Cube L4 root: ${STM32CUBE_L4_ROOT} (version ${STM32CUBE_L4_VERSION})") +function(find_newest_stm32cube_fw_l4 OUT_DIR OUT_VER) + set(_repo_root "") + + # 1) If the caller provided a direct hint, use it + if(DEFINED STM32CUBE_REPO_HINT AND EXISTS "${STM32CUBE_REPO_HINT}") + set(_repo_root "${STM32CUBE_REPO_HINT}") + else() + # 2) Build the default path based on platform + if(CMAKE_HOST_WIN32) + # Prefer USERPROFILE if available + set(_userprofile "$ENV{USERPROFILE}") + if(_userprofile STREQUAL "") + # Fallback to C:/Users/ + if(NOT DEFINED CURRENT_USER OR CURRENT_USER STREQUAL "") + set(_env_user "$ENV{USERNAME}") + if(NOT _env_user STREQUAL "") + set(CURRENT_USER "${_env_user}") + endif() + endif() + if(DEFINED CURRENT_USER AND NOT CURRENT_USER STREQUAL "") + set(_repo_root "C:/Users/${CURRENT_USER}/STM32Cube/Repository") + endif() + else() + # Convert backslashes to forward slashes for CMake path sanity + file(TO_CMAKE_PATH "${_userprofile}" _userprofile_cmake) + set(_repo_root "${_userprofile_cmake}/STM32Cube/Repository") + endif() + else() + # macOS and Linux + set(_home "$ENV{HOME}") + if(NOT _home STREQUAL "") + file(TO_CMAKE_PATH "${_home}" _home_cmake) + set(_repo_root "${_home_cmake}/STM32Cube/Repository") + endif() + endif() + endif() + + # Validate we have a repository root + if(_repo_root STREQUAL "" OR NOT EXISTS "${_repo_root}") + set(${OUT_DIR} "" PARENT_SCOPE) + set(${OUT_VER} "" PARENT_SCOPE) + message(STATUS "STM32Cube Repository not found. Checked: ${_repo_root}") + return() + endif() + + # 3) Glob STM32Cube L4 folders + file(GLOB _candidates + LIST_DIRECTORIES true + "${_repo_root}/STM32Cube_FW_L4_V*" + ) + + if(_candidates STREQUAL "") + set(${OUT_DIR} "" PARENT_SCOPE) + set(${OUT_VER} "" PARENT_SCOPE) + message(STATUS "No STM32Cube L4 packages found under: ${_repo_root}") + return() + endif() + + # 4) Pick the highest semantic version using CMake's VERSION comparison + set(_best_dir "") + set(_best_ver "") + + foreach(_dir IN LISTS _candidates) + get_filename_component(_name "${_dir}" NAME) + # Expect names like STM32Cube_FW_L4_V1.17.2 + # Extract the numeric version after the V + string(REGEX MATCH "STM32Cube_FW_L4_V([0-9]+\\.[0-9]+\\.[0-9]+)" _m "${_name}") + if(_m) + # Capture group 1 is the version x.y.z + string(REGEX REPLACE "STM32Cube_FW_L4_V" "" _ver "${_m}") + if(_best_ver STREQUAL "" OR _best_ver VERSION_LESS _ver) + set(_best_ver "${_ver}") + set(_best_dir "${_dir}") + endif() + endif() + endforeach() + + if(_best_dir STREQUAL "") + set(${OUT_DIR} "" PARENT_SCOPE) + set(${OUT_VER} "" PARENT_SCOPE) + message(STATUS "STM32Cube L4 directories found but no valid version pattern matched under: ${_repo_root}") + return() + endif() + + # 5) Return results + set(${OUT_DIR} "${_best_dir}" PARENT_SCOPE) + set(${OUT_VER} "${_best_ver}" PARENT_SCOPE) + message(STATUS "Found newest STM32Cube L4: ${_best_dir} (version ${_best_ver})") +endfunction() # find_newest_stm32cube_fw_l4 + + +# 1) Hints from environment or cache +set(_HINTS "") +if(DEFINED ENV{STM32CUBEIDE_DIR}) + message(STATUS "Found env STM32CUBEIDE_DIR=$ENV{STM32CUBEIDE_DIR}") + list(APPEND _HINTS "$ENV{STM32CUBEIDE_DIR}") +endif() + +if(DEFINED STM32CUBEIDE_DIR) + message(STATUS "Found STM32CUBEIDE_DIR=${STM32CUBEIDE_DIR}") + list(APPEND _HINTS "${STM32CUBEIDE_DIR}") +endif() + +if(DEFINED ENV{STM32CUBEIDE_ROOT}) + message(STATUS "Found env STM32CUBEIDE_ROOT=$ENV{STM32CUBEIDE_ROOT}") + list(APPEND _HINTS "$ENV{STM32CUBEIDE_ROOT}") +endif() + +if(DEFINED STM32CUBEIDE_ROOT) + message(STATUS "Found STM32CUBEIDE_ROOT=${STM32CUBEIDE_ROOT}") + list(APPEND _HINTS "${STM32CUBEIDE_ROOT}") +endif() + +foreach(h ${_HINTS}) + message(STATUS "Looking for STM32CubeIDE.exe in ${h}") + if(CMAKE_HOST_WIN32) + if(EXISTS "${h}/STM32CubeIDE.exe") + _stm32cubeide_set_from_exec("${h}/STM32CubeIDE.exe") + endif() + elseif(CMAKE_HOST_APPLE) + if(EXISTS "${h}/STM32CubeIDE.app/Contents/MacOS/STM32CubeIDE") + _stm32cubeide_set_from_exec("${h}/STM32CubeIDE.app/Contents/MacOS/STM32CubeIDE") + elseif(EXISTS "${h}/Contents/MacOS/STM32CubeIDE") + _stm32cubeide_set_from_exec("${h}/Contents/MacOS/STM32CubeIDE") + endif() + else() + if(EXISTS "${h}/stm32cubeide") + _stm32cubeide_set_from_exec("${h}/stm32cubeide") + endif() + endif() +endforeach() + +# 2) PATH search +if(NOT STM32CUBEIDE_EXECUTABLE) + if(CMAKE_HOST_WIN32) + find_program(_CUBE_EXE NAMES "STM32CubeIDE.exe") + elseif(CMAKE_HOST_APPLE OR CMAKE_HOST_UNIX) + find_program(_CUBE_EXE NAMES "stm32cubeide") + endif() + if(_CUBE_EXE) + _stm32cubeide_set_from_exec("${_CUBE_EXE}") + endif() +endif() + +# 3) OS-specific probing +if(NOT STM32CUBEIDE_EXECUTABLE) + if(CMAKE_HOST_WIN32) + # Try Registry: uninstall entries often expose InstallLocation + # 64-bit and 32-bit views + foreach(_HK + "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall" + "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall") + execute_process(COMMAND reg query ${_HK} /f STM32CubeIDE /s + OUTPUT_VARIABLE _reg + ERROR_VARIABLE _reg_err + RESULT_VARIABLE _reg_rc) + if(_reg_rc EQUAL 0 AND _reg MATCHES "InstallLocation\\s+REG_SZ\\s+([^\r\n]+)") + string(REGEX REPLACE ".*InstallLocation\\s+REG_SZ\\s+([^\r\n]+).*" "\\1" _loc "${_reg}") + string(REPLACE "\\" "/" _loc "${_loc}") + if(EXISTS "${_loc}/STM32CubeIDE.exe") + _stm32cubeide_set_from_exec("${_loc}/STM32CubeIDE.exe") + endif() + endif() + endforeach() + + # Common default roots + if(NOT STM32CUBEIDE_EXECUTABLE) + file(GLOB _candidates + "C:/ST/STM32CubeIDE_*" + "C:/Program Files/STMicroelectronics/STM32CubeIDE*" + "C:/Program Files (x86)/STMicroelectronics/STM32CubeIDE*") + + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.7") + list(SORT _candidates COMPARE NATURAL ORDER DESCENDING) + else() + list(SORT _candidates) + list(REVERSE _candidates) + endif() + + foreach(_this_c ${_candidates}) + message(STATUS "Looking at ${_this_c}") + if(EXISTS "${_this_c}/STM32CubeIDE.exe") + message(STATUS "Found ${_this_c}/STM32CubeIDE.exe") + _stm32cubeide_set_from_exec("${_this_c}/STM32CubeIDE.exe") + break() + endif() + + if(EXISTS "${_this_c}/STM32CubeIDE/STM32CubeIDE.exe") + message(STATUS "Found ${_this_c}/STM32CubeIDE/STM32CubeIDE.exe") + _stm32cubeide_set_from_exec("${_this_c}/STM32CubeIDE/STM32CubeIDE.exe") + break() + endif() + endforeach() + endif() + + elseif(CMAKE_HOST_APPLE) + # Standard Applications folder + if(EXISTS "/Applications/STM32CubeIDE.app/Contents/MacOS/STM32CubeIDE") + _stm32cubeide_set_from_exec("/Applications/STM32CubeIDE.app/Contents/MacOS/STM32CubeIDE") + else() + # Fall back: scan *.app names + file(GLOB _apps "/Applications/STM32CubeIDE*.app") + + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.7") + list(SORT _apps COMPARE NATURAL ORDER DESCENDING) + else() + list(SORT _apps) + list(REVERSE _apps) + endif() + + foreach(app ${_apps}) + if(EXISTS "${app}/Contents/MacOS/STM32CubeIDE") + _stm32cubeide_set_from_exec("${app}/Contents/MacOS/STM32CubeIDE") + break() + endif() + endforeach() + + # Spotlight as last resort + if(NOT STM32CUBEIDE_EXECUTABLE) + execute_process(COMMAND mdfind "kMDItemCFBundleIdentifier == com.st.stm32cubeide" + OUTPUT_VARIABLE _mdfind RESULT_VARIABLE _mdrc) + if(_mdrc EQUAL 0 AND _mdfind) + string(REGEX MATCH ".*\\.app" _app "${_mdfind}") + if(_app AND EXISTS "${_app}/Contents/MacOS/STM32CubeIDE") + _stm32cubeide_set_from_exec("${_app}/Contents/MacOS/STM32CubeIDE") + endif() + endif() + endif() + endif() + + else() # Linux + # Desktop file -> Exec path + if(EXISTS "/usr/share/applications/stm32cubeide.desktop") + file(READ "/usr/share/applications/stm32cubeide.desktop" _desk) + string(REGEX MATCH "Exec=([^ \n\r]+)" _m "${_desk}") + if(_m) + string(REGEX REPLACE "Exec=([^ \n\r]+).*" "\\1" _exec "${_desk}") + # Resolve symlink if any + execute_process(COMMAND bash -lc "readlink -f \"${_exec}\"" OUTPUT_VARIABLE _rl RESULT_VARIABLE _rc) + if(_rc EQUAL 0) + string(STRIP "${_rl}" _rls) + if(EXISTS "${_rls}") + _stm32cubeide_set_from_exec("${_rls}") + endif() + elseif(EXISTS "${_exec}") + _stm32cubeide_set_from_exec("${_exec}") + endif() + endif() + endif() + + # Typical install roots under /opt + if(NOT STM32CUBEIDE_EXECUTABLE) + file(GLOB _candidates "/opt/st/stm32cubeide_*") + + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.7") + list(SORT _candidates COMPARE NATURAL ORDER DESCENDING) + else() + list(SORT _candidates) + list(REVERSE _candidates) + endif() + + foreach(c ${_candidates}) + if(EXISTS "${c}/stm32cubeide") + _stm32cubeide_set_from_exec("${c}/stm32cubeide") + break() + endif() + endforeach() + endif() + endif() # Windows or Mac else Linux +endif() # !STM32CUBEIDE_EXECUTABLE + + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(STM32CubeIDE + REQUIRED_VARS STM32CUBEIDE_EXECUTABLE STM32CUBEIDE_ROOT + FAIL_MESSAGE "STM32CubeIDE not found. Set STM32CUBEIDE_DIR or add it to PATH." +) + +if(STM32CUBEIDE_EXECUTABLE) + message(STATUS "Found STM32 CubeIDE: ${STM32CUBEIDE_EXECUTABLE}") + set(STM32CUBEIDE_FOUND TRUE) +else() + message(STATUS "Not found: STM32 CubeIDE") +endif() + +# The CubeIDE version likely does not match FW version: +# C:\Users\${CURRENT_USER}\STM32Cube\Repository\STM32Cube_FW_L4_V1.18.0\Drivers\STM32L4xx_HAL_Driver +# C:/Users/${CURRENT_USER}/STM32Cube/Repository/STM32Cube_FW_L4_V1.14.1/Drivers/ + +message(STATUS "CubeIDE Config WOLFBOOT_TARGET=${WOLFBOOT_TARGET}") +string(TOLOWER "${WOLFBOOT_TARGET}" _wb_target_lc) +string(FIND "${_wb_target_lc}" "stm32l4" _pos) +message(STATUS "Checking if the HAL and CMSIS libraries needed") +if(_pos EQUAL 0) + # Only do this for the L4! + find_newest_stm32cube_fw_l4(STM32CUBE_L4_ROOT STM32CUBE_L4_VERSION) + set(STM32_HAL_DIR "${STM32CUBE_L4_ROOT}/Drivers/STM32L4xx_HAL_Driver") + set(CMSIS_DIR "${STM32CUBE_L4_ROOT}/Drivers/CMSIS") + + if(STM32CUBE_L4_VERSION) + set(HAL_BASE "${STM32CUBE_L4_ROOT}") + if(IS_DIRECTORY "${HAL_BASE}") + message(STATUS "Found HAL_BASE=${HAL_BASE}") + set(FOUND_HAL_BASE true) + # CubeIDE + set_and_echo_dir(HAL_DRV "${HAL_BASE}/Drivers/STM32L4xx_HAL_Driver") + set_and_echo_dir(HAL_CMSIS_DEV "${HAL_BASE}/Drivers/CMSIS/Device/ST/STM32L4xx/Include") + set_and_echo_dir(HAL_CMSIS_CORE "${HAL_BASE}/Drivers/CMSIS/Include") + set_and_echo_dir(HAL_TEMPLATE_INC "${HAL_BASE}/Projects/B-L475E-IOT01A/Templates/Inc") + else() + message(STATUS "Not found expected HAL_BASE=${HAL_BASE}") + endif() + endif() +else() + message(STATUS "WOLFBOOT_TARGET=${WOLFBOOT_TARGET}, not loading HAL and CMSIS libraries.") +endif() # #STM32L4 detection + +string(FIND "${_wb_target_lc}" "stm32g0" _pos) +if(_pos EQUAL 0) + +endif() + +mark_as_advanced(STM32CUBEIDE_EXECUTABLE STM32CUBEIDE_ROOT STM32CUBEIDE_VERSION) + +set(CUBE_IDE_CONFIG_CMAKE_INCLUDED TRUE) +message(STATUS "End cube_ide_config.cmake") + +endif() # DETECT_CUBEIDE diff --git a/cmake/current_user.cmake b/cmake/current_user.cmake new file mode 100644 index 0000000000..19a3c6f52d --- /dev/null +++ b/cmake/current_user.cmake @@ -0,0 +1,106 @@ +# wolfboot/cmake/current_user.cmake +# +# 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 +# +# get_current_user() +# Sets to the best guess of the current user across Windows, Linux, macOS, and WSL. + +# Example usage +# get_current_user(CURRENT_USER) +# message(STATUS "Current user detected: ${CURRENT_USER}") + +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake, and anything else that wants to detect is loaded + if(DEFINED CURRENT_USER_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() + +function(get_current_user OUT_VAR) + set(_user "") + + # Fast path from environment + foreach(var USER USERNAME LOGNAME) + if(DEFINED ENV{${var}} AND NOT "$ENV{${var}}" STREQUAL "") + set(_user "$ENV{${var}}") + break() + endif() + endforeach() + + # Windows specific fallbacks (native Win or WSL) + if(_user STREQUAL "") + if(WIN32 OR DEFINED ENV{WSL_DISTRO_NAME}) + # Try PowerShell first + execute_process( + COMMAND powershell -NoProfile -Command "$env:USERNAME" + OUTPUT_VARIABLE _user + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + if(_user STREQUAL "") + # Fallback to cmd.exe + execute_process( + COMMAND cmd.exe /c echo %USERNAME% + OUTPUT_VARIABLE _user + ERROR_QUIET + ) + string(REPLACE "\r" "" _user "${_user}") + string(STRIP "${_user}" _user) + endif() + endif() + endif() + + # POSIX fallbacks + if(_user STREQUAL "") + execute_process( + COMMAND id -un + OUTPUT_VARIABLE _user + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + if(_user STREQUAL "") + execute_process( + COMMAND whoami + OUTPUT_VARIABLE _user + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + + # Last resort: CI hints or placeholder + if(_user STREQUAL "") + foreach(var GITHUB_ACTOR BUILD_USER USERNAME USER LOGNAME) + if(DEFINED ENV{${var}} AND NOT "$ENV{${var}}" STREQUAL "") + set(_user "$ENV{${var}}") + break() + endif() + endforeach() + endif() + if(_user STREQUAL "") + set(_user "unknown") + endif() + + set(${OUT_VAR} "${_user}" PARENT_SCOPE) +endfunction() + +set(CURRENT_USER_CMAKE_INCLUDED true) diff --git a/cmake/downloads/README.md b/cmake/downloads/README.md new file mode 100644 index 0000000000..81e7b682be --- /dev/null +++ b/cmake/downloads/README.md @@ -0,0 +1,21 @@ +# wolbBoot CMake Downloads + +Device-specific supplemental download specifications. + +Include in `CmakePresets.json` via the `WOLFBOOT_DOWNLOADS_CMAKE` + +``` +"cacheVariables": { + "WOLFBOOT_DOWNLOADS_CMAKE": "${sourceDir}/cmake/downloads/my_dependency.cmake" +} +``` + +Format for `my_dependency.cmake` entries: + +``` +add_download( + NAME some_name + URL https://github.com/some/repo.git + TAG 5.9.0 +) +``` diff --git a/cmake/downloads/stm32l4.cmake b/cmake/downloads/stm32l4.cmake new file mode 100644 index 0000000000..0900963ed3 --- /dev/null +++ b/cmake/downloads/stm32l4.cmake @@ -0,0 +1,39 @@ +# wolfboot/cmake/downloads/stm32l4.cmake +# +# 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 +# + +# The STM32L4 is known to need additional HAL source files: +add_download( + NAME st_hal + URL https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git + TAG v1.13.5 +) + +add_download( + NAME cmsis_dev + URL https://github.com/STMicroelectronics/cmsis_device_l4.git + TAG v1.7.4 +) + +add_download( + NAME cmsis_core + URL https://github.com/ARM-software/CMSIS_5.git + TAG 5.9.0 +) diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 9fe006c165..ea3930a9a2 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -1,4 +1,4 @@ -# functions.cmake +# wolfboot/cmake/functions.cmake # # Copyright (C) 2025 wolfSSL Inc. # @@ -18,6 +18,17 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake, and anything else that wants to detect is loaded + if(DEFINED FUNCTIONS_CMAKE_INCLUDED) + return() + endif() + set(FUNCTIONS_CMAKE_INCLUDED TRUE) +else() + include_guard(GLOBAL) +endif() + function(override_cache VAR VAL) get_property(VAR_STRINGS CACHE ${VAR} PROPERTY STRINGS) LIST(FIND VAR_STRINGS ${VAL} CK) @@ -55,3 +66,29 @@ function(add_option NAME HELP_STRING DEFAULT VALUES) endif() endfunction() +function(print_env VAR) + if(DEFINED ENV{${VAR}} AND NOT "$ENV{${VAR}}" STREQUAL "") + message(STATUS "${VAR} = $ENV{${VAR}}") + else() + message(STATUS "${VAR} = (not set)") + endif() +endfunction() + +# Sets to . +# If points to an existing directory, prints a STATUS message. +function(set_and_echo_dir var_name value_expr) + set(_val "${value_expr}") + # Export to caller's scope + set(${var_name} "${_val}" PARENT_SCOPE) + + if(IS_DIRECTORY "${_val}") + message(STATUS "-- set ${var_name}; Found directory: ${_val}") + else() + message(STATUS "-- Warning: set ${var_name}") + message(STATUS "-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + message(STATUS "-- Directory not found: ${_val}") + message(STATUS "-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") + endif() +endfunction() + +set(FUNCTIONS_CMAKE_INCLUDED true) diff --git a/cmake/load_dot_config.cmake b/cmake/load_dot_config.cmake new file mode 100644 index 0000000000..4a58408292 --- /dev/null +++ b/cmake/load_dot_config.cmake @@ -0,0 +1,152 @@ +# wolfboot/cmake/load_dot_config.cmake +# +# 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 +# +# Usage: +# include(cmake/load_dot_config.cmake) +# load_dot_config("${CMAKE_SOURCE_DIR}/.config") # set normal CMake vars +# # or cache them so GUIs (e.g. Visual Studio) can see/edit them: +# load_dot_config("${CMAKE_SOURCE_DIR}/.config" CACHE_VARS) + +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake, and anything else that wants to detect is loaded + if(DEFINED LOAD_DOT_CONFIG_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() + +function(load_dot_config CONFIG_PATH) + set(_USE_CACHE OFF) + foreach(_arg IN LISTS ARGN) + if(_arg STREQUAL "CACHE_VARS") + set(_USE_CACHE ON) + endif() + endforeach() + + message(STATUS "Reading config file: ${CONFIG_PATH}") + if(NOT EXISTS "${CONFIG_PATH}") + message(FATAL_ERROR "load_dot_config: File not found: ${CONFIG_PATH}") + endif() + + # Read the entire file, normalize newlines to \n, then split into a CMake list. + file(READ "${CONFIG_PATH}" _cfg_raw) + # Normalize CRLF and CR to LF + string(REPLACE "\r\n" "\n" _cfg_raw "${_cfg_raw}") + string(REPLACE "\r" "\n" _cfg_raw "${_cfg_raw}") + # Split into a list where each element is one line + string(REPLACE "\n" ";" _cfg_lines "${_cfg_raw}") + + message(STATUS "-- Parsing lines from config file...") + foreach(_line IN LISTS _cfg_lines) + # Strip comments and whitespace + string(REGEX REPLACE "\\s*#.*$" "" _line "${_line}") + string(STRIP "${_line}" _line) + if(_line STREQUAL "") + message(STATUS "-- Skipping blank line") + continue() + endif() + message(STATUS "-- Found line: ${_line}") + + # KEY[?]=VALUE + # CMAKE_MATCH_1 = KEY, CMAKE_MATCH_2 = "?" or "", CMAKE_MATCH_3 = VALUE + # Visual guide (ASCII only): + # Group 1: Key name (...........1..........) + # Optional Space [ \t]* + # Group 2: Operand ( 2 ) + # Literal equals = + # Optional Space [ \t] + # Group 3: Value ( 3) + if(NOT _line MATCHES "^([A-Za-z_][A-Za-z0-9_]*)[ \t]*([?]?)=[ \t]*(.*)$") + message(WARNING "load_dot_config: Skipping unrecognized line: ${_line}") + continue() + endif() + set(_key "${CMAKE_MATCH_1}") # Setting name + set(_op "${CMAKE_MATCH_2}") # operand "?" or "" + set(_val "${CMAKE_MATCH_3}") # the value to + message(STATUS "-- Parsed key: ${_key}") + message(STATUS "-- Parsed op: ${_op}") + message(STATUS "-- Parsed val: ${_val}") + + # Trim value spaces + string(STRIP "${_val}" _val) + + # Remove value surrounding double quotes if present + if(_val MATCHES "^\"(.*)\"$") + set(_val "${CMAKE_MATCH_1}") + endif() + + # Expand Make-style $(VAR) to CMake env form $ENV{VAR} + # We keep $ENV{VAR} literal in the set() call so it expands now. + # Do multiple replacements if many occurrences exist. + while(_val MATCHES "\\$\\(([A-Za-z_][A-Za-z0-9_]*)\\)") + string(REGEX REPLACE "\\$\\(([A-Za-z_][A-Za-z0-9_]*)\\)" "\$ENV{\\1}" _val "${_val}") + endwhile() + + # After replacing with $ENV{...}, expand it to its actual value now. + # The "configure" trick expands env refs without touching other text. + set(_expanded "${_val}") + string(CONFIGURE "${_expanded}" _expanded @ONLY) + + # Detect prior definition + set(_already_defined FALSE) + if(DEFINED ${_key}) + set(_already_defined TRUE) + message(STATUS "-- Already defined: ${_key}=${_val}") + else() + # Check cache + get_property(_cache_type CACHE "${_key}" PROPERTY TYPE SET) + if(_cache_type) + set(_already_defined TRUE) + message(STATUS "-- Already defined (cache) ${_key}=${_val}") + endif() + endif() + + # Respect ?= (only set if not already defined) + set(_should_set TRUE) + if(_op STREQUAL "?" AND _already_defined) + set(_should_set FALSE) + endif() + + if(_should_set) + if(_USE_CACHE) + # Use STRING so values like "0x1000" stay as text; FORCE to mirror Make's "=" + # For "?=", do not FORCE to preserve user edits from cache/GUI. + if(_op STREQUAL "?") + message(STATUS "-- Cache Conditional Assignment: ${_key}=${_expanded} from ${CONFIG_PATH}") + set(${_key} "${_expanded}" CACHE STRING "Imported from ${CONFIG_PATH}") + else() + message(STATUS "-- Cache Assignment: ${_key}=${_expanded} from ${CONFIG_PATH}") + set(${_key} "${_expanded}" CACHE STRING "Imported from ${CONFIG_PATH}" FORCE) + endif() + else() + # Set variable in parent scope so caller can see value. + message(STATUS "-- Assignment: ${_key}=${_val}") + set(${_key} "${_expanded}" PARENT_SCOPE) + endif() + else() + message(STATUS "-- Skipping assignment: ${_key}=${_val}") + endif() + endforeach() + message(STATUS "-- Done processing ${CONFIG_PATH}") +endfunction() + +set(LOAD_DOT_CONFIG_CMAKE_INCLUDED TRUE) diff --git a/cmake/preset-examples/CMakeUserPresets.json.sample b/cmake/preset-examples/CMakeUserPresets.json.sample new file mode 100644 index 0000000000..5cad019606 --- /dev/null +++ b/cmake/preset-examples/CMakeUserPresets.json.sample @@ -0,0 +1,24 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "my-stm32l4", + "displayName": "my STM32L4", + "inherits": [ + "stm32l4" + ], + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-my-stm32l4", + "cacheVariables": { + "ARM_GCC_BIN": "C:/SysGCC/arm-eabi/bin", + "HOST_CC": "C:/Program Files/LLVM/bin/clang.exe" + } + } + ], + "buildPresets": [ + { + "name": "my-stm32l4", + "configurePreset": "my-stm32l4" + } + ] +} diff --git a/cmake/preset-examples/README.md b/cmake/preset-examples/README.md new file mode 100644 index 0000000000..9792eabf71 --- /dev/null +++ b/cmake/preset-examples/README.md @@ -0,0 +1,3 @@ +# wolfBoot CMake USer Preset Examples + +[CMakeUserPresets.json.sample](./CMakeUserPresets.json.sample) Reference example. diff --git a/cmake/stm32_hal_download.cmake b/cmake/stm32_hal_download.cmake new file mode 100644 index 0000000000..4df82a17ca --- /dev/null +++ b/cmake/stm32_hal_download.cmake @@ -0,0 +1,197 @@ +# wolfboot/cmake/stm32_hal_download.cmake +# +# 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 +# + +# If not found: +# 1) The CubeIDE +# 2) VisualGDB/EmbeddedBSPs/arm-eabi/com.sysprogs.arm.stm32 +# 3) User-specified +# +# ... then download HAL files as needed: + +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake, and anything else that wants to detect is loaded + if(DEFINED STM32_HAL_DOWNLOAD_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() + + +if(ENABLE_HAL_DOWNLOAD) # Entire file wrapper + include(FetchContent) + + + if(NOT FUNCTIONS_CMAKE_INCLUDED) + include(cmake/functions.cmake) + endif() + + # Accumulators for the DSL + set(_DL_NAMES) + set(_DL_URLS) + set(_DL_TAGS) + + # Mini DSL + function(add_download) + cmake_parse_arguments(AD "" "" "NAME;URL;TAG" ${ARGN}) + if(NOT AD_NAME) + message(FATAL_ERROR "add_download requires NAME") + endif() + if(NOT AD_URL) + message(FATAL_ERROR "add_download requires URL") + endif() + if(NOT AD_TAG) + set(AD_TAG "master") + endif() + + list(APPEND _DL_NAMES "${AD_NAME}") + list(APPEND _DL_URLS "${AD_URL}") + list(APPEND _DL_TAGS "${AD_TAG}") + + set(_DL_NAMES "${_DL_NAMES}" PARENT_SCOPE) + set(_DL_URLS "${_DL_URLS}" PARENT_SCOPE) + set(_DL_TAGS "${_DL_TAGS}" PARENT_SCOPE) + endfunction() + + set(DOWNLOADS_FOUND false) + # If a downloads list is provided, include it + if(DEFINED WOLFBOOT_DOWNLOADS_CMAKE) + if(EXISTS "${WOLFBOOT_DOWNLOADS_CMAKE}") + message(STATUS "Including downloads list: ${WOLFBOOT_DOWNLOADS_CMAKE}") + include("${WOLFBOOT_DOWNLOADS_CMAKE}") + set(DOWNLOADS_FOUND true) + else() + # If there's a defined download, the file specified needs to exist! + message(FATAL_ERROR "WOLFBOOT_DOWNLOADS_CMAKE enabled but file now found: ${WOLFBOOT_DOWNLOADS_CMAKE}") + endif() + else() + message(STATUS "No WOLFBOOT_DOWNLOADS_CMAKE and no builtin defaults for target: ${WOLFBOOT_TARGET}. Skipping auto downloads.") + endif() # WOLFBOOT_DOWNLOADS_CMAKE + + # Fallback: The stm32l4 trio is known to be needed, so hard-coded here: + if(WOLFBOOT_TARGET STREQUAL "stm32l4" AND (NOT DOWNLOADS_FOUND)) + message(STATUS "WARNING not downloads found for known target needing them: stm32l4" ) + + add_download( + NAME st_hal + URL https://github.com/STMicroelectronics/stm32l4xx_hal_driver.git + TAG v1.13.5 + ) + add_download( + NAME cmsis_dev + URL https://github.com/STMicroelectronics/cmsis_device_l4.git + TAG v1.7.4 + ) + add_download( + NAME cmsis_core + URL https://github.com/ARM-software/CMSIS_5.git + TAG 5.9.0 + ) + endif() + + + # Validate lists are aligned + list(LENGTH _DL_NAMES _n1) + list(LENGTH _DL_URLS _n2) + list(LENGTH _DL_TAGS _n3) + if(NOT (_n1 EQUAL _n2 AND _n1 EQUAL _n3)) + message(FATAL_ERROR "add_download internal list length mismatch: names=${_n1} urls=${_n2} tags=${_n3}") + endif() + + # Nothing to do + if(_n1 EQUAL 0) + set(STM32_HAL_DOWNLOAD_CMAKE_INCLUDED TRUE) + #--------------------------------------------------------------------------------------------- + message(STATUS "No files found needing to be downloaded. If needed, configure WOLFBOOT_DOWNLOADS_CMAKE") + return() + #--------------------------------------------------------------------------------------------- + endif() + + # Fetch loop + set(FETCHCONTENT_QUIET OFF) + set(FETCHCONTENT_BASE_DIR "${CMAKE_BINARY_DIR}/_deps") + + set(_ALL_NAMES) + math(EXPR _last "${_n1} - 1") + foreach(i RANGE 0 ${_last}) + list(GET _DL_NAMES ${i} _name) + list(GET _DL_URLS ${i} _url) + list(GET _DL_TAGS ${i} _tag) + + message(STATUS "Fetching ${_url} (tag ${_tag})") + FetchContent_Declare(${_name} + GIT_REPOSITORY "${_url}" + GIT_TAG "${_tag}" + GIT_SHALLOW TRUE + GIT_PROGRESS FALSE + ) + list(APPEND _ALL_NAMES "${_name}") + endforeach() + + if(_ALL_NAMES) + FetchContent_MakeAvailable(${_ALL_NAMES}) + endif() + + # st_hal + FetchContent_GetProperties(st_hal) # ensures *_SOURCE_DIR vars are available + if(DEFINED st_hal_SOURCE_DIR AND EXISTS "${st_hal_SOURCE_DIR}") + set_and_echo_dir(HAL_BASE "${st_hal_SOURCE_DIR}") + set_and_echo_dir(HAL_DRV "${st_hal_SOURCE_DIR}") + else() + message(FATAL_ERROR "st_hal source dir not found; expected after FetchContent.") + endif() + + # cmsis_dev + FetchContent_GetProperties(cmsis_dev) + if(DEFINED cmsis_dev_SOURCE_DIR AND EXISTS "${cmsis_dev_SOURCE_DIR}") + set_and_echo_dir(HAL_CMSIS_DEV "${cmsis_dev_SOURCE_DIR}/Include") + else() + message(FATAL_ERROR "cmsis_dev source dir not found.") + endif() + + # cmsis_core + FetchContent_GetProperties(cmsis_core) + if(DEFINED cmsis_core_SOURCE_DIR AND EXISTS "${cmsis_core_SOURCE_DIR}") + set_and_echo_dir(HAL_CMSIS_CORE "${cmsis_core_SOURCE_DIR}/CMSIS/Core/Include") + else() + message(FATAL_ERROR "cmsis_core source dir not found.") + endif() + + + # Map include directories when known names are fetched + # Adjust or extend this block if you add more components + if(TARGET st_hal) + set_and_echo_dir(HAL_BASE "${st_hal_SOURCE_DIR}") + set_and_echo_dir(HAL_DRV "${st_hal_SOURCE_DIR}") + endif() + + if(TARGET cmsis_dev) + set_and_echo_dir(HAL_CMSIS_DEV "${cmsis_dev_SOURCE_DIR}/Include") + endif() + + if(TARGET cmsis_core) + set_and_echo_dir(HAL_CMSIS_CORE "${cmsis_core_SOURCE_DIR}/CMSIS/Core/Include") + endif() + +endif() #ENABLE_HAL_DOWNLOAD + +set(STM32_HAL_DOWNLOAD_CMAKE_INCLUDED true) diff --git a/cmake/toolchain_aarch64-none-elf.cmake b/cmake/toolchain_aarch64-none-elf.cmake index 4c3de5c546..7155e16ba8 100644 --- a/cmake/toolchain_aarch64-none-elf.cmake +++ b/cmake/toolchain_aarch64-none-elf.cmake @@ -18,11 +18,21 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake + if(DEFINED TOOLCHAIN_AARCH64_NONE_ELF_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() set(CMAKE_SYSTEM_NAME Generic) # There needs to be a default platform or the `project()` command will fail. if(NOT DEFINED WOLFBOOT_TARGET) + message(STATUS "WOLFBOOT_TARGET not set, defaulting to stm32h7") set(WOLFBOOT_TARGET "stm32h7") endif() @@ -86,7 +96,7 @@ message(STATUS "Cross-compiling using GNU aarch64-none-elf toolchain") # Options for DEBUG build # -Og Enables optimizations that do not interfere with debugging. -# -g Produce debugging information in the operating system’s native format. +# -g Produce debugging information in the operating system's native format. set(CMAKE_C_FLAGS_DEBUG "-Og -g" CACHE INTERNAL "C Compiler options for debug build type") set(CMAKE_CXX_FLAGS_DEBUG "-Og -g" CACHE INTERNAL "C++ Compiler options for debug build type") set(CMAKE_ASM_FLAGS_DEBUG "-g" CACHE INTERNAL "ASM Compiler options for debug build type") @@ -112,3 +122,5 @@ set(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG -flto -Wl,-flto" CACHE INTERNAL set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -flto -Wl,-flto" CACHE INTERNAL "C++ Compiler options for minimum size release build type") set(CMAKE_ASM_FLAGS_MINSIZEREL "" CACHE INTERNAL "ASM Compiler options for minimum size release build type") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-flto -Wl,-flto" CACHE INTERNAL "Linker options for minimum size release build type") + +set(TOOLCHAIN_AARCH64_NONE_ELF_CMAKE_INCLUDED true) diff --git a/cmake/toolchain_arm-none-eabi.cmake b/cmake/toolchain_arm-none-eabi.cmake index c2438f8359..21cd3ff138 100644 --- a/cmake/toolchain_arm-none-eabi.cmake +++ b/cmake/toolchain_arm-none-eabi.cmake @@ -1,4 +1,4 @@ -# toolchain_arm-none-eabi.cmake +# wolfboot/cmake/toolchain_arm-none-eabi.cmake # # Copyright (C) 2025 wolfSSL Inc. # @@ -18,15 +18,32 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake + if(DEFINED TOOLCHAIN_ARM_NONE_EABI_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() set(CMAKE_SYSTEM_NAME Generic) +# Keep try-compile from attempting to run target binaries +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES ARM_GCC_BIN WOLFBOOT_TARGET) + # There needs to be a default platform or the `project()` command will fail. if(NOT DEFINED WOLFBOOT_TARGET) - set(WOLFBOOT_TARGET "stm32h7") + message(STATUS "Select a target, e.g. 'cmake --preset stm32l4'") + message(FATAL_ERROR "WOLFBOOT_TARGET not set") + # set(WOLFBOOT_TARGET "stm32h7") endif() # Cortex-M CPU +# TODO move to presets if(WOLFBOOT_TARGET STREQUAL "stm32l0") set(CMAKE_SYSTEM_PROCESSOR cortex-m0) set(MCPU_FLAGS "-mcpu=cortex-m0 -mthumb -mlittle-endian -mthumb-interwork ") @@ -36,37 +53,104 @@ elseif(WOLFBOOT_TARGET STREQUAL "stm32u5") elseif(WOLFBOOT_TARGET STREQUAL "stm32h7") set(CMAKE_SYSTEM_PROCESSOR cortex-m7) set(MCPU_FLAGS "-mcpu=cortex-m7 -mthumb -mlittle-endian -mthumb-interwork") +elseif(WOLFBOOT_TARGET STREQUAL "stm32l4") + set(CMAKE_SYSTEM_PROCESSOR cortex-m4) + # L4 has FPU (single-precision). Let the toolchain pick the right libs. + set(MCPU_FLAGS "-mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard") else() set(CMAKE_SYSTEM_PROCESSOR cortex-m3) set(MCPU_FLAGS "-mcpu=cortex-m3 -mthumb -mlittle-endian -mthumb-interwork ") endif() -# ----------------------------------------------------------------------------- -# Set toolchain paths -# ----------------------------------------------------------------------------- -set(TOOLCHAIN arm-none-eabi) -set(CMAKE_CXX_STANDARD 20) +# ----- Select compilers (works on WSL/Linux and Windows) ----- +# Optional: allow an explicit bin dir +set(ARM_GCC_BIN "" CACHE PATH "Path to Arm GNU Toolchai 'bin' directory") + +if(CMAKE_HOST_WIN32) + message(STATUS "toolchain_arm-none-eabi.cmake is CMAKE_HOST_WIN32 mode") + if(ARM_GCC_BIN) + file(TO_CMAKE_PATH "${ARM_GCC_BIN}" _BIN) + set(CMAKE_C_COMPILER "${_BIN}/arm-none-eabi-gcc.exe" CACHE FILEPATH "" FORCE) + set(CMAKE_CXX_COMPILER "${_BIN}/arm-none-eabi-g++.exe" CACHE FILEPATH "" FORCE) + set(CMAKE_ASM_COMPILER "${_BIN}/arm-none-eabi-gcc.exe" CACHE FILEPATH "" FORCE) + else() + # Try PATH + find_program(CMAKE_C_COMPILER NAMES arm-none-eabi-gcc.exe + HINTS + "C:/Program Files/Ninja" + "C:/SysGCC/arm-eabi/bin" + "C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/14.2 rel1/bin" + "C:/ST/STM32CubeIDE_1.14.1/STM32CubeIDE/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.11.3.rel1.win32_1.1.100.202309141235/tools/bin" + ) + find_program(CMAKE_CXX_COMPILER NAMES arm-none-eabi-g++.exe + HINTS + "C:/Program Files/Ninja" + "C:/SysGCC/arm-eabi/bin" + "C:/Program Files (x86)/Arm GNU Toolchain arm-none-eabi/14.2 rel1/bin" + "C:/ST/STM32CubeIDE_1.14.1/STM32CubeIDE/plugins/com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.11.3.rel1.win32_1.1.100.202309141235/tools/bin" + ) + + set(CMAKE_ASM_COMPILER "${CMAKE_C_COMPILER}" CACHE FILEPATH "" FORCE) + endif() +else() + message(STATUS "toolchain_arm-none-eabi.cmake checking for arm compiler") + if(ARM_GCC_BIN) + file(TO_CMAKE_PATH "${ARM_GCC_BIN}" _BIN) + set(CMAKE_C_COMPILER "${_BIN}/arm-none-eabi-gcc" CACHE FILEPATH "" FORCE) + set(CMAKE_CXX_COMPILER "${_BIN}/arm-none-eabi-g++" CACHE FILEPATH "" FORCE) + set(CMAKE_ASM_COMPILER "${_BIN}/arm-none-eabi-gcc" CACHE FILEPATH "" FORCE) + else() + # Assume Mac / Linux is in path. No hints. + find_program(CMAKE_C_COMPILER NAMES arm-none-eabi-gcc) + find_program(CMAKE_CXX_COMPILER NAMES arm-none-eabi-g++) + set(CMAKE_ASM_COMPILER "${CMAKE_C_COMPILER}" CACHE FILEPATH "" FORCE) + endif() +endif() +message(STATUS "Found CMAKE_C_COMPILER=${CMAKE_C_COMPILER}") +# Use the compiler's own include dir (Homebrew GCC may have no sysroot) execute_process( - COMMAND which ${TOOLCHAIN}-gcc - OUTPUT_VARIABLE TOOLCHAIN_GCC_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE) + COMMAND ${CMAKE_C_COMPILER} -print-file-name=include + OUTPUT_VARIABLE GCC_INCLUDE_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) +if(GCC_INCLUDE_DIR AND EXISTS "${GCC_INCLUDE_DIR}") + include_directories(SYSTEM "${GCC_INCLUDE_DIR}") +endif() # get toolchain version. CMAKE_C_COMPILER_VERSION cannot be used here since its not defined until # `project()` is run in the top-level cmake. The toolchain has to be setup before the `project` call execute_process( - COMMAND ${TOOLCHAIN}-gcc -dumpversion - OUTPUT_VARIABLE TOOLCHAIN_GCC_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) + COMMAND ${CMAKE_C_COMPILER} -print-sysroot + OUTPUT_VARIABLE GCC_SYSROOT + OUTPUT_STRIP_TRAILING_WHITESPACE +) +if(GCC_SYSROOT) + set(CMAKE_SYSROOT "${GCC_SYSROOT}") +endif() -get_filename_component(TOOLCHAIN_BIN_DIR ${TOOLCHAIN_GCC_PATH} DIRECTORY) -get_filename_component(TOOLCHAIN_ROOT_DIR "${TOOLCHAIN_BIN_DIR}/../" DIRECTORY ABSOLUTE) -set(CMAKE_SYSROOT ${TOOLCHAIN_ROOT_DIR}/${TOOLCHAIN}) +# Some sanity checks on compiler and target OS +# TODO remove OS specific presets +if(NOT CMAKE_C_COMPILER OR NOT CMAKE_CXX_COMPILER) + if("${TARGET_OS}" STREQUAL "") + message(STATUS "Warning: cmake presets should define TARGET_OS = [WINDOWS | LINUX]") + endif() + if(CMAKE_HOST_WIN32) + if("${TARGET_OS}" STREQUAL "LINUX") + message(FATAL_ERROR "Linux presets are not supported in Windows. Choose a different preset.") + endif() + else() + if("${TARGET_OS}" STREQUAL "Windows") + message(FATAL_ERROR "Windows presets are only supported on Windows. Choose a different preset.") + endif() + endif() + message(FATAL_ERROR "arm-none-eabi toolchain not found. Set ARM_GCC_BIN or add to PATH.") +endif() -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- # Set compiler/linker flags -#----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- set(OBJECT_GEN_FLAGS "${MCPU_FLAGS} -Wall -Wextra -Wno-main -ffreestanding -Wno-unused -ffunction-sections -fdata-sections" ) @@ -76,19 +160,27 @@ set(CMAKE_C_FLAGS "${OBJECT_GEN_FLAGS}" CACHE INTERNAL "C Compiler options") set(CMAKE_ASM_FLAGS "${OBJECT_GEN_FLAGS}" CACHE INTERNAL "ASM Compiler options") set(CMAKE_EXE_LINKER_FLAGS "${MCPU_FLAGS} ${LD_FLAGS} -Wl,--gc-sections --specs=nano.specs --specs=nosys.specs" CACHE INTERNAL "Linker options") -#--------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- # Set compilers and toolchain utilities -#--------------------------------------------------------------------------------------- -set(CMAKE_C_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "C Compiler") -set(CMAKE_CXX_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-g++ CACHE INTERNAL "C++ Compiler") -set(CMAKE_ASM_COMPILER ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc CACHE INTERNAL "ASM Compiler") -set(TOOLCHAIN_LD ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-ld CACHE INTERNAL "Toolchain linker") -set(TOOLCHAIN_AR ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-gcc-ar CACHE INTERNAL "Toolchain archive tool") -set(TOOLCHAIN_OBJCOPY ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-objcopy CACHE INTERNAL "Toolchain objcopy tool") -set(TOOLCHAIN_OBJDUMP ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-objdump CACHE INTERNAL "Toolchain objdump tool") -set(TOOLCHAIN_SIZE ${TOOLCHAIN_BIN_DIR}/${TOOLCHAIN}-size CACHE INTERNAL "Toolchain object size tool") - -set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_PREFIX}/${${TOOLCHAIN}} ${CMAKE_PREFIX_PATH}) +#--------------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- +# Derive toolchain helper paths from the chosen compiler +#--------------------------------------------------------------------------------------------- +get_filename_component(_BIN_DIR "${CMAKE_C_COMPILER}" DIRECTORY) +if(CMAKE_HOST_WIN32) + set(_EXE ".exe") +else() + set(_EXE "") +endif() + + +set(TOOLCHAIN_AR "${_BIN_DIR}/arm-none-eabi-ar${_EXE}" CACHE INTERNAL "") +set(TOOLCHAIN_OBJCOPY "${_BIN_DIR}/arm-none-eabi-objcopy${_EXE}" CACHE INTERNAL "") +set(TOOLCHAIN_OBJDUMP "${_BIN_DIR}/arm-none-eabi-objdump${_EXE}" CACHE INTERNAL "") +set(TOOLCHAIN_SIZE "${_BIN_DIR}/arm-none-eabi-size${_EXE}" CACHE INTERNAL "") + + +# set(CMAKE_FIND_ROOT_PATH ${TOOLCHAIN_PREFIX}/${${TOOLCHAIN}} ${CMAKE_PREFIX_PATH}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) @@ -98,7 +190,7 @@ message(STATUS "Cross-compiling using GNU arm-none-eabi toolchain") # Options for DEBUG build # -Og Enables optimizations that do not interfere with debugging. -# -g Produce debugging information in the operating system’s native format. +# -g Produce debugging information in the operating system's native format. set(CMAKE_C_FLAGS_DEBUG "-Og -g" CACHE INTERNAL "C Compiler options for debug build type") set(CMAKE_CXX_FLAGS_DEBUG "-Og -g" CACHE INTERNAL "C++ Compiler options for debug build type") set(CMAKE_ASM_FLAGS_DEBUG "-g" CACHE INTERNAL "ASM Compiler options for debug build type") @@ -124,3 +216,27 @@ set(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG -flto -Wl,-flto" CACHE INTERNAL set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -flto -Wl,-flto" CACHE INTERNAL "C++ Compiler options for minimum size release build type") set(CMAKE_ASM_FLAGS_MINSIZEREL "" CACHE INTERNAL "ASM Compiler options for minimum size release build type") set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-flto -Wl,-flto" CACHE INTERNAL "Linker options for minimum size release build type") + + +# Locate the GNU Arm bin dir from the compiler path +get_filename_component(_gcc_dir "${CMAKE_C_COMPILER}" DIRECTORY) + +# Prefer the tool right next to the compiler +find_program(CMAKE_SIZE + NAMES arm-none-eabi-size + HINTS "${_gcc_dir}" + NO_DEFAULT_PATH +) +# Fallback: PATH search +if(NOT CMAKE_SIZE) + find_program(CMAKE_SIZE NAMES arm-none-eabi-size) +endif() + +# Make it visible to all dirs and saved in CMakeCache.txt +if(CMAKE_SIZE) + set(CMAKE_SIZE "${CMAKE_SIZE}" CACHE FILEPATH "Path to arm-none-eabi-size") +else() + message(STATUS "CMAKE_SIZE arm-none-eabi-size not found; add your ARM GCC bin dir to PATH or fix the toolchain hints.") +endif() + +set(TOOLCHAIN_ARM_NONE_EABI_CMAKE_INCLUDED true) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 60e2bbf6c1..39b355f960 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -18,6 +18,17 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake + if(DEFINED UTILS_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() + # -------------------------------------------------------------------------------------------------- # Utility for properly installing a file output regardless of if the current configuration is multi # config or not @@ -56,19 +67,30 @@ macro(gen_bin_target_outputs TARGET) # Create bin from elf target add_custom_command( - OUTPUT ${FILENAME}.bin + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FILENAME}.bin" + COMMAND "${TOOLCHAIN_OBJCOPY}" + -O binary "$" + "${CMAKE_CURRENT_BINARY_DIR}/${FILENAME}.bin" DEPENDS ${TARGET} - COMMAND ${TOOLCHAIN_OBJCOPY} -O binary $ - $.bin) + VERBATIM + ) list(APPEND TARGET_OUTPUTS ${FILENAME}.bin) # Print size of bin target add_custom_command( - OUTPUT ${FILENAME}.size + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FILENAME}.size" DEPENDS ${TARGET} - COMMAND ${TOOLCHAIN_SIZE} $ | tee $.size) + COMMAND "${CMAKE_COMMAND}" + -DTOOLCHAIN_SIZE=${TOOLCHAIN_SIZE} + -DINPUT=$ + -DOUT=${CMAKE_CURRENT_BINARY_DIR}/${FILENAME}.size + -P "${SIZE_SCRIPT}" + VERBATIM + ) list(APPEND TARGET_OUTPUTS ${FILENAME}.size) # Add top level target for all MCU standard outputs add_custom_target(${FILENAME}_outputs ALL DEPENDS ${TARGET_OUTPUTS}) endmacro() + +set(UTILS_CMAKE_INCLUDED true) diff --git a/cmake/visualgdb_config.cmake b/cmake/visualgdb_config.cmake new file mode 100644 index 0000000000..24fad6534b --- /dev/null +++ b/cmake/visualgdb_config.cmake @@ -0,0 +1,93 @@ +# wolfboot/cmake/visualgdb_config.cmake +# +# 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 +# + +# See wolfboot/cmake/config_defaults.cmake + +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake + if(DEFINED VISUALGDB_CONFIG_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() + +# VisualGDB toolchains are installed automatically with the product +# or can be found at: https://gnutoolchains.com/download/ + +if(DETECT_VISUALGDB) + message(STATUS "Begin VisualGDB detection...") + # TODO needs to be more generic, perhaps in presets? + + if("${WOLFBOOT_TARGET}" STREQUAL "" ) + message(STATUS "WOLFBOOT_TARGET is not defined") + else() + string(STRIP "${WOLFBOOT_TARGET}" _target_trimmed) + string(TOUPPER "${_target_trimmed}" WOLFBOOT_TARGET_DIR) + if(WOLFBOOT_TARGET_DIR MATCHES "^STM32") + message(STATUS "Starts with STM32, will look for ${WOLFBOOT_TARGET_DIR}") + else() + message(STATUS "WARNING: target not yet supported: ${WOLFBOOT_TARGET}") + endif() + endif() + + if("${HAL_BASE}" STREQUAL "") + message(STATUS "HAL_BASE not yet found, searching VisualGDB...") + + # VisualDGB files can be used from Windows: + if(IS_DIRECTORY "C:/Users/${CURRENT_USER}/AppData/Local/VisualGDB") + set(LIB_STM32_WINDOWS "C:/Users/${CURRENT_USER}/AppData/Local/VisualGDB/EmbeddedBSPs/arm-eabi/com.sysprogs.arm.stm32/${WOLFBOOT_TARGET_DIR}xxxx") + if(IS_DIRECTORY "${LIB_STM32_WINDOWS}") + set(FOUND_HAL_BASE true) + message(STATUS "LIB_STM32_WINDOWS found: ${LIB_STM32_WINDOWS}") + set_and_echo_dir(HAL_BASE "${LIB_STM32_WINDOWS}") + endif() + endif() + + # VisualDGB files can also be used from WSL: + if(IS_DIRECTORY "/mnt/c/Users/${CURRENT_USER}/AppData/Local/VisualGDB") + set(LIB_STM32_WSL "/mnt/c/Users/${CURRENT_USER}/AppData/Local/VisualGDB/EmbeddedBSPs/arm-eabi/com.sysprogs.arm.stm32/${WOLFBOOT_TARGET_DIR}xxxx") + if(IS_DIRECTORY "${LIB_STM32_WSL}") + set(FOUND_HAL_BASE true) + message(STATUS "LIB_STM32_WSL found: ${LIB_STM32_WSL}") + set_and_echo_dir(HAL_BASE "${LIB_STM32_WSL}") + endif() + endif() + + if("${HAL_BASE}" STREQUAL "") + message(STATUS "VisualGDB detection could not set HAL_BASE") + else() + # VisualGDB + set_and_echo_dir(HAL_DRV "${HAL_BASE}/${WOLFBOOT_TARGET_DIR}xx_HAL_Driver") + set_and_echo_dir(HAL_CMSIS_DEV "${HAL_BASE}/CMSIS_HAL/Device/ST/${WOLFBOOT_TARGET_DIR}xx/Include") + set_and_echo_dir(HAL_CMSIS_CORE "${HAL_BASE}/CMSIS_HAL/Include") + # In VisualGDB, the samples are in the parent from the HAL_BASE + # set_and_echo_dir(HAL_TEMPLATE_INC "${HAL_BASE}/../VendorSamples/L4/Projects/B-L475E-IOT01A/Templates/Inc") + endif() + else() + message(STATUS "Skipped VisualGDB, found HAL_BASE=${HAL_BASE}") + endif() + + message(STATUS "Completed VisualGDB detection.") +endif() # if visualgdb_config.cmake + +set(VISUALGDB_CONFIG_CMAKE_INCLUDED TRUE) diff --git a/cmake/vs2022_config.cmake b/cmake/vs2022_config.cmake new file mode 100644 index 0000000000..d4a65bfb42 --- /dev/null +++ b/cmake/vs2022_config.cmake @@ -0,0 +1,176 @@ +# wolfboot/cmake/vs2022_config.cmake +# +# 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 +# + +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake + if(DEFINED VS2022_CONFIG_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() + +# See cmake/config_defaults.cmake for environment config and detection preferences. +if(DETECT_VS2022) + +if(USE_32BIT_LIBS) +# Raw inputs copied from your Developer Prompt +set(WIN_DEV_PATH_RAW [=[ +C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\bin\HostX86\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\VCPackages;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\bin\Roslyn;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\;C:\Program Files (x86)\HTML Help Workshop;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Team Tools\DiagnosticsHub\Collector;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\CodeCoverage.Console;C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\\x86;C:\Program Files (x86)\Windows Kits\10\bin\\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\\MSBuild\Current\Bin\amd64;C:\Windows\Microsoft.NET\Framework\v4.0.30319;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Git\cmd;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-15.2.0_20250920\riscv32-esp-elf\bin;C:\SysGCC\esp32-master\tools\xtensa-esp-elf\esp-15.2.0_20250920\xtensa-esp-elf\bin;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Git\cmd;C:\Users\%USERNAME%\AppData\Local\Microsoft\WindowsApps;C:\Users\%USERNAME%\AppData\Local\Programs\Microsoft VS Code\bin;C:\ST\STM32CubeIDE_1.14.1\STM32CubeIDE\plugins\com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.win32_2.1.100.202311100844\tools\bin;C:\Program Files\Git\usr\bin\;C:\Users\%USERNAME%\.dotnet\tools;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-13.2.0_20240530\riscv32-esp-elf\bin;C:\Users\%USERNAME%\AppData\Local\Microsoft\WinGet\Packages\Ninja-build.Ninja_Microsoft.Winget.Source_8wekyb3d8bbwe;;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\Linux\bin\ConnectionManagerExe +]=]) + +set(WIN_DEV_INCLUDE_RAW [=[ +C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\VS\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\um;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\shared;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\winrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um +]=]) + +set(WIN_DEV_LIB_RAW [=[ +C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\lib\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\lib\x86;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x86;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\ucrt\x86;C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86 +]=]) +endif() + + +if(USE_64BIT_LIBS) +set(WIN_DEV_PATH_RAW [=[ +C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\bin\HostX64\x64;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\VCPackages;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\bin\Roslyn;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\;C:\Program Files (x86)\HTML Help Workshop;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Team Tools\DiagnosticsHub\Collector;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\CodeCoverage.Console;C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\\x64;C:\Program Files (x86)\Windows Kits\10\bin\\x64;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\\MSBuild\Current\Bin\amd64;C:\Windows\Microsoft.NET\Framework64\v4.0.30319;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Git\cmd;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-15.2.0_20250920\riscv32-esp-elf\bin;C:\SysGCC\esp32-master\tools\xtensa-esp-elf\esp-15.2.0_20250920\xtensa-esp-elf\bin;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Git\cmd;C:\Users\%USERNAME%\AppData\Local\Microsoft\WindowsApps;C:\Users\%USERNAME%\AppData\Local\Programs\Microsoft VS Code\bin;C:\ST\STM32CubeIDE_1.14.1\STM32CubeIDE\plugins\com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.win32_2.1.100.202311100844\tools\bin;C:\Program Files\Git\usr\bin\;C:\Users\%USERNAME%\.dotnet\tools;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-13.2.0_20240530\riscv32-esp-elf\bin;C:\Users\%USERNAME%\AppData\Local\Microsoft\WinGet\Packages\Ninja-build.Ninja_Microsoft.Winget.Source_8wekyb3d8bbwe;;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\Linux\bin\ConnectionManagerExe;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\vcpkg +]=]) + +set(WIN_DEV_INCLUDE_RAW [=[ +C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\VS\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\um;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\shared;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\winrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um +]=]) + +set(WIN_DEV_LIB_RAW [=[ +C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\lib\x64;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\lib\x64;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\lib\x86\store\references;C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.26100.0;C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0;C:\Windows\Microsoft.NET\Framework64\v4.0.30319 +]=]) +endif() + + +# Normalize a raw path token: strip quotes/whitespace, convert to CMake-style slashes +function(_normalize_path _out _in) + set(_p "${_in}") + string(REPLACE "\"" "" _p "${_p}") + string(STRIP "${_p}" _p) + + # Convert backslashes to forward slashes for CMake + file(TO_CMAKE_PATH "${_p}" _p) + + # Drop a single trailing slash to stabilize dedupe + if(_p MATCHES ".+/$") + string(REGEX REPLACE "/$" "" _p "${_p}") + endif() + set(${_out} "${_p}" PARENT_SCOPE) +endfunction() + +# Build a clean env-style variable from a raw ;-separated list +# Usage: +# build_env_from_dirs(PATH ) +# build_env_from_dirs(INCLUDE ) +# build_env_from_dirs(LIB ) +# +# Produces: +# _LIST -> CMake list of existing, deduplicated, normalized dirs +# _STRING -> Same, joined with ';' suitable for an env var +function(build_env_from_dirs NAME) + set(_seen ) + set(_final ) + set(_ok_to_add false) + message(STATUS "[${NAME}] build_env_from_dirs; USE_32BIT_LIBS=${USE_32BIT_LIBS}, USE_64BIT_LIBS=${USE_64BIT_LIBS}") + foreach(_raw IN LISTS ARGN) + if(_raw STREQUAL "") + continue() + endif() + + _normalize_path(_p "${_raw}") + if(_p STREQUAL "") + continue() + endif() + + if(IS_DIRECTORY "${_p}") + list(FIND _seen "${_p}" _idx) + if(_idx EQUAL -1) + # Not seen, check for x86 exclusions + string(FIND "${_p}" "/x86" _pos) + if(_pos GREATER -1) + # Known 32 bit names + if(USE_32BIT_LIBS) + set(_ok_to_add true) + else() + message(STATUS "-- [${NAME}] skipping 32 bit lib search path: ${_p}") + set(_ok_to_add false) + endif() + else() + # If not a known 32 bit name, it must be 64 bit + if(USE_64BIT_LIBS) + set(_ok_to_add true) + else() + message(STATUS "-- [${NAME}] skipping non-32 bit lib search path: ${_p}") + set(_ok_to_add false) + endif() + endif() + if(_ok_to_add) + message(STATUS "-- [${NAME}] appending search path: ${_p}") + + list(APPEND _final "${_p}") + list(APPEND _seen "${_p}") + endif() + endif() + else() + # Uncomment for troubleshooting + # message(STATUS "[${NAME}] Skipping missing: ${_p}") + endif() + endforeach() + + list(JOIN _final ";" _joined) + set(${NAME}_LIST "${_final}" PARENT_SCOPE) + set(${NAME}_STRING "${_joined}" PARENT_SCOPE) +endfunction() # build_env_from_dirs + +# Only helpful if Visual Studio is installed +# Note VS2022 is installed by default in GitHub workflow `runs-on: windows-latest` +if(IS_DIRECTORY "C:/Program Files/Microsoft Visual Studio/") + message(STATUS "Found C:/Program Files/Microsoft Visual Studio/") + # Build the CMake equivalents + build_env_from_dirs(PATH ${WIN_DEV_PATH_RAW}) + build_env_from_dirs(INCLUDE ${WIN_DEV_INCLUDE_RAW}) + build_env_from_dirs(LIB ${WIN_DEV_LIB_RAW}) +else() + message(STATUS "Visual Studio not found, skipping VS2022_config.cmake") +endif() + +# Results: +# PATH_LIST / PATH_STRING +# INCLUDE_LIST / INCLUDE_STRING +# LIB_LIST / LIB_STRING + +# Optional: export to the environment for tools launched by CMake +# set(ENV{Path} "${PATH_STRING}") +# set(ENV{INCLUDE} "${INCLUDE_STRING}") +# set(ENV{LIB} "${LIB_STRING}") + +# Optional: integrate with CMake search variables +# list(PREPEND CMAKE_PREFIX_PATH ${PATH_LIST}) +# list(PREPEND CMAKE_PROGRAM_PATH ${PATH_LIST}) +# list(PREPEND CMAKE_INCLUDE_PATH ${INCLUDE_LIST}) +# list(PREPEND CMAKE_LIBRARY_PATH ${LIB_LIST}) + +endif() # DETECT_VS2022 + +set(VS2022_CONFIG_CMAKE_INCLUDED true) diff --git a/cmake/wolfboot.cmake b/cmake/wolfboot.cmake index cae75bf9f5..4781b3b193 100644 --- a/cmake/wolfboot.cmake +++ b/cmake/wolfboot.cmake @@ -18,6 +18,16 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# Ensure this file is only included and initialized once +if(CMAKE_VERSION VERSION_LESS 3.10) + # Fallback path for older CMake + if(DEFINED WOLFBOOT_CMAKE_INCLUDED) + return() + endif() +else() + include_guard(GLOBAL) +endif() + include(${CMAKE_CURRENT_LIST_DIR}/utils.cmake) set(VERSION ${WOLFBOOT_VERSION}) @@ -89,29 +99,48 @@ endfunction() function(gen_wolfboot_factory_image PLATFORM_NAME TARGET) get_filename_component(FILENAME ${TARGET} NAME) - if(NOT DEFINED ${PLATFORM_NAME}_BOOT_ADDRESS) - message(FATAL_ERROR "${PLATFORM_NAME}_BOOT_ADDRESS is not defined") + # Resolve BOOT_ADDRESS from either _BOOT_ADDRESS or WOLFBOOT_PARTITION_BOOT_ADDRESS + set(_plat_boot_var "${PLATFORM_NAME}_BOOT_ADDRESS") + + if(DEFINED ${_plat_boot_var} AND NOT "${${_plat_boot_var}}" STREQUAL "") + message(STATUS "Found PLATFORM_NAME=${PLATFORM_NAME} for ${_plat_boot_var}") + set(BOOT_ADDRESS "${${_plat_boot_var}}") + elseif(DEFINED WOLFBOOT_PARTITION_BOOT_ADDRESS AND NOT "${WOLFBOOT_PARTITION_BOOT_ADDRESS}" STREQUAL "") + set(BOOT_ADDRESS "${WOLFBOOT_PARTITION_BOOT_ADDRESS}") + else() + message(FATAL_ERROR "BOOT_ADDRESS not defined. Define ${_plat_boot_var} or WOLFBOOT_PARTITION_BOOT_ADDRESS.") + endif() + message(STATUS "${_plat_boot_var}=${${_plat_boot_var}}") + message(STATUS "WOLFBOOT_PARTITION_BOOT_ADDRESS=${WOLFBOOT_PARTITION_BOOT_ADDRESS}") + message(STATUS "Selected BOOT_ADDRESS=${BOOT_ADDRESS}") + + # Additional check for ARCH_FLASH_OFFSET + if((NOT DEFINED ARCH_FLASH_OFFSET) OR ("${ARCH_FLASH_OFFSET}" STREQUAL "")) + message(FATAL_ERROR "ARCH_FLASH_OFFSET is not defined") + endif() + + message(STATUS "ARCH_FLASH_OFFSET=${ARCH_FLASH_OFFSET}") + if("${ARCH_FLASH_OFFSET}" STREQUAL "0x0") + # See if(ARCH STREQUAL "ARM") cmake section + message(STATUS " -- WARNING: ARCH_FLASH_OFFSET is 0x0") endif() if(NOT DEFINED BINASSEMBLE) message(FATAL_ERROR "BINASSEMBLE is not defined") endif() - if(NOT DEFINED ARCH_FLASH_OFFSET) - message(FATAL_ERROR "ARCH_FLASH_OFFSET is not defined") - endif() gen_wolfboot_signed_image(${TARGET}) - set(BOOT_ADDRESS ${${PLATFORM_NAME}_BOOT_ADDRESS}) # merge images add_custom_command( OUTPUT ${FILENAME}_factory.bin - DEPENDS $.bin ${FILENAME}_v${VERSION}_signed.bin + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/wolfboot_${PLATFORM_NAME}.bin" + "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_v${VERSION}_signed.bin" ${WOLFBOOT_SIGNING_PRIVATE_KEY} binAssemble - COMMAND ${BINASSEMBLE} ${FILENAME}_factory.bin ${ARCH_FLASH_OFFSET} - $.bin ${BOOT_ADDRESS} ${TARGET}_v${VERSION}_signed.bin + COMMAND ${BINASSEMBLE} "${CMAKE_CURRENT_BINARY_DIR}/${FILENAME}_factory.bin" ${ARCH_FLASH_OFFSET} + "${CMAKE_CURRENT_BINARY_DIR}/wolfboot_${PLATFORM_NAME}.bin" ${BOOT_ADDRESS} "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_v${VERSION}_signed.bin" COMMENT "Assembling ${FILENAME} factory image") list(APPEND BOOTLOADER_OUTPUTS ${FILENAME}_factory.bin) @@ -119,3 +148,5 @@ function(gen_wolfboot_factory_image PLATFORM_NAME TARGET) multiconfigfileinstall(${BOOTLOADER_OUTPUTS} bin) endfunction() + +set(WOLFBOOT_CMAKE_INCLUDED true) diff --git a/cmake/write_size.cmake b/cmake/write_size.cmake new file mode 100644 index 0000000000..4235cd00cd --- /dev/null +++ b/cmake/write_size.cmake @@ -0,0 +1,36 @@ +# write_size.cmake +# +# 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 + + +# Args: -DINPUT=... -DOUT=... -DTOOLCHAIN_SIZE=... +execute_process( + COMMAND "${TOOLCHAIN_SIZE}" "${INPUT}" + OUTPUT_VARIABLE SIZE_OUT + RESULT_VARIABLE RC +) +if(NOT RC EQUAL 0) + message(FATAL_ERROR "size failed with code ${RC}") +endif() + +# Echo to console (so you still see it in the build log) +message("${SIZE_OUT}") + +# Save to file +file(WRITE "${OUT}" "${SIZE_OUT}") diff --git a/config/examples/README.md b/config/examples/README.md new file mode 100644 index 0000000000..4325ce51e8 --- /dev/null +++ b/config/examples/README.md @@ -0,0 +1,29 @@ +# Config Example Files + +This directory contains example `.config` presets for various target devices. + +## Make + +The examples here can be copied directly to the project `.config` file to use with `make`. + +## CMake + +See the [CMakePresets.json](../../CMakePresets.json) file. + +Config files can be added or updated to the `CMakePresets.json` like this: + +```bash +python3 ./tools/scripts/config2presets.py ./config/examples/stm32h7.config + +# then test it: + +./tools/scripts/wolfboot_cmake_full_build.sh --target stm32h7 +``` + +## Troubleshooting + +The wrong toolchain is being used, or a target was not specified + +``` +Error: no such instruction: `isb' +``` diff --git a/config/examples/visualgdb-stm32l4.config b/config/examples/visualgdb-stm32l4.config new file mode 100644 index 0000000000..2bb6aed08e --- /dev/null +++ b/config/examples/visualgdb-stm32l4.config @@ -0,0 +1,33 @@ +VISUALGDB=1 +VISUALGDB_BASE=/mnt/c/Users/$(USER)/AppData/Local/VisualGDB/EmbeddedBSPs/arm-eabi/com.sysprogs.arm.stm32/STM32L4xxxx + +TARGET=stm32l4 +STM32L4_PART?=STM32L475xx +BOARD=B-L475E-IOT01A + +SIGN=ECC256 +HASH=SHA256 +DEBUG?=0 +VTOR?=1 +CORTEX_M0?=0 +NO_ASM?=0 +EXT_FLASH?=0 +SPI_FLASH?=0 +ALLOW_DOWNGRADE?=0 +NVM_FLASH_WRITEONCE=1 +WOLFBOOT_VERSION?=0 +V?=0 +SPMATH?=1 +RAM_CODE?=0 +DUALBANK_SWAP?=0 + +# (Optional) Silence the "integer expression expected" warning cleanly +# Hex is fine functionally, but bash 'test' in some make rules dislikes it. +IMAGE_HEADER_SIZE?=512 # 0x200 + +WOLFBOOT_SECTOR_SIZE=0x1000 +WOLFBOOT_PARTITION_SIZE=0x7A000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x0800A000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x08084000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x080FE000 +WOLFTPM?=0 diff --git a/docs/CMake.md b/docs/CMake.md new file mode 100644 index 0000000000..6f156f8ddd --- /dev/null +++ b/docs/CMake.md @@ -0,0 +1,3 @@ +# wolfBoot CMake + +See the [`WOLFBOOT_ROOT`/cmake/README.md](../cmake/README.md) file. diff --git a/docs/PQ.md b/docs/PQ.md index 9eb0caa268..a6b2a1cb89 100644 --- a/docs/PQ.md +++ b/docs/PQ.md @@ -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 @@ -95,7 +95,7 @@ tradeoff. Stateful HBS schemes are based on the security of their underlying hash functions and Merkle trees, which are not expected to be broken by the advent of cryptographically relevant quantum computers. For this reason they have -been recommended by both NIST SP 800-208, and the NSA’s CNSA 2.0 suite. +been recommended by both NIST SP 800-208, and the NSA's CNSA 2.0 suite. See these links for more info on stateful HBS support and wolfSSL/wolfCrypt: - https://www.wolfssl.com/documentation/manuals/wolfssl/appendix07.html#post-quantum-stateful-hash-based-signatures diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..3ecd13c5e6 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,33 @@ +## 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/). + + +- [**API.md**](./API.md) - Overview of wolfBoot public APIs and how to use them. +- [**ata_security.md**](./ata_security.md) - ATA security features (lock/unlock, passwords) and wolfBoot integration. +- [**azure_keyvault.md**](./azure_keyvault.md) - Using Azure Key Vault for key management and signing with wolfBoot. +- [**CMake.md**](./CMake.md) - CMake-based build setup, presets, toolchains, and tips for building wolfBoot. +- [**compile.md**](./compile.md) - How to build/compile wolfBoot (toolchains, options, typical steps). +- [**encrypted_partitions.md**](./encrypted_partitions.md) - Creating and managing encrypted firmware/data partitions. +- [**firmware_image.md**](./firmware_image.md) - wolfBoot firmware image format, layout, and metadata. +- [**firmware_update.md**](./firmware_update.md) - Update flow: slots, verification, rollback, and recovery. +- [**flash-OTP.md**](./flash-OTP.md) - Using One-Time Programmable (OTP) regions in flash for secure data. +- [**flash_partitions.md**](./flash_partitions.md) - Flash partitioning schemes and configuration guidance. +- [**HAL.md**](./HAL.md) - Hardware Abstraction Layer notes and porting considerations. +- [**keystore.md**](./keystore.md) - Keystore design, key storage, and access strategies. +- [**lib.md**](./lib.md) - Using wolfBoot as a library and linking/integration guidance. +- [**Loader.md**](./Loader.md) - Loader/secondary stage behavior and handoff to application. +- [**measured_boot.md**](./measured_boot.md) - Measured boot concepts and recording measurements (e.g., PCRs). +- [**png/**](./png) - Folder of images/diagrams referenced by the documentation. +- [**PQ.md**](./PQ.md) - Post-quantum algorithms and PQC support in wolfBoot. +- [**README.md**](./README.md) - Overview and index of the documentation set. +- [**remote_flash.md**](./remote_flash.md) - Working with external/remote flash (SPI/QSPI, mapping, access). +- [**Renesas.md**](./Renesas.md) - Notes and specifics for Renesas platforms/ports. +- [**Signing.md**](./Signing.md) - Keys, signatures, and the image signing workflow. +- [**STM32-TZ.md**](./STM32-TZ.md) - STM32 TrustZone (Armv8-M) setup and usage with wolfBoot. +- [**STM32.md**](./STM32.md) - STM32 platform notes, options, and integration tips. +- [**Targets.md**](./Targets.md) - Supported targets and platform-specific configuration. +- [**TPM.md**](./TPM.md) - TPM integration, measured boot, and attestation flows. +- [**wolfHSM.md**](./wolfHSM.md) - Integrating wolfHSM with wolfBoot for secure key operations. + + diff --git a/docs/STM32.md b/docs/STM32.md new file mode 100644 index 0000000000..6f169f1067 --- /dev/null +++ b/docs/STM32.md @@ -0,0 +1,123 @@ +## 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 +``` + +The device manufacturer toolchain _also_ needs to be installed. For example without the [STM32CubeIDE Software](https://www.st.com/en/development-tools/stm32cubeide.html), +errors like this will 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" + | ^~~~~~~~~~~~~~~~~ +``` + +## Quick Start + +```bash +git clone https://github.com/wolfssl/wolfBoot.git +cd wolfBoot +git submodule update --init + +## Use make +# edit your .config or copy from config/examples +make + +## OR ## + +# use cmake via wolfbuild.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 ` +* Build: `cmake --build --preset ` + +```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" + } + ] +} +``` diff --git a/docs/Signing.md b/docs/Signing.md index cdc36da9aa..465924066b 100644 --- a/docs/Signing.md +++ b/docs/Signing.md @@ -1,4 +1,4 @@ -# wolfBoot Key Tools +# wolfBoot Key Tools `keygen` and `sign` are two command line tools to be used on a PC (or automated server) environment to manage wolfBoot private keys and sign the initial diff --git a/docs/Windows.md b/docs/Windows.md new file mode 100644 index 0000000000..f712c73a3f --- /dev/null +++ b/docs/Windows.md @@ -0,0 +1,39 @@ +# Windows Barebones + +A Windows (no Visual Studio installed), perhaps for VS Code or DOS command-prompt only setup. + + + + +```dos +winget install -e --id LLVM.LLVM +``` + +Expect an output like: + +```text +Found LLVM [LLVM.LLVM] Version 21.1.3 +This application is licensed to you by its owner. +Microsoft is not responsible for, nor does it grant any licenses to, third-party packages. +Downloading https://github.com/llvm/llvm-project/releases/download/llvmorg-21.1.3/LLVM-21.1.3-win64.exe + ██████████████████████████████ 356 MB / 356 MB +Successfully verified installer hash +Starting package install... +Successfully installed +``` + +Expected install directory is + +``` +C:\Program Files\LLVM\bin +``` + +Add a `HOST_CC` to the `configurePresets` - `cacheVariables` as is done in the [CMakeUserPresets.json.sample](../cmake/preset-examples/CMakeUserPresets.json.sample): + +``` + "configurePresets": [ + { + "cacheVariables": { + "HOST_CC": "C:/Program Files/LLVM/bin/clang.exe" + } +``` diff --git a/hal/stm32l4xx_hal_conf.h b/hal/stm32l4xx_hal_conf.h index 85b39c2bd4..32c6f4b177 100644 --- a/hal/stm32l4xx_hal_conf.h +++ b/hal/stm32l4xx_hal_conf.h @@ -22,12 +22,30 @@ #ifndef __STM32L4xx_HAL_CONF_H #define __STM32L4xx_HAL_CONF_H -#define HAL_MODULE_ENABLED +#define HAL_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED #define HAL_FLASH_MODULE_ENABLED #define HAL_RCC_MODULE_ENABLED -#include "stm32l4xx_hal_flash.h" -#include "stm32l4xx_hal_rcc.h" + /* Many ST examples define this in stm32l4xx_hal_conf.h */ +#ifndef TICK_INT_PRIORITY + #define TICK_INT_PRIORITY 0U +#endif + +#include "stm32l4xx_hal_def.h" + +/* Pull in headers for the enabled modules */ +#if defined(HAL_CORTEX_MODULE_ENABLED) + #include "stm32l4xx_hal_cortex.h" +#endif +#if defined(HAL_FLASH_MODULE_ENABLED) + #include "stm32l4xx_hal_flash.h" + #include "stm32l4xx_hal_flash_ex.h" +#endif +#if defined(HAL_RCC_MODULE_ENABLED) + #include "stm32l4xx_hal_rcc.h" +#endif + #define assert_param(expr) ((void)0U) #endif /* __STM32L4xx_HAL_CONF_H */ diff --git a/tools/scripts/cmake_dev_prompt_test.bat b/tools/scripts/cmake_dev_prompt_test.bat new file mode 100644 index 0000000000..f680965d52 --- /dev/null +++ b/tools/scripts/cmake_dev_prompt_test.bat @@ -0,0 +1,79 @@ +::!/cmd/batch +:: +:: cmake_dev_prompt_test.bat +:: +:: Some cmake tests from a VS 2022 dev prompt +:: +:: We start in /tools/scripts, but build two directories up: from wolfBoot root +:: +:: Example: +:: C:\workspace\wolfBoot>.\tools\scripts\cmake_dev_prompt_test.bat +:: +@echo off +setlocal enableextensions enabledelayedexpansion + +rem === Resolve script path/dir === +set "SCRIPT_PATH=%~f0" +for %%I in ("%~dp0") do set "SCRIPT_DIR=%%~fI" + +rem === Repo root is parent of /tools/scripts === +for %%I in ("%SCRIPT_DIR%\..\..") do set "REPO_ROOT=%%~fI" + +rem === Caller's current directory === +for %%I in ("%CD%") do set "CALLER_CWD=%%~fI" + +rem === (Optional) Normalize to physical paths via PowerShell to resolve junctions/symlinks === +rem call :physpath "%SCRIPT_DIR%" SCRIPT_DIR_P +rem call :physpath "%REPO_ROOT%" REPO_ROOT_P +rem call :physpath "%CALLER_CWD%" CALLER_CWD_P +set "SCRIPT_DIR_P=%SCRIPT_DIR%" +set "REPO_ROOT_P=%REPO_ROOT%" +set "CALLER_CWD_P=%CALLER_CWD%" + +rem === Print only if caller CWD is neither nor \scripts === +if /I "%CALLER_CWD_P%"=="%REPO_ROOT_P%" goto after_print +if /I "%CALLER_CWD_P%"=="%REPO_ROOT_P%\scripts" goto after_print + +echo Caller CWD = %CALLER_CWD_P% +echo SCRIPT_DIR = %SCRIPT_DIR_P% +echo REPO_ROOT = %REPO_ROOT_P% + +:after_print +rem === Always work from repo root === +pushd "%REPO_ROOT_P%" || goto :err +echo Starting %~nx0 from %CD% + +:: Is CMake installed? +where cmake >nul 2>&1 +if errorlevel 1 ( + echo This test should be run from a VS2022 dev prompt. + echo Error: CMake is not installed or not found in path. + goto err +) + + +echo Remove prior build directories... +if exist "build-stm32l4" rmdir /s /q "build-stm32l4" || goto :err + + +:: Begin tests and examples + +cmake --preset stm32l4 + + +:: cmake --build --preset stm32l4 --parallel 4 -v + +cmake --build --preset stm32l4 + +:: Deleting immediately may cause an anti-virus file-locking problem +:: rmdir /s /q build-stm32l4 + +goto done + +:err +echo Failed +exit /b 1 + +:done +echo Done. +exit /b 0 diff --git a/tools/scripts/cmake_dot_config.sh b/tools/scripts/cmake_dot_config.sh new file mode 100644 index 0000000000..28a106698a --- /dev/null +++ b/tools/scripts/cmake_dot_config.sh @@ -0,0 +1,125 @@ +#!/bin/bash + +# cmake_dot_config.sh +# +# Example for using cmake with .config +# +# Reminder for WSL: +# git update-index --chmod=+x wolfboot_cmake_full_build.sh +# git commit -m "Make wolfboot_cmake_full_build.sh executable" +# git push + +# Specify the executable shell checker you want to use: +MY_SHELLCHECK="shellcheck" + +# Check if the executable is available in the PATH +if command -v "$MY_SHELLCHECK" >/dev/null 2>&1; then + # Run your command here + shellcheck "$0" || exit 1 +else + echo "$MY_SHELLCHECK is not installed. Please install it if changes to this script have been made." +fi + +set -euo pipefail + +# Begin common dir init, for /tools/scripts +# Resolve this script's absolute path and its directories +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_PATH="${SCRIPT_DIR}/$(basename -- "${BASH_SOURCE[0]}")" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" + +# Normalize to physical paths (no symlinks, no trailing slashes) +# SCRIPT_DIR_P="$(cd -- "$SCRIPT_DIR" && pwd -P)" +REPO_ROOT_P="$(cd -- "$REPO_ROOT" && pwd -P)" +CALLER_CWD_P="$(pwd -P)" # where the user ran the script from + +# Print only if caller's cwd is neither REPO_ROOT nor REPO_ROOT/scripts +case "$CALLER_CWD_P" in + "$REPO_ROOT_P" | "$REPO_ROOT_P"/scripts) + : # silent + ;; + *) + echo "Script paths:" + echo "-- SCRIPT_PATH =$SCRIPT_PATH" + echo "-- SCRIPT_DIR =$SCRIPT_DIR" + echo "-- REPO_ROOT =$REPO_ROOT" + ;; +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)" + +# End common dir init + +# Regardless of where launches, we should not be at pwd=WOLFBOOT_ROOT + +# Set some logging params +LOG_FILE="run.log" +KEYWORD="Config mode: dot" +echo "Saving output to $LOG_FILE" + +echo "Fetch stm32h7 example .config" + +SRC="./config/examples/stm32h7.config" +DST="./.config" + +# Exit if the .config file already exists (perhaps it is valid? we will delete our copy when done here) +if [ -e "$DST" ]; then + echo "ERROR: .config already exists! We need to copy a new test file. Delete or save existing file." >&2 + exit 1 +fi + +echo "Source config file: $SRC" +echo "Destination file: $DST" + +# Ensure source exists +if [ ! -f "$SRC" ]; then + echo "ERROR: Source not found: $SRC" >&2 + exit 1 +fi + +echo "copy $SRC $DST" +cp -p "$SRC" "$DST" || { echo "ERROR: Copy failed." >&2; exit 1; } + +# Verify destination exists and is non-empty +if [ ! -s "$DST" ]; then + echo "ERROR: Destination missing after copy or file is empty: $DST" >&2 + exit 1 +fi + +# Optional: verify content matches exactly +if ! cmp -s "$SRC" "$DST"; then + echo "ERROR: Destination content does not match source." >&2 + exit 1 +fi + +echo "OK: $DST created and verified." + +cp ./config/examples/stm32h7.config ./.config +ls .config + +echo "" +echo "This .config contents:" +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 + +# 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 + +# Sample build +cmake --build build-stm32h7 -j10 + +rm .config + diff --git a/tools/scripts/cmake_dotconfig_test.bat b/tools/scripts/cmake_dotconfig_test.bat new file mode 100644 index 0000000000..05ca903b54 --- /dev/null +++ b/tools/scripts/cmake_dotconfig_test.bat @@ -0,0 +1,133 @@ +::!/cmd/batch +:: +:: cmake_dotconfig_test.bat +:: +:: See similar Ubuntu workflow: .guthub\workflows\test-build-cmake-dot-config.yml +:: +:: Some cmake tests from a VS 2022 dev prompt +:: +:: We start in /tools/scripts, but build two directories up: from wolfBoot root +:: +:: Example: +:: C:\workspace\wolfBoot>.\tools\scripts\cmake_dotconfig_test.bat +:: +:: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +:: +:: TODO This DOS Batch File is currently FAILING for .config cmake +:: +:: Consider cmake presets or contact support +:: +:: See also working Linux / WSL: cmake_dot_config.sh +:: +:: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +@echo off +setlocal enableextensions enabledelayedexpansion + +rem === Resolve script path/dir === +set "SCRIPT_PATH=%~f0" +for %%I in ("%~dp0") do set "SCRIPT_DIR=%%~fI" + +rem === Repo root is parent of /tools/scripts === +for %%I in ("%SCRIPT_DIR%\..\..") do set "REPO_ROOT=%%~fI" + +rem === Caller's current directory === +for %%I in ("%CD%") do set "CALLER_CWD=%%~fI" + +rem === (Optional) Normalize to physical paths via PowerShell to resolve junctions/symlinks === +rem call :physpath "%SCRIPT_DIR%" SCRIPT_DIR_P +rem call :physpath "%REPO_ROOT%" REPO_ROOT_P +rem call :physpath "%CALLER_CWD%" CALLER_CWD_P +set "SCRIPT_DIR_P=%SCRIPT_DIR%" +set "REPO_ROOT_P=%REPO_ROOT%" +set "CALLER_CWD_P=%CALLER_CWD%" + +rem === Print only if caller CWD is neither nor \scripts === +if /I "%CALLER_CWD_P%"=="%REPO_ROOT_P%" goto after_print +if /I "%CALLER_CWD_P%"=="%REPO_ROOT_P%\scripts" goto after_print + +echo Caller CWD = %CALLER_CWD_P% +echo SCRIPT_DIR = %SCRIPT_DIR_P% +echo REPO_ROOT = %REPO_ROOT_P% + +:after_print +rem === Always work from repo root === +pushd "%REPO_ROOT_P%" || goto :err +echo Starting %~nx0 from %CD% + +:: Is CMake installed? +where cmake >nul 2>&1 +if errorlevel 1 ( + echo This test should be run from a VS2022 dev prompt. + echo Error: CMake is not installed or not found in path. + goto err +) + + +set "SRC=.\config\examples\stm32h7.config" +set "DST=.\.config" + + +echo Remove prior build directories... + +if exist "build-stm32h7" rmdir /s /q "build-stm32h7" || goto :err + +rem Exit if the .config file already exists (perhaps it is a valid file? we'll delete our copy when done here') +if exist ".config" ( + >&2 echo ERROR: .config already exists! We need to copy a new test file. Delete or save existing file. + goto :err +) + +rem cp ./config/examples/stm32h7.config ./.config + +echo "Source config file: %SRC%" +echo "Destination file: %DST%" + +rem Ensure source exists +if not exist "%SRC%" ( + >&2 echo ERROR: Source not found: "%SRC%" + goto :err +) + +echo copy %SRC% %DST% +copy "%SRC%" "%DST%" +if errorlevel 1 ( + >&2 echo ERROR: Copy failed. + goto :err +) + +rem Verify destination exists and is non-empty +if not exist "%DST%" ( + >&2 echo ERROR: Destination missing after copy: "%DST%" + goto :err +) + +echo( & rem blank line +echo Current directory: +pwd + +echo( & rem blank line +dir .config +echo( & rem blank line +echo .config contents: + +echo( & rem blank line +type .config +echo( & rem blank line + +echo Begin dot-config test + +cmake -S . -B build-stm32h7 -DUSE_DOT_CONFIG=ON -DWOLFBOOT_TARGET=stm32h7 + +cmake --build build-stm32h7 --parallel 1 + +del .config + +goto done + +:err +echo Failed +exit /b 1 + +:done +echo Done. +exit /b 0 diff --git a/tools/scripts/cmake_test.bat b/tools/scripts/cmake_test.bat new file mode 100644 index 0000000000..dcc2487265 --- /dev/null +++ b/tools/scripts/cmake_test.bat @@ -0,0 +1,81 @@ +::!/cmd/batch +:: +:: cmake_test.bat +:: +:: Unlike the cmake_dev_prompt_test.bat that is expected to run in a VS 2022 Dev Prompt +:: This test manually sets paths to cmake and include files (also assumes VS 2022 is installed, but can be any suitable path) +cls + +set "Path=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\bin\HostX86\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\VCPackages;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\bin\Roslyn;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\;C:\Program Files (x86)\HTML Help Workshop;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Team Tools\DiagnosticsHub\Collector;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\CodeCoverage.Console;C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\\x86;C:\Program Files (x86)\Windows Kits\10\bin\\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\\MSBuild\Current\Bin\amd64;C:\Windows\Microsoft.NET\Framework\v4.0.30319;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Git\cmd;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-15.2.0_20250920\riscv32-esp-elf\bin;C:\SysGCC\esp32-master\tools\xtensa-esp-elf\esp-15.2.0_20250920\xtensa-esp-elf\bin;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Git\cmd;C:\Users\gojimmypi\AppData\Local\Microsoft\WindowsApps;C:\Users\gojimmypi\AppData\Local\Programs\Microsoft VS Code\bin;C:\ST\STM32CubeIDE_1.14.1\STM32CubeIDE\plugins\com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.win32_2.1.100.202311100844\tools\bin;C:\Program Files\Git\usr\bin\;C:\Users\gojimmypi\.dotnet\tools;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-13.2.0_20240530\riscv32-esp-elf\bin;C:\Users\gojimmypi\AppData\Local\Microsoft\WinGet\Packages\Ninja-build.Ninja_Microsoft.Winget.Source_8wekyb3d8bbwe;;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\Linux\bin\ConnectionManagerExe" +set "INCLUDE=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\VS\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\um;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\shared;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\winrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um" +set "LIB=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\lib\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\lib\x86;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x86;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\ucrt\x86;C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86" + +:: We start in /tools/scripts, but build two directories up: from wolfBoot root + +:: Begin common start directory detection +@echo off +setlocal enableextensions enabledelayedexpansion + +rem === Resolve script path/dir === +set "SCRIPT_PATH=%~f0" +for %%I in ("%~dp0") do set "SCRIPT_DIR=%%~fI" + +rem === Repo root is parent of /tools/scripts === +for %%I in ("%SCRIPT_DIR%\..\..") do set "REPO_ROOT=%%~fI" + +rem === Caller's current directory === +for %%I in ("%CD%") do set "CALLER_CWD=%%~fI" + +rem === (Optional) Normalize to physical paths via PowerShell to resolve junctions/symlinks === +rem call :physpath "%SCRIPT_DIR%" SCRIPT_DIR_P +rem call :physpath "%REPO_ROOT%" REPO_ROOT_P +rem call :physpath "%CALLER_CWD%" CALLER_CWD_P +set "SCRIPT_DIR_P=%SCRIPT_DIR%" +set "REPO_ROOT_P=%REPO_ROOT%" +set "CALLER_CWD_P=%CALLER_CWD%" + +rem === Print only if caller CWD is neither nor \scripts === +if /I "%CALLER_CWD_P%"=="%REPO_ROOT_P%" goto after_print +if /I "%CALLER_CWD_P%"=="%REPO_ROOT_P%\scripts" goto after_print + +echo Caller CWD = %CALLER_CWD_P% +echo SCRIPT_DIR = %SCRIPT_DIR_P% +echo REPO_ROOT = %REPO_ROOT_P% + +:after_print +rem === Always work from repo root === +pushd "%REPO_ROOT_P%" || goto :err +echo Starting %~nx0 from %CD% +:: End common start directory detection + + +:: Is CMake installed? +where cmake >nul 2>&1 +if errorlevel 1 ( + echo This test should be run from a VS2022 dev prompt. + echo Error: CMake is not installed or not found in path. + goto err +) + + + +rmdir /s /q build-stm32l4 + +cmake --preset stm32l4 + + +:: cmake --build --preset stm32l4 --parallel 4 -v + +cmake --build --preset stm32l4 + +goto done + +:err +popd +echo Failed. +exit /b 1 + +:done +popd +echo Done. +exit /b 0 diff --git a/tools/scripts/cmake_test.sh b/tools/scripts/cmake_test.sh new file mode 100644 index 0000000000..bcc7aa2410 --- /dev/null +++ b/tools/scripts/cmake_test.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Specify the executable shell checker you want to use: +MY_SHELLCHECK="shellcheck" + +# Check if the executable is available in the PATH +if command -v "$MY_SHELLCHECK" >/dev/null 2>&1; then + # Run your command here + shellcheck "$0" || exit 1 +else + echo "$MY_SHELLCHECK is not installed. Please install it if changes to this script have been made." +fi + +# Resolve this script's absolute path and its directories +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_PATH="${SCRIPT_DIR}/$(basename -- "${BASH_SOURCE[0]}")" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../../" && pwd)" + +# Normalize to physical paths (no symlinks, no trailing slashes) +# SCRIPT_DIR_P="$(cd -- "$SCRIPT_DIR" && pwd -P)" +REPO_ROOT_P="$(cd -- "$REPO_ROOT" && pwd -P)" +CALLER_CWD_P="$(pwd -P)" # <— where the user ran the script from + +# Print only if caller's cwd is neither REPO_ROOT nor REPO_ROOT/scripts +case "$CALLER_CWD_P" in + "$REPO_ROOT_P" | "$REPO_ROOT_P"/scripts) + : # silent + ;; + *) + echo "Script paths:" + echo "-- SCRIPT_PATH =$SCRIPT_PATH" + echo "-- SCRIPT_DIR =$SCRIPT_DIR" + echo "-- REPO_ROOT =$REPO_ROOT" + ;; +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 "Remove prior build directories..." +rm -rf ./build-stm32l4 + +echo "cmake --preset stm32l4" + cmake --preset stm32l4 + +echo "cmake --build --preset stm32l4" + cmake --build --preset stm32l4 diff --git a/tools/scripts/config2presets.py b/tools/scripts/config2presets.py new file mode 100644 index 0000000000..76a2059dba --- /dev/null +++ b/tools/scripts/config2presets.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 + +# Adds .config file to CMakePresets.json +# +# Example: +# python3 ./tools/scripts/config2presets.py ./config/examples/stm32h7.config + +import argparse, json, os, re, sys +from collections import OrderedDict +from pathlib import Path + +COMMENT_RE = re.compile(r"\s*(#.*)?$") +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"} + + +def normalize_bool(s: str): + v = s.strip().lower() + if v in BOOL_TRUE: + return "ON" + if v in BOOL_FALSE: + return "OFF" + return None + + +def parse_config(path: Path): + kv = OrderedDict() + with path.open("r", encoding="utf-8") as f: + for ln in f: + if COMMENT_RE.fullmatch(ln): + continue + m = LINE_RE.match(ln.rstrip("\n")) + if not m: + # skip silently; load_dot_config warns elsewhere + continue + key, val = m.group(1), m.group(2).strip() + kv[key] = val + return kv + + +def choose_target(kv): + # Prefer explicit wolfBoot var; else accept TARGET if present + if "WOLFBOOT_TARGET" in kv and kv["WOLFBOOT_TARGET"]: + return kv["WOLFBOOT_TARGET"] + if "TARGET" in kv and kv["TARGET"]: + return kv["TARGET"] + return "custom" + + +def to_cache_vars(kv): + cache = OrderedDict() + for k, v in kv.items(): + # Map TARGET -> WOLFBOOT_TARGET if the latter is not already set + if k == "TARGET" and "WOLFBOOT_TARGET" not in kv: + cache["WOLFBOOT_TARGET"] = v + continue + + # Normalize booleans to ON/OFF; keep everything else as strings + nb = normalize_bool(v) + cache[k] = nb if nb is not None else v + return cache + + +def ensure_base_vars(cache, toolchain_path): + # Always ensure toolchain file is set + cache.setdefault("CMAKE_TOOLCHAIN_FILE", toolchain_path) + # Typically desired + cache.setdefault("BUILD_TEST_APPS", "ON") + # Force preset mode when generating from .config into presets + cache["WOLFBOOT_CONFIG_MODE"] = "preset" + return cache + + +def make_preset_name(target): + return f"{target}" + + +def make_binary_dir(source_dir, target): + return os.path.join(source_dir, f"build-{target}") + + +def load_existing_presets(presets_path: Path): + try: + with presets_path.open("r", encoding="utf-8") as f: + return json.load(f) + except FileNotFoundError: + return None + + +def merge_preset(doc, cfg_preset, bld_preset): + if doc is None: + return { + "version": 3, + "configurePresets": [cfg_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: + doc["configurePresets"] = [] + if "buildPresets" not in doc: + 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] + return doc + + +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") + 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 = (script_dir / ".." / "..").resolve() + + caller_cwd = Path.cwd().resolve() + + # Print only if caller's current working directory is neither REPO_ROOT nor REPO_ROOT/tools/scripts + if caller_cwd != repo_root and caller_cwd != (repo_root / "tools" / "scripts"): + print("Script paths:") + print(f"-- SCRIPT_PATH = {script_path}") + print(f"-- SCRIPT_DIR = {script_dir}") + print(f"-- REPO_ROOT = {repo_root}") + + # Always work from the repo root, regardless of where the script was invoked + try: + os.chdir(repo_root) + except OSError as e: + print(f"Failed to cd to: {repo_root}\n{e}", file=sys.stderr) + sys.exit(1) + print(f"Starting {script_path} from {Path.cwd().resolve()}") + # End common dir init + + # 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) + 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() + + kv = parse_config(config_path) + if not kv: + print(f"No settings parsed from .config: {config_path}", file=sys.stderr) + sys.exit(2) + + 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()) + + # 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})" + + 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"]), + ]) + + # Ensure schema v3 unless existing file says otherwise + doc = load_existing_presets(presets_path) + if doc is None: + doc = {"version": 3} + if "version" not in doc: + doc["version"] = 3 + + result = merge_preset(doc, cfg_preset, bld_preset) + + # Pretty-print with stable key order + with presets_path.open("w", encoding="utf-8") as f: + json.dump(result, f, indent=2) + f.write("\n") + + print(f"Updated {presets_path} with preset '{preset_name}' targeting '{target}'") + + +if __name__ == "__main__": + main() diff --git a/tools/scripts/wolfboot_cmake_full_build.sh b/tools/scripts/wolfboot_cmake_full_build.sh new file mode 100644 index 0000000000..66c1b7051c --- /dev/null +++ b/tools/scripts/wolfboot_cmake_full_build.sh @@ -0,0 +1,310 @@ +#!/bin/bash + +# wolfboot_cmake_full_build.sh +# +# ./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] +# +# Options: +# Set WOLFBOOT_CLEAN_STRICT=1 to error is any other build directories found +# +# Reminder for WSL: +# git update-index --chmod=+x wolfboot_cmake_full_build.sh +# git commit -m "Make wolfboot_cmake_full_build.sh executable" +# git push + +# Specify the executable shell checker you want to use: +MY_SHELLCHECK="shellcheck" + +# Check if the executable is available in the PATH +if command -v "$MY_SHELLCHECK" >/dev/null 2>&1; then + # Run your command here + shellcheck "$0" || exit 1 +else + echo "$MY_SHELLCHECK is not installed. Please install it if changes to this script have been made." +fi + +# Begin common dir init, for /tools/scripts +# Resolve this script's absolute path and its directories +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_PATH="${SCRIPT_DIR}/$(basename -- "${BASH_SOURCE[0]}")" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" + +# Normalize to physical paths (no symlinks, no trailing slashes) +# SCRIPT_DIR_P="$(cd -- "$SCRIPT_DIR" && pwd -P)" +REPO_ROOT_P="$(cd -- "$REPO_ROOT" && pwd -P)" +CALLER_CWD_P="$(pwd -P)" # where the user ran the script from + +# Print only if caller's cwd is neither REPO_ROOT nor REPO_ROOT/scripts +case "$CALLER_CWD_P" in + "$REPO_ROOT_P" | "$REPO_ROOT_P"/scripts) + : # silent + ;; + *) + echo "Script paths:" + echo "-- SCRIPT_PATH =$SCRIPT_PATH" + echo "-- SCRIPT_DIR =$SCRIPT_DIR" + echo "-- REPO_ROOT =$REPO_ROOT" + ;; +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)" + +# End common dir init + +# find_stm32_tool: locate STM32CubeProgrammer tools (e.g., STM32_Programmer_CLI, STLinkUpgrade) +# Usage: +# find_stm32_tool STM32_Programmer_CLI # prints full path, returns 0 if found +# find_stm32_tool STLinkUpgrade # finds .exe on WSL/Windows or .jar on macOS/Linux +# find_stm32_tool STM32_Programmer_CLI STLink_CLI # tries each name until one is found +# +# Optional environment override: +# export STM32CUBE_PROGRAMMER_ROOT="/path/to/STM32CubeProgrammer" +# # (either the install root or its bin/ directory) +# +# ---------- Examples ---------- +# Find the CLI on any platform: +# cli_path="$(find_stm32_tool STM32_Programmer_CLI)" || { echo "CLI not found"; exit 1; } +# echo "CLI: $cli_path" + +# Find the STLink upgrader (exe on WSL/Windows, jar on macOS/Linux): +# upg_path="$(find_stm32_tool STLinkUpgrade STLinkUpgrade.jar)" || { echo "Upgrader not found"; exit 1; } +# echo "Upgrader: $upg_path" + +find_stm32_tool() { + if [ "$#" -lt 1 ]; then + echo "Usage: find_stm32_tool [alt_name ...]" >&2 + return 2 + fi + + # Build candidate bin directories (order matters) + _bins=() + + # 1) User override + if [ -n "$STM32CUBE_PROGRAMMER_ROOT" ]; then + if [ -d "$STM32CUBE_PROGRAMMER_ROOT/bin" ]; then + _bins+=("$STM32CUBE_PROGRAMMER_ROOT/bin") + fi + if [ -d "$STM32CUBE_PROGRAMMER_ROOT" ] && { [ -x "$STM32CUBE_PROGRAMMER_ROOT/STM32_Programmer_CLI" ] || [ -x "$STM32CUBE_PROGRAMMER_ROOT/STM32_Programmer_CLI.exe" ]; }; then + _bins+=("$STM32CUBE_PROGRAMMER_ROOT") + fi + fi + + # 2) WSL/Windows (common default) + if [ -d "/mnt/c" ]; then + _bins+=( + "/mnt/c/Program Files/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin" + "/mnt/c/Program Files (x86)/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin" + ) + fi + + # 3) macOS .app bundle paths + _mac_app="/Applications/STMicroelectronics/STM32Cube/STM32CubeProgrammer/STM32CubeProgrammer.app" + if [ -d "$_mac_app" ]; then + # Most recent distributions place binaries here: + _bins+=("$_mac_app/Contents/Resources/bin") + # Some older guides/installers used this: + _bins+=("$_mac_app/Contents/MacOs/bin") + fi + + # 4) Linux / macOS common install locations + _bins+=( + "$HOME/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin" + "/usr/local/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin" + "/opt/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin" + ) + + # Deduplicate while preserving order + _uniq_bins=() + for d in "${_bins[@]}"; do + _seen=0 + for u in "${_uniq_bins[@]}"; do + [ "$u" = "$d" ] && _seen=1 && break + done + [ "$_seen" -eq 0 ] && _uniq_bins+=("$d") + done + + # Try each requested name across all candidate directories. + for name in "$@"; do + for dir in "${_uniq_bins[@]}"; do + [ -d "$dir" ] || continue + + # Candidates to test (with and without .exe) + cand1="$dir/$name" + cand2="$dir/$name.exe" + + # Special-case: STLinkUpgrade may be shipped as a .jar on macOS/Linux + cand3="$dir/${name%.jar}.jar" + + # Prefer native executable if present + if [ -x "$cand1" ]; then + printf "%s\n" "$cand1" + return 0 + fi + if [ -x "$cand2" ]; then + printf "%s\n" "$cand2" + return 0 + fi + # Jar isn't -x by default; accept it if it exists and is readable + if [ -r "$cand3" ] && { [ "${name%.jar}" = "STLinkUpgrade" ] || [ "$name" = "STLinkUpgrade.jar" ]; }; then + printf "%s\n" "$cand3" + return 0 + fi + done + done + + # Not found + return 1 +} + +#--------------------------------------------------------------------------------------------- +# +#--------------------------------------------------------------------------------------------- +if [ $# -gt 0 ]; then + THIS_OPERATION="$1" + + TARGET="$2" + if [ "$TARGET" = "" ]; then + echo "No target specified" + fi + + if [ "$THIS_OPERATION" = "--CLEAN" ]; then + if [ "$TARGET" = "" ]; then + echo "Clean... (build)" + rm -rf ./build + if [ -e ./build ]; then + echo "ERROR: ./build still exists after rm -rf" >&2 + exit 1 + fi + else + echo "Clean... (build-$TARGET)" + rm -rf "./build-$TARGET" + if [ -e "./build-$TARGET" ]; then + echo "ERROR: ./build-$TARGET still exists after rm -rf" >&2 + exit 1 + fi + fi + + # Any other build directories? + # Warn if others remain, but don't fail unless strict is requested + shopt -s nullglob + others=() + for d in build-*; do + # skip generic build dir (if any) and the one we just removed + [ "$d" = "build" ] && continue + [ "$d" = "build-$TARGET" ] && continue + others+=("$d") + done + + if ((${#others[@]})); then + printf 'Note: Found %d other build directory target(s):\n' "${#others[@]}" + printf '%s\n' "${others[@]}" + if [ -n "$WOLFBOOT_CLEAN_STRICT" ]; then + echo "Failing because WOLFBOOT_CLEAN_STRICT is set." + exit 1 + fi + else + echo 'Success: No other build-[target] directories found.' + fi + exit 0 + fi + + if [ "$THIS_OPERATION" = "--target" ]; then + TARGET="$2" + echo "Set target: $TARGET" + fi + + if [ "$THIS_OPERATION" = "--stlink-upgrade" ]; then + echo "ST-Link upgrade!" + CLI="$(find_stm32_tool STLinkUpgrade)" || { echo "CLI not found"; exit 1; } + if [ -f "$CLI" ]; then + echo "Found stlink upgrade tool: $CLI" + else + echo "CLI=$CLI" + echo "STLinkUpgrade.exe not found, exiting" + exit 2 + fi + + # Run STLinkUpgrade.exe + "$CLI" + status=$? + if [ "$status" -eq 0 ]; then + echo "OK: command succeeded" + else + echo "Failed: command exited with status $status" + fi + exit "$status" + fi + + # TODO Move flash operation to cmake + if [ "$THIS_OPERATION" = "--flash" ]; 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 + + WOLFBOOT_BIN="build-$TARGET/test-app/wolfboot_$TARGET.bin" + echo Checking "WOLFBOOT_BIN=$WOLFBOOT_BIN" + if [ ! -f "$WOLFBOOT_BIN" ]; then + echo "Missing: $WOLFBOOT_BIN (build first: cmake --build --preset \"$TARGET\")" + exit 2 + fi + IMAGE_WOLFBOOT=$(wslpath -w "$WOLFBOOT_BIN") + "$CLI" -c port=SWD mode=UR freq=400 -w "$IMAGE_WOLFBOOT" 0x08000000 -v + + SIGNED="build-$TARGET/test-app/image_v1_signed.bin" + echo "Checking SIGNED=$SIGNED" + if [ ! -f "$SIGNED" ]; then + echo "Missing: $SIGNED (try: cmake --build --preset \"$TARGET\" --target test-app)" + exit 2 + fi + + BOOT_ADDR=0x0800A000 # your wolfBoot BOOT address + IMAGE_SIGNED=$(wslpath -w "$SIGNED") + echo "IMAGE_SIGNED=$IMAGE_SIGNED" + + # SWD via ST-LINK (Windows handles the USB) + "$CLI" -c port=SWD mode=UR freq=400 -w "$IMAGE_SIGNED" "$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 + echo "Please specify a target." + echo "" + echo " $0 --CLEAN [your target]" + echo " $0 --target [your target]" + echo " $0 --flash [your target]" + echo "" + cmake -S . -B build --list-presets=configure + exit 1 +fi + +echo "cmake --preset $TARGET" + cmake --preset "$TARGET" + +echo "cmake --build --preset $TARGET -j" + cmake --build --preset "$TARGET" -j + +# Reminder: Manual build +# mkdir -p build +# cd build +# cmake -DWOLFBOOT_TARGET=stm32h7 -DBUILD_TEST_APPS=yes -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x8020000 -DWOLFBOOT_SECTOR_SIZE=0x20000 -DWOLFBOOT_PARTITION_SIZE=0xD0000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80F0000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81C0000 .. +# make From e2c1e146957ae96d509876b0129b9ff706e2c277 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Wed, 19 Nov 2025 08:21:30 -0800 Subject: [PATCH 2/9] Trim unused preset cacheVariables --- CMakePresets.json | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 909104110a..4fd1e660f7 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -71,7 +71,6 @@ "hidden": true, "generator": "Ninja", "cacheVariables": { - "ST_CMSIS_CORE_TAG": "5.9.0" } }, { @@ -115,12 +114,7 @@ ], "cacheVariables": { "WOLFBOOT_TARGET": "stm32c0", - "ST_HAL_TAG": "v1.4.0", - "ST_CMSIS_TAG": "v1.3.0", "ARCH": "ARM", - "DEBUG": "OFF", - "VTOR": "ON", - "CORTEX_M0": "ON", "NO_ASM": "OFF", "NO_MPU": "ON", "EXT_FLASH": "OFF", @@ -128,9 +122,7 @@ "ALLOW_DOWNGRADE": "OFF", "NVM_FLASH_WRITEONCE": "ON", "WOLFBOOT_VERSION": "OFF", - "V": "OFF", "SPMATH": "ON", - "DUALBANK_SWAP": "OFF", "RAM_CODE": "OFF", "WOLFBOOT_PARTITION_SIZE": "0x2000", "WOLFBOOT_SECTOR_SIZE": "0x800", @@ -151,7 +143,6 @@ "cacheVariables": { "WOLFBOOT_TARGET": "stm32f1", "ARCH": "ARM", - "VTOR": "OFF", "SPMATH": "ON", "DISABLE_BACKUP": "OFF", "NVM_FLASH_WRITEONCE": "ON", @@ -175,16 +166,12 @@ "cacheVariables": { "WOLFBOOT_TARGET": "stm32g0", "ARCH": "ARM", - "DEBUG": "OFF", - "VTOR": "ON", - "CORTEX_M0": "ON", "NO_ASM": "OFF", "EXT_FLASH": "OFF", "SPI_FLASH": "OFF", "ALLOW_DOWNGRADE": "OFF", "NVM_FLASH_WRITEONCE": "ON", "WOLFBOOT_VERSION": "OFF", - "V": "OFF", "SPMATH": "ON", "RAM_CODE": "ON", "DUALBANK_SWAP": "OFF", @@ -194,7 +181,6 @@ "WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x08008000", "WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08013000", "WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x0801E000", - "CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake", "BUILD_TEST_APPS": "ON" } }, @@ -208,15 +194,10 @@ ], "generator": "Ninja", "cacheVariables": { - "ST_HAL_TAG": "v1.10.6", - "ST_CMSIS_TAG": "v1.7.4", - "CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake", "WOLFBOOT_TARGET": "stm32h7", "BUILD_TEST_APPS": "yes", "ARCH": "ARM", - "DEBUG": "OFF", "DEBUG_UART": "OFF", - "VTOR": "ON", "NO_ASM": "OFF", "EXT_FLASH": "OFF", "SPI_FLASH": "OFF", @@ -225,10 +206,8 @@ "ALLOW_DOWNGRADE": "OFF", "NVM_FLASH_WRITEONCE": "OFF", "WOLFBOOT_VERSION": "ON", - "V": "OFF", "SPMATH": "ON", "RAM_CODE": "OFF", - "DUALBANK_SWAP": "OFF", "WOLFBOOT_PARTITION_SIZE": "0xD0000", "WOLFBOOT_SECTOR_SIZE": "0x20000", "WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x8020000", @@ -249,30 +228,22 @@ }, "cacheVariables": { "WOLFBOOT_TARGET": "stm32l4", - "WOLFBOOT_DOWNLOADS_CMAKE": "${sourceDir}/cmake/downloads/stm32l4.cmake", - "STM32L4_PART": "STM32L475xx", - "BOARD": "B-L475E-IOT01A", "ARCH": "ARM", - "DEBUG": "OFF", "VTOR": "ON", - "CORTEX_M0": "OFF", "NO_ASM": "OFF", "EXT_FLASH": "OFF", "SPI_FLASH": "OFF", "ALLOW_DOWNGRADE": "OFF", "NVM_FLASH_WRITEONCE": "ON", "WOLFBOOT_VERSION": "OFF", - "V": "OFF", "SPMATH": "ON", "RAM_CODE": "OFF", - "DUALBANK_SWAP": "OFF", "IMAGE_HEADER_SIZE": "256", "WOLFBOOT_SECTOR_SIZE": "0x1000", "WOLFBOOT_PARTITION_SIZE": "0x7A000", "WOLFBOOT_PARTITION_BOOT_ADDRESS": "0x0800A000", "WOLFBOOT_PARTITION_UPDATE_ADDRESS": "0x08084000", "WOLFBOOT_PARTITION_SWAP_ADDRESS": "0x080FE000", - "WOLFTPM": "OFF", "CMAKE_TOOLCHAIN_FILE": "cmake/toolchain_arm-none-eabi.cmake", "BUILD_TEST_APPS": "ON" } From 6341fd11b1bc97da4d6e124ac99ac610c7fd2942 Mon Sep 17 00:00:00 2001 From: "kevin.walker" Date: Wed, 19 Nov 2025 21:41:49 +0000 Subject: [PATCH 3/9] fix: always quote when doing list search --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb325acb71..5ab5265961 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,7 +378,7 @@ if(NOT DEFINED CACHE{WOLFBOOT_TARGET}) CACHE INTERNAL "Target platform") endif() -if(${WOLFBOOT_TARGET} IN_LIST ARM_TARGETS) +if("${WOLFBOOT_TARGET}" IN_LIST ARM_TARGETS) set(ARCH ARM) elseif(WOLFBOOT_TARGET STREQUAL "x86_64_efi") set(ARCH x86_64) From 7d0e735522a6c70e1dcf15aaeafaa1bc16f202a2 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Thu, 20 Nov 2025 17:05:12 -0800 Subject: [PATCH 4/9] doc polish --- IDE/VSCode/install.sh | 4 +- README.md | 191 +---------------- cmake/README.md | 11 +- docs/CMake.md | 340 +++++++++++++++++++++++++++++- docs/Signing.md | 2 +- lib/README.md | 15 ++ tools/scripts/cmake_dot_config.sh | 4 +- 7 files changed, 368 insertions(+), 199 deletions(-) create mode 100644 lib/README.md diff --git a/IDE/VSCode/install.sh b/IDE/VSCode/install.sh index e61b4213bf..c9fbff3bb6 100644 --- a/IDE/VSCode/install.sh +++ b/IDE/VSCode/install.sh @@ -46,11 +46,9 @@ echo "Starting $0 from $(pwd -P)" # End common dir init pwd -exit 0 - - git clone https://github.com/gojimmypi/wolfBoot.git cd wolfBoot +git submodule update --init sudo apt-get update diff --git a/README.md b/README.md index 084040f21b..d95b3af9f8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# wolfBoot +# wolfBoot wolfSSL Secure Bootloader ([Home page](https://www.wolfssl.com/products/wolfboot/), [Manual](https://www.wolfssl.com/documentation/manuals/wolfboot/), [wolfBoot-examples](https://github.com/wolfSSL/wolfBoot-examples)) @@ -41,8 +41,6 @@ The bootloader consists of the following components: ## Requirements -### Linux - Ensure the proper toolchain is installed. See the [docs](./docs/README.md) for platform-specific details. ## Integrating wolfBoot in an existing project @@ -125,192 +123,9 @@ cp config/examples/stm32h7.config .config make keytools make ``` +## CMake -### CMake - Presets - -This section explains how to build wolfBoot using CMake Presets. -Presets let you keep repeatable build settings in a single JSON file ([CMakePresets.json](./CMakePresets.json)) so -you can configure and build with short, memorable commands like: - -``` -cmake --list-presets -cmake --preset stm32l4 -cmake --build --preset stm32l4 -``` - -See the `WOLFBOOT_ROOT`/[config_defaults.cmake](./config_defaults.cmake) file. - -#### Convert existing `.config` to CMake Presets - -The [tools/scripts/config2presets.py](./tools/scripts/config2presets.py) script cam -convert existing [config/examples](./config/examples) to CMake presets. - -For example: - -```python -python3 ./tools/scripts/config2presets.py ./config/examples/stm32h7.config -``` - -#### Tips & Gotchas - -Out-of-source enforced: wolfBoot’s CMakeLists.txt blocks in-source builds; -presets default to `build-${presetName}` anyway. - -Toolchain auto-select: If `WOLFBOOT_TARGET` is not x86_64_efi or sim, -CMAKE_TOOLCHAIN_FILE defaults to `cmake/toolchain_arm-none-eabi.cmake`. - -Windows host tools: When HOST_CC is `cl.exe`, CMakeLists.txt creates a -lightweight `unistd.h` shim and adjusts flags—no manual changes needed. - -`$penv` vs `$env`: Use `$penv{VAR}` in environment to append to the existing -process environment (keeps your PATH). `$env{VAR}` replaces it. - -Visual Studio / VS Code: Both detect presets automatically; -select the preset from the status bar or CMake menu, then build. - -`--fresh`: Re-configure from scratch without deleting the build directory. - -For further details, see the [cmake/README](./cmake/README.md) - -### CMake - Read .config file - -See [cmake/README](./cmake/README.md#build-with-cmake-using-config-files). - -### CMake - Command-line Settings - -To build using CMake, create a `build` directory and run `cmake` with the target platform as well as values for the partition -size and address variables. To build the test-apps, run with `-DBUILD_TEST_APPS=yes`. To use the wolfCrypt-py keytools, run -with `-DPYTHON_KEYTOOLS=yes`. - -For example, to build for the stm32h7 platform: -``` -$ mkdir build -$ cd build -$ cmake -DWOLFBOOT_TARGET=stm32h7 -DBUILD_TEST_APPS=yes -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x8020000 -DWOLFBOOT_SECTOR_SIZE=0x20000 -DWOLFBOOT_PARTITION_SIZE=0xD0000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80F0000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81C0000 .. -$ make -``` - -The output should look something like: -``` -Scanning dependencies of target keystore -[ 2%] Building signing tool -[ 4%] Building keygen tool -[ 7%] Generating keystore.c and signing private key -Keytype: ECC256 -Gen /home/user/wolfBoot/build/wolfboot_signing_private_key.der -Generating key (type: ECC256) -Associated key file: /home/user/wolfBoot/build/wolfboot_signing_private_key.der -Key type : ECC256 -Public key slot: 0 -Done. -[ 7%] Built target keystore -Scanning dependencies of target public_key -[ 9%] Building C object CMakeFiles/public_key.dir/keystore.c.o -[ 11%] Linking C static library libpublic_key.a -[ 14%] Built target public_key -Scanning dependencies of target wolfboothal -[ 16%] Building C object CMakeFiles/wolfboothal.dir/hal/stm32h7.c.o -[ 19%] Linking C static library libwolfboothal.a -[ 19%] Built target wolfboothal -Scanning dependencies of target wolfcrypt -[ 21%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/integer.c.o -[ 23%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/tfm.c.o -[ 26%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/ecc.c.o -[ 28%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/memory.c.o -[ 30%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/wc_port.c.o -[ 33%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/wolfmath.c.o -[ 35%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/hash.c.o -[ 38%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/sha256.c.o -[ 40%] Linking C static library libwolfcrypt.a -[ 40%] Built target wolfcrypt -Scanning dependencies of target wolfboot -[ 42%] Building C object CMakeFiles/wolfboot.dir/src/libwolfboot.c.o -[ 45%] Linking C static library libwolfboot.a -[ 45%] Built target wolfboot -Scanning dependencies of target image -[ 47%] Building C object test-app/CMakeFiles/image.dir/app_stm32h7.c.o -[ 50%] Building C object test-app/CMakeFiles/image.dir/led.c.o -[ 52%] Building C object test-app/CMakeFiles/image.dir/system.c.o -[ 54%] Building C object test-app/CMakeFiles/image.dir/timer.c.o -[ 57%] Building C object test-app/CMakeFiles/image.dir/startup_arm.c.o -[ 59%] Linking C executable image -[ 59%] Built target image -Scanning dependencies of target image_signed -[ 61%] Generating image.bin -[ 64%] Signing image -wolfBoot KeyTools (Compiled C version) -wolfBoot version 10C0000 -Update type: Firmware -Input image: /home/user/wolfBoot/build/test-app/image.bin -Selected cipher: ECC256 -Selected hash : SHA256 -Public key: /home/user/wolfBoot/build/wolfboot_signing_private_key.der -Output image: /home/user/wolfBoot/build/test-app/image_v1_signed.bin -Target partition id : 1 -Calculating SHA256 digest... -Signing the digest... -Output image(s) successfully created. -[ 64%] Built target image_signed -Scanning dependencies of target image_outputs -[ 66%] Generating image.size - text data bss dec hex filename - 5284 108 44 5436 153c /home/user/wolfBoot/build/test-app/image -[ 69%] Built target image_outputs -Scanning dependencies of target wolfboot_stm32h7 -[ 71%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/string.c.o -[ 73%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/image.c.o -[ 76%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/loader.c.o -[ 78%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/boot_arm.c.o -[ 80%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/update_flash.c.o -[ 83%] Linking C executable wolfboot_stm32h7 -[ 83%] Built target wolfboot_stm32h7 -Scanning dependencies of target binAssemble -[ 85%] Generating bin-assemble tool -[ 85%] Built target binAssemble -Scanning dependencies of target image_boot -[ 88%] Generating wolfboot_stm32h7.bin -[ 90%] Signing image -wolfBoot KeyTools (Compiled C version) -wolfBoot version 10C0000 -Update type: Firmware -Input image: /home/user/wolfBoot/build/test-app/image.bin -Selected cipher: ECC256 -Selected hash : SHA256 -Public key: /home/user/wolfBoot/build/wolfboot_signing_private_key.der -Output image: /home/user/wolfBoot/build/test-app/image_v1_signed.bin -Target partition id : 1 -Calculating SHA256 digest... -Signing the digest... -Output image(s) successfully created. -[ 92%] Assembling image factory image -[ 95%] Built target image_boot -Scanning dependencies of target wolfboot_stm32h7_outputs -[ 97%] Generating wolfboot_stm32h7.size - text data bss dec hex filename - 42172 0 76 42248 a508 /home/user/wolfBoot/build/test-app/wolfboot_stm32h7 -[100%] Built target wolfboot_stm32h7_outputs -``` - -Signing and hashing algorithms can be specified with `-DSIGN=` and `-DHASH=`. To view additional -options to configuring wolfBoot, add `-LAH` to your cmake command, along with the partition specifications. -``` -$ cmake -DWOLFBOOT_TARGET=stm32h7 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x8020000 -DWOLFBOOT_SECTOR_SIZE=0x20000 -DWOLFBOOT_PARTITION_SIZE=0xD0000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80F0000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81C0000 -LAH .. -``` - -#### stm32f4 -``` -$ cmake -DWOLFBOOT_TARGET=stm32f4 -DWOLFBOOT_PARTITION_SIZE=0x20000 -DWOLFBOOT_SECTOR_SIZE=0x20000 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x08020000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x08040000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x08060000 .. -``` - -#### stm32u5 -``` -$ cmake -DWOLFBOOT_TARGET=stm32u5 -DBUILD_TEST_APPS=yes -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x08100000 -DWOLFBOOT_SECTOR_SIZE=0x2000 -DWOLFBOOT_PARTITION_SIZE=0x20000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x817F000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81FE000 -DNO_MPU=yes .. -``` - -##### stm32l0 -``` -$ cmake -DWOLFBOOT_TARGET=stm32l0 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x8000 -DWOLFBOOT_SECTOR_SIZE=0x1000 -DWOLFBOOT_PARTITION_SIZE=0x10000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x18000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x28000 -DNVM_FLASH_WRITEONCE=yes .. -``` +See [docs/CMake](./docs/CMake.md) and [cmake includes](./cmake/README.md). ## Troubleshooting diff --git a/cmake/README.md b/cmake/README.md index 7f6ca47c90..f57ba1123a 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -1,8 +1,8 @@ -# wolfBoot Cmake +# wolfBoot CMake Review the [Keystore Docs](../docs/keystore.md) and [Signing Docs](../docs/Signing.md) regarding backup and storage of the generated `src/keystore.c` file. This file -is excluded from source in `.gitignore`). +is excluded from source in `.gitignore`. **Save to a safe place outside of the wolfBoot tree.** @@ -25,7 +25,7 @@ set(FOUND_HAL_BASE false) set(USE_DOT_CONFIG false) ``` -## cmake Directory Overview +## Relevant CMake Files - [`WOLFBOOT_ROOT`/CMakeLists.txt](../CMakeLists.txt) - Top-level CMake entry that configures the wolfBoot build. Used to initialize the project, include cmake/wolfboot.cmake, set options, and define targets. @@ -40,6 +40,8 @@ Centralizes toolchain paths, target names, build directories, and key cache vari Maps Visual Studio configurations (Debug, Release) to existing CMake presets. Controls IntelliSense, environment variables, and the preset shown in the VS CMake toolbar. +## This `cmake` Directory Overview + - [preset-examples/CMakeUserPresets.json.sample](./preset-examples/CMakeUserPresets.json.sample) - Example local overrides for user-specific paths and options. Copy to `CMakeUserPresets.json` in the `WOLFBOOT_ROOT` directory and customize. Not committed. Copy to `WOLFBOOT_ROOT` and remove the `.sample` suffix. - [config_defaults.cmake](./config_defaults.cmake) - Default cache values and feature toggles used when presets or .config do not provide them. @@ -73,7 +75,8 @@ Controls IntelliSense, environment variables, and the preset shown in the VS CMa - [downloads/stm32l4.cmake](./downloads/stm32l4.cmake) - STM32L4 fetch script for HAL and CMSIS. - [`WOLFBOOT_ROOT`/.vs/VSWorkspaceSettings.json](../.vs/VSWorkspaceSettings.json) - Exclusion directories: Visual Studio tries to be "helpful" and open a solution file. This is undesired when opening a directory as a CMake project. ---- + +---- ### Build with cmake using `.config` files diff --git a/docs/CMake.md b/docs/CMake.md index 6f156f8ddd..210499fdab 100644 --- a/docs/CMake.md +++ b/docs/CMake.md @@ -1,3 +1,341 @@ -# wolfBoot CMake +# wolfBoot CMake See the [`WOLFBOOT_ROOT`/cmake/README.md](../cmake/README.md) file. + +### CMake - Presets + +This section explains how to build wolfBoot using CMake Presets. +Presets let you keep repeatable build settings in a single JSON file ([`[WOLFBOOT_ROOT]/CMakePresets.json`](../CMakePresets.json)) so +you can configure and build with short, memorable commands like: + +``` +cmake --list-presets +cmake --preset stm32l4 +cmake --build --preset stm32l4 +``` + +See the `WOLFBOOT_ROOT`/[config_defaults.cmake](./config_defaults.cmake) file. + +#### Convert existing `.config` to CMake Presets + +The [`[WOLFBOOT_ROOT]`/tools/scripts/config2presets.py](../tools/scripts/config2presets.py) script cam +convert existing [config/examples](../config/examples) to CMake presets. + +For example: + +```python +python3 ./tools/scripts/config2presets.py ./config/examples/stm32h7.config +``` + +### Build with cmake using `.config` files + +Presets are preferred instead of `.config`, see below. + +To use `.config` files instead of presets, + +```bash +# cd your [WOLFBOOT_ROOT] + +# Backup current config +mv ./.config ./.config.bak + +# Get an example config +cp ./config/examples/stm32h7.config ./.config + +# Call cmake with -DUSE_DOT_CONFIG=ON +cmake -S . -B build-stm32h7 -DUSE_DOT_CONFIG=ON + +# Sample build +cmake --build build-stm32h7 -j +``` + +The output should look contain text like this: + +```text +-- Found a .config file, will parse +-- Config mode: dot (.config cache) +-- Loading config from: /mnt/c/workspace/wolfBoot-gojimmypi +-- Reading config file: /mnt/c/workspace/wolfBoot-gojimmypi/.config +-- -- Parsing lines from config file... +-- -- Found line: ARCH?=ARM +-- -- Parsed key: ARCH +-- -- Parsed op: ? +-- -- Parsed val: ARM +-- -- Assignment: ARCH=ARM +-- -- Found line: TARGET?=stm32h7 +-- -- Parsed key: TARGET +-- -- Parsed op: ? +-- -- Parsed val: stm32h7 +-- -- Assignment: TARGET=stm32h7 +-- -- Found line: SIGN?=ECC256 +-- -- Parsed key: SIGN +-- -- Parsed op: ? +-- -- Parsed val: ECC256 + ...etc... +``` + +Calling `cmake` with an existing `.config` file will default to dot-config mode. + +```bash +ls .config +cmake -S . -B build-stm32h7 +``` + +Specify additional directories, for example the STM32L4: + +```bash +cmake -S . -B build-stm32l4 -DUSE_DOT_CONFIG=ON \ + -DHAL_DRV="${VG_BASE}/Drivers/STM32L4xx_HAL_Driver" \ + -DHAL_CMSIS_DEV="${VG_BASE}/Drivers/CMSIS/Device/ST/STM32L4xx/Include" \ + -DHAL_CMSIS_CORE="${VG_BASE}/Drivers/CMSIS/Include" \ + -DHAL_TEMPLATE_INC="${VG_BASE}/Drivers/STM32L4xx_HAL_Driver/Inc" + +cmake --build build-stm32l4 -j +``` + +### Build presets + +Each configure preset has a matching build preset with jobs=4, verbose=true, and targets=["all"]. + +Example commands: + +```bash +cmake --preset stm32l4 +cmake --build --preset stm32l4 + +cmake --preset stm32h7 +cmake --build --preset stm32h7 +``` + +### CMake User Presets. + +See the [preset-examples/CMakeUserPresets.json.sample(./preset-examples/CMakeUserPresets.json.sample). +Copy the file to `WOLFBOOT_ROOT` and remove the`.sample` suffix: `CMakeUserPresets.json`. + +It is critically important that none the names of a user preset do not conflict with regular presets. + +For instance, the sample extends and overrides some of the `stm32l4` settings, +using LLVM clang on Windows, and prefixes ALL the names with `my-`: + +```json +{ + "version": 3, + "configurePresets": [ + { + "name": "my-stm32l4", + "displayName": "my STM32L4", + "inherits": [ + "stm32l4" + ], + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-my-stm32l4", + "cacheVariables": { + "ARM_GCC_BIN": "C:/SysGCC/arm-eabi/bin", + "HOST_CC": "C:/Program Files/LLVM/bin/clang.exe" + } + } + ], + "buildPresets": [ + { + "name": "my-stm32l4", + "configurePreset": "my-stm32l4" + } + ] +} +``` + + +From the [docs for CMake Presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html): + +>"Added in version 3.19. +> +>One problem that CMake users often face is sharing settings with other people for common ways to configure +a project. This may be done to support CI builds, or for users who frequently use the same build. CMake +supports two main files, `CMakePresets.json` and `CMakeUserPresets.json`, that allow users to specify common +configure options and share them with others. CMake also supports files included with the include field. +> +>`CMakePresets.json` and` CMakeUserPresets.json` live in the project's root directory. They both have +exactly the same format, and both are optional (though at least one must be present if `--preset` is +specified). `CMakePresets.json` is meant to specify project-wide build details, while `CMakeUserPresets.json` +is meant for developers to specify their own local build details. +> +>CMakePresets.json may be checked into a version control system, and `CMakeUserPresets.json` should NOT be +checked in. For example, if a project is using Git, `CMakePresets.json` may be tracked, and +`CMakeUserPresets.json` should be added to the .gitignore." + +## Troubleshooting + +The wrong toolchain is being used, or a target was not specified: + +``` +Error: no such instruction: `isb' +``` + +### Other log files + +Windows users may find cmake log files in this directory helpful: + +``` +C:\Users\%USERNAME%\AppData\Local\CMakeTools +``` + +#### Tips & Gotchas + +Out-of-source enforced: wolfBoots CMakeLists.txt blocks in-source builds; +presets default to `build-${presetName}` anyway. + +Toolchain auto-select: If `WOLFBOOT_TARGET` is not x86_64_efi or sim, +CMAKE_TOOLCHAIN_FILE defaults to `cmake/toolchain_arm-none-eabi.cmake`. + +Windows host tools: When HOST_CC is `cl.exe`, CMakeLists.txt creates a +lightweight `unistd.h` shim and adjusts flagsno manual changes needed. + +`$penv` vs `$env`: Use `$penv{VAR}` in environment to append to the existing +process environment (keeps your PATH). `$env{VAR}` replaces it. + +Visual Studio / VS Code: Both detect presets automatically; +select the preset from the status bar or CMake menu, then build. + +`--fresh`: Re-configure from scratch without deleting the build directory. + +For further details, see the [cmake/README](../cmake/README.md) + +### CMake - Read .config file + +See [cmake/README](../cmake/README.md#build-with-cmake-using-config-files). + +### CMake - Command-line Settings + +To build using CMake, create a `build` directory and run `cmake` with the target platform as well as values for the partition +size and address variables. To build the test-apps, run with `-DBUILD_TEST_APPS=yes`. To use the wolfCrypt-py keytools, run +with `-DPYTHON_KEYTOOLS=yes`. + +For example, to build for the stm32h7 platform: +``` +$ mkdir build +$ cd build +$ cmake -DWOLFBOOT_TARGET=stm32h7 -DBUILD_TEST_APPS=yes -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x8020000 -DWOLFBOOT_SECTOR_SIZE=0x20000 -DWOLFBOOT_PARTITION_SIZE=0xD0000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80F0000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81C0000 .. +$ make +``` + +The output should look something like: +``` +Scanning dependencies of target keystore +[ 2%] Building signing tool +[ 4%] Building keygen tool +[ 7%] Generating keystore.c and signing private key +Keytype: ECC256 +Gen /home/user/wolfBoot/build/wolfboot_signing_private_key.der +Generating key (type: ECC256) +Associated key file: /home/user/wolfBoot/build/wolfboot_signing_private_key.der +Key type : ECC256 +Public key slot: 0 +Done. +[ 7%] Built target keystore +Scanning dependencies of target public_key +[ 9%] Building C object CMakeFiles/public_key.dir/keystore.c.o +[ 11%] Linking C static library libpublic_key.a +[ 14%] Built target public_key +Scanning dependencies of target wolfboothal +[ 16%] Building C object CMakeFiles/wolfboothal.dir/hal/stm32h7.c.o +[ 19%] Linking C static library libwolfboothal.a +[ 19%] Built target wolfboothal +Scanning dependencies of target wolfcrypt +[ 21%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/integer.c.o +[ 23%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/tfm.c.o +[ 26%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/ecc.c.o +[ 28%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/memory.c.o +[ 30%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/wc_port.c.o +[ 33%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/wolfmath.c.o +[ 35%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/hash.c.o +[ 38%] Building C object lib/CMakeFiles/wolfcrypt.dir/wolfssl/wolfcrypt/src/sha256.c.o +[ 40%] Linking C static library libwolfcrypt.a +[ 40%] Built target wolfcrypt +Scanning dependencies of target wolfboot +[ 42%] Building C object CMakeFiles/wolfboot.dir/src/libwolfboot.c.o +[ 45%] Linking C static library libwolfboot.a +[ 45%] Built target wolfboot +Scanning dependencies of target image +[ 47%] Building C object test-app/CMakeFiles/image.dir/app_stm32h7.c.o +[ 50%] Building C object test-app/CMakeFiles/image.dir/led.c.o +[ 52%] Building C object test-app/CMakeFiles/image.dir/system.c.o +[ 54%] Building C object test-app/CMakeFiles/image.dir/timer.c.o +[ 57%] Building C object test-app/CMakeFiles/image.dir/startup_arm.c.o +[ 59%] Linking C executable image +[ 59%] Built target image +Scanning dependencies of target image_signed +[ 61%] Generating image.bin +[ 64%] Signing image +wolfBoot KeyTools (Compiled C version) +wolfBoot version 10C0000 +Update type: Firmware +Input image: /home/user/wolfBoot/build/test-app/image.bin +Selected cipher: ECC256 +Selected hash : SHA256 +Public key: /home/user/wolfBoot/build/wolfboot_signing_private_key.der +Output image: /home/user/wolfBoot/build/test-app/image_v1_signed.bin +Target partition id : 1 +Calculating SHA256 digest... +Signing the digest... +Output image(s) successfully created. +[ 64%] Built target image_signed +Scanning dependencies of target image_outputs +[ 66%] Generating image.size + text data bss dec hex filename + 5284 108 44 5436 153c /home/user/wolfBoot/build/test-app/image +[ 69%] Built target image_outputs +Scanning dependencies of target wolfboot_stm32h7 +[ 71%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/string.c.o +[ 73%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/image.c.o +[ 76%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/loader.c.o +[ 78%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/boot_arm.c.o +[ 80%] Building C object test-app/CMakeFiles/wolfboot_stm32h7.dir/__/src/update_flash.c.o +[ 83%] Linking C executable wolfboot_stm32h7 +[ 83%] Built target wolfboot_stm32h7 +Scanning dependencies of target binAssemble +[ 85%] Generating bin-assemble tool +[ 85%] Built target binAssemble +Scanning dependencies of target image_boot +[ 88%] Generating wolfboot_stm32h7.bin +[ 90%] Signing image +wolfBoot KeyTools (Compiled C version) +wolfBoot version 10C0000 +Update type: Firmware +Input image: /home/user/wolfBoot/build/test-app/image.bin +Selected cipher: ECC256 +Selected hash : SHA256 +Public key: /home/user/wolfBoot/build/wolfboot_signing_private_key.der +Output image: /home/user/wolfBoot/build/test-app/image_v1_signed.bin +Target partition id : 1 +Calculating SHA256 digest... +Signing the digest... +Output image(s) successfully created. +[ 92%] Assembling image factory image +[ 95%] Built target image_boot +Scanning dependencies of target wolfboot_stm32h7_outputs +[ 97%] Generating wolfboot_stm32h7.size + text data bss dec hex filename + 42172 0 76 42248 a508 /home/user/wolfBoot/build/test-app/wolfboot_stm32h7 +[100%] Built target wolfboot_stm32h7_outputs +``` + +Signing and hashing algorithms can be specified with `-DSIGN=` and `-DHASH=`. To view additional +options to configuring wolfBoot, add `-LAH` to your cmake command, along with the partition specifications. +``` +$ cmake -DWOLFBOOT_TARGET=stm32h7 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x8020000 -DWOLFBOOT_SECTOR_SIZE=0x20000 -DWOLFBOOT_PARTITION_SIZE=0xD0000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x80F0000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81C0000 -LAH .. +``` + +#### stm32f4 +``` +$ cmake -DWOLFBOOT_TARGET=stm32f4 -DWOLFBOOT_PARTITION_SIZE=0x20000 -DWOLFBOOT_SECTOR_SIZE=0x20000 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x08020000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x08040000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x08060000 .. +``` + +#### stm32u5 +``` +$ cmake -DWOLFBOOT_TARGET=stm32u5 -DBUILD_TEST_APPS=yes -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x08100000 -DWOLFBOOT_SECTOR_SIZE=0x2000 -DWOLFBOOT_PARTITION_SIZE=0x20000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x817F000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x81FE000 -DNO_MPU=yes .. +``` + +##### stm32l0 +``` +$ cmake -DWOLFBOOT_TARGET=stm32l0 -DWOLFBOOT_PARTITION_BOOT_ADDRESS=0x8000 -DWOLFBOOT_SECTOR_SIZE=0x1000 -DWOLFBOOT_PARTITION_SIZE=0x10000 -DWOLFBOOT_PARTITION_UPDATE_ADDRESS=0x18000 -DWOLFBOOT_PARTITION_SWAP_ADDRESS=0x28000 -DNVM_FLASH_WRITEONCE=yes .. +``` diff --git a/docs/Signing.md b/docs/Signing.md index 465924066b..d06e43418d 100644 --- a/docs/Signing.md +++ b/docs/Signing.md @@ -179,7 +179,7 @@ is provided: `BASE_SIGNED_IMG.BIN` and the new image signed starting from `IMAGE.BIN`. The result is stored in a file ending in `_signed_diff.bin`. -The compression scheme used is Bentley–McIlroy. +The compression scheme used is Bentley-McIlroy. Options: * `--no-base-sha` : Avoid adding the sha of the base image to the manifest header. diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000000..ec85e20f72 --- /dev/null +++ b/lib/README.md @@ -0,0 +1,15 @@ +# lib + +Submodules from other repositories: + +- wolfHSM +- wolfPKCS11 +- wolfssl +- wolfTPM + +If you cloned wolfBoot from GitHub (rather than using a release package), you'll need to initialize and update the git submodules first: + +``` +git submodule update --init +``` + diff --git a/tools/scripts/cmake_dot_config.sh b/tools/scripts/cmake_dot_config.sh index 28a106698a..c84bd46128 100644 --- a/tools/scripts/cmake_dot_config.sh +++ b/tools/scripts/cmake_dot_config.sh @@ -5,8 +5,8 @@ # Example for using cmake with .config # # Reminder for WSL: -# git update-index --chmod=+x wolfboot_cmake_full_build.sh -# git commit -m "Make wolfboot_cmake_full_build.sh executable" +# git update-index --chmod=+x cmake_dot_config.sh +# git commit -m "Make cmake_dot_config.sh executable" # git push # Specify the executable shell checker you want to use: From 8b91362761845dc1c1910f76469e4e0623a031aa Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Thu, 20 Nov 2025 17:39:55 -0800 Subject: [PATCH 5/9] Additional STM32 clarificaitons --- docs/STM32.md | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/STM32.md b/docs/STM32.md index 6f169f1067..b5ff24c636 100644 --- a/docs/STM32.md +++ b/docs/STM32.md @@ -9,8 +9,8 @@ sudo apt install -y build-essential gcc-arm-none-eabi binutils-arm-none-eabi arm-none-eabi-gcc --version # should print the version ``` -The device manufacturer toolchain _also_ needs to be installed. For example without the [STM32CubeIDE Software](https://www.st.com/en/development-tools/stm32cubeide.html), -errors like this will otherwise be encountered: +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 @@ -19,27 +19,52 @@ hal/stm32l4.c:24:10: fatal error: stm32l4xx_hal.h: No such file or directory | ^~~~~~~~~~~~~~~~~ ``` +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 +``` + -## OR ## +### CMake -# use cmake via wolfbuild.sh script: +``` +## 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 +## VS Code Windows users may need one of these: From 1ad66e9a6b20af9acd6013b5eb3bb9e86a090127 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Fri, 21 Nov 2025 17:54:14 -0800 Subject: [PATCH 6/9] Improve docs, add targets and tests per https://github.com/wolfSSL/wolfBoot/pull/598#pullrequestreview-3492319645 --- .../workflows/test-build-cmake-dot-config.yml | 80 ++- .github/workflows/test-build-cmake-mac.yml | 17 +- .../workflows/test-build-cmake-presets.yml | 19 +- .github/workflows/test-build-cmake-script.yml | 48 +- .../workflows/test-build-cmake-windows.yml | 17 +- CMakeLists.txt | 97 +++- CMakePresets.json | 428 ++++++++++++-- IDE/VSCode/README.md | 28 +- IDE/VSCode/install.sh | 3 +- config/examples/stm32g0.config | 2 +- docs/PQ.md | 2 +- docs/README.md | 2 +- docs/STM32.md | 148 ----- docs/Signing.md | 2 + tools/keytools/README.md | 58 +- tools/scripts/cmake_dot_config.sh | 28 +- tools/scripts/config2presets.py | 520 ++++++++++++++++-- tools/scripts/wolfboot_cmake_full_build.sh | 37 ++ 18 files changed, 1222 insertions(+), 314 deletions(-) delete mode 100644 docs/STM32.md diff --git a/.github/workflows/test-build-cmake-dot-config.yml b/.github/workflows/test-build-cmake-dot-config.yml index d34758d4f0..31a288bff3 100644 --- a/.github/workflows/test-build-cmake-dot-config.yml +++ b/.github/workflows/test-build-cmake-dot-config.yml @@ -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 "Target: ${TARGET}" + echo "Build dir: ${BUILD_DIR}" + echo "Saving output to ${LOG_FILE}" + + CONFIG_SRC="./config/examples/${{ matrix.target }}" + + echo "Fetch ${TARGET} example .config (source: ${CONFIG_SRC})" + if [ ! -f "${CONFIG_SRC}" ]; then + echo "Missing config file: ${CONFIG_SRC}" >&2 + exit 1 + fi + + cp "${CONFIG_SRC}" ./.config + ls .config + cat .config echo "" echo "Clean" - rm -rf ./build-stm32h7 + rm -rf "./${BUILD_DIR}" # 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" + 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" + if grep -q -- "${KEYWORD}" "${LOG_FILE}"; then + echo "Keyword found: ${KEYWORD}" else - echo "Keyword not found: $KEYWORD" >&2 + echo "Keyword not found: ${KEYWORD}" >&2 exit 1 fi - # Sample build - cmake --build build-stm32h7 --parallel 8 + # 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 diff --git a/.github/workflows/test-build-cmake-mac.yml b/.github/workflows/test-build-cmake-mac.yml index 601692d5fb..babe776195 100644 --- a/.github/workflows/test-build-cmake-mac.yml +++ b/.github/workflows/test-build-cmake-mac.yml @@ -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 diff --git a/.github/workflows/test-build-cmake-presets.yml b/.github/workflows/test-build-cmake-presets.yml index a0be0af3bd..964a073844 100644 --- a/.github/workflows/test-build-cmake-presets.yml +++ b/.github/workflows/test-build-cmake-presets.yml @@ -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' diff --git a/.github/workflows/test-build-cmake-script.yml b/.github/workflows/test-build-cmake-script.yml index 9a19ba1816..30278aaa5f 100644 --- a/.github/workflows/test-build-cmake-script.yml +++ b/.github/workflows/test-build-cmake-script.yml @@ -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 }}" diff --git a/.github/workflows/test-build-cmake-windows.yml b/.github/workflows/test-build-cmake-windows.yml index 9eab7b6250..1d55333cb2 100644 --- a/.github/workflows/test-build-cmake-windows.yml +++ b/.github/workflows/test-build-cmake-windows.yml @@ -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. diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ab5265961..02c35497b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 - $<$:/Umin> - $<$:/Umax> - $<$:/USIGN> - $<$:/UHASH> - $<$:/Zc:preprocessor> + $<$:/Umin> + $<$:/Umax> + $<$:/USIGN> + $<$:/UHASH> + $<$:/Zc:preprocessor> ) - endif() +endif() # TARGET ${WOLFSSL_TGT} if(BUILD_TEST_APPS OR BUILD_IMAGE) message(STATUS "Building wolfBoot image") diff --git a/CMakePresets.json b/CMakePresets.json index 4fd1e660f7..796b0f9312 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -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", diff --git a/IDE/VSCode/README.md b/IDE/VSCode/README.md index c0442319ce..f955fc0a04 100644 --- a/IDE/VSCode/README.md +++ b/IDE/VSCode/README.md @@ -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 diff --git a/IDE/VSCode/install.sh b/IDE/VSCode/install.sh index c9fbff3bb6..9b54408241 100644 --- a/IDE/VSCode/install.sh +++ b/IDE/VSCode/install.sh @@ -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 diff --git a/config/examples/stm32g0.config b/config/examples/stm32g0.config index 8d4f953e68..7e99b28486 100644 --- a/config/examples/stm32g0.config +++ b/config/examples/stm32g0.config @@ -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 diff --git a/docs/PQ.md b/docs/PQ.md index 346a5779dd..ab1c54ab44 100644 --- a/docs/PQ.md +++ b/docs/PQ.md @@ -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 diff --git a/docs/README.md b/docs/README.md index 3ecd13c5e6..758e556d25 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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/). diff --git a/docs/STM32.md b/docs/STM32.md deleted file mode 100644 index b5ff24c636..0000000000 --- a/docs/STM32.md +++ /dev/null @@ -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 ` -* Build: `cmake --build --preset ` - -```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" - } - ] -} -``` diff --git a/docs/Signing.md b/docs/Signing.md index d06e43418d..5c27818908 100644 --- a/docs/Signing.md +++ b/docs/Signing.md @@ -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. diff --git a/tools/keytools/README.md b/tools/keytools/README.md index cee4e06a0d..87ad18bd16 100644 --- a/tools/keytools/README.md +++ b/tools/keytools/README.md @@ -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 devices OTP/NVM keystore. No signing, no encryptionjust 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. diff --git a/tools/scripts/cmake_dot_config.sh b/tools/scripts/cmake_dot_config.sh index c84bd46128..ea249fbd78 100644 --- a/tools/scripts/cmake_dot_config.sh +++ b/tools/scripts/cmake_dot_config.sh @@ -22,6 +22,16 @@ fi set -euo pipefail +# Require a target argument, e.g. stm32h7 +TARGET="${1-}" +if [ -z "$TARGET" ]; then + echo "Usage: $0 " >&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 - diff --git a/tools/scripts/config2presets.py b/tools/scripts/config2presets.py index 76a2059dba..442a936502 100644 --- a/tools/scripts/config2presets.py +++ b/tools/scripts/config2presets.py @@ -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 @@ 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 ' 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})" - - 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"]), - ]) + display_name = args.display_name or f"{target}" + + # 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() diff --git a/tools/scripts/wolfboot_cmake_full_build.sh b/tools/scripts/wolfboot_cmake_full_build.sh index 66c1b7051c..ffbf0b800b 100644 --- a/tools/scripts/wolfboot_cmake_full_build.sh +++ b/tools/scripts/wolfboot_cmake_full_build.sh @@ -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 From 4474cf8337861f35aca2ad7275c1f475ad3a0569 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Sat, 22 Nov 2025 10:40:55 -0800 Subject: [PATCH 7/9] Disable no config sim test. --- .github/workflows/test-build-cmake-presets.yml | 3 +-- .github/workflows/test-build-cmake-script.yml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-build-cmake-presets.yml b/.github/workflows/test-build-cmake-presets.yml index 964a073844..4381964734 100644 --- a/.github/workflows/test-build-cmake-presets.yml +++ b/.github/workflows/test-build-cmake-presets.yml @@ -3,7 +3,6 @@ name: WolfBoot CMake Presets Build on: push: branches: [ 'master', 'main', 'release/**' ] - branches: [ '*' ] pull_request: branches: [ "*" ] @@ -23,7 +22,7 @@ jobs: fail-fast: false matrix: target: - - sim + # - sim # - imx-rt # Disabled, requires NXP SDK - stm32c0 - stm32f1 diff --git a/.github/workflows/test-build-cmake-script.yml b/.github/workflows/test-build-cmake-script.yml index 30278aaa5f..dfe34ab5d3 100644 --- a/.github/workflows/test-build-cmake-script.yml +++ b/.github/workflows/test-build-cmake-script.yml @@ -19,7 +19,7 @@ jobs: fail-fast: false matrix: target: - - "~No config (wolfBoot sim)" + # - "~No config (wolfBoot sim)" # - imx-rt # Disabled, requires NXP SDK - stm32c0 - stm32f1 From 079fb006aba2546dd354cf4b1d9d82d8fab3c7d6 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Mon, 24 Nov 2025 13:04:06 -0800 Subject: [PATCH 8/9] Minor docs update, code review changes, script modifications. --- CMakeLists.txt | 20 +++--- docs/CMake.md | 10 ++- tools/keytools/README.md | 16 +++-- tools/scripts/cmake_test.bat | 108 ++++++++++++++++++++++++++++++-- tools/scripts/config2presets.py | 13 ++++ 5 files changed, 143 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02c35497b0..971bc7f07f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,17 @@ message(STATUS "Begin [WOLFBOOT_ROOT]/CmakeLists.txt") +#--------------------------------------------------------------------------------------------- +# First, ensure no in-source build occurs. +#--------------------------------------------------------------------------------------------- +if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") + message(FATAL_ERROR + "In-source builds are not allowed for wolfBoot.\ + Run cmake from a separate directory from where CMakeLists.txt lives.\ + Clean up any stray cache or build directories and try again. \ + See [WOLFBOOT_ROOT]/docs/CMake.md for additional details.") +endif() + message(STATUS "wolfBoot target: ${WOLFBOOT_TARGET}") message(STATUS "CMake version: ${CMAKE_VERSION}") message(STATUS "Generator: ${CMAKE_GENERATOR}") @@ -46,14 +57,6 @@ include(cmake/config_defaults.cmake) #--------------------------------------------------------------------------------------------- # Initial environment checks #--------------------------------------------------------------------------------------------- -if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") - message( - FATAL_ERROR - "In-source builds are not allowed for wolfBoot.\ - Run cmake from a separate directory from where CMakeLists.txt lives.\ - NOTE: cmake will now create CMakeCache.txt and CMakeFiles/*.\ - You must delete them, or cmake will refuse to work.") -endif() # This must appear before project(wolfBoot) if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) @@ -66,6 +69,7 @@ if(NOT DEFINED CMAKE_TOOLCHAIN_FILE) endif() endif() + if(NOT DEFINED PREFERRED_HOST_CC_NAME_LIST OR PREFERRED_HOST_CC_NAME_LIST STREQUAL "") # set(PREFERRED_HOST_CC_NAME_LIST gcc clang cl) if(CMAKE_HOST_WIN32) diff --git a/docs/CMake.md b/docs/CMake.md index 210499fdab..94609efd67 100644 --- a/docs/CMake.md +++ b/docs/CMake.md @@ -2,6 +2,12 @@ See the [`WOLFBOOT_ROOT`/cmake/README.md](../cmake/README.md) file. +## Important: No in-source builds. + +One of the first checks in the `[WOLFBOOT_ROOT]/CMakeLists.txt` is whether `CMAKE_SOURCE_DIR` == `CMAKE_BINARY_DIR`. +In-source builds are not supported. The provided wolfSSL presets will typically prevent this. +Beware when integrating with existing projects or creating custom presets. + ### CMake - Presets This section explains how to build wolfBoot using CMake Presets. @@ -181,14 +187,14 @@ C:\Users\%USERNAME%\AppData\Local\CMakeTools #### Tips & Gotchas -Out-of-source enforced: wolfBoots CMakeLists.txt blocks in-source builds; +Out-of-source enforced: wolfBoot's CMakeLists.txt blocks in-source builds; presets default to `build-${presetName}` anyway. Toolchain auto-select: If `WOLFBOOT_TARGET` is not x86_64_efi or sim, CMAKE_TOOLCHAIN_FILE defaults to `cmake/toolchain_arm-none-eabi.cmake`. Windows host tools: When HOST_CC is `cl.exe`, CMakeLists.txt creates a -lightweight `unistd.h` shim and adjusts flagsno manual changes needed. +lightweight `unistd.h` shim and adjusts flags-no manual changes needed. `$penv` vs `$env`: Use `$penv{VAR}` in environment to append to the existing process environment (keeps your PATH). `$env{VAR}` replaces it. diff --git a/tools/keytools/README.md b/tools/keytools/README.md index 87ad18bd16..5fabbcc810 100644 --- a/tools/keytools/README.md +++ b/tools/keytools/README.md @@ -39,6 +39,13 @@ make wolfboot_signing_private_key.der SIGN=ED25519 ./tools/keytools/keygen --ed25519 -g wolfboot_signing_private_key.der ``` +Note the above example is a basic case where a single key is generated. +The tool supports multiple keys both with `[-g privkey]` and `[-i pubkey]` parameters. + +See the local docs [docs/keystore.md](../../docs/keystore.md) +and the [wolfBoot Keystore section of the manual](https://www.wolfssl.com/documentation/manuals/wolfboot/appendix04.html) +for additional details. + ## Debugging and Development ### `DEBUG_SIGNTOOL` @@ -48,12 +55,3 @@ Enables additional diagnostic messages that may be useful during development and ### `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. diff --git a/tools/scripts/cmake_test.bat b/tools/scripts/cmake_test.bat index dcc2487265..482986b4fa 100644 --- a/tools/scripts/cmake_test.bat +++ b/tools/scripts/cmake_test.bat @@ -6,9 +6,104 @@ :: This test manually sets paths to cmake and include files (also assumes VS 2022 is installed, but can be any suitable path) cls -set "Path=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\bin\HostX86\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\VCPackages;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\bin\Roslyn;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\;C:\Program Files (x86)\HTML Help Workshop;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Team Tools\DiagnosticsHub\Collector;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\CodeCoverage.Console;C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\\x86;C:\Program Files (x86)\Windows Kits\10\bin\\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\\MSBuild\Current\Bin\amd64;C:\Windows\Microsoft.NET\Framework\v4.0.30319;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Git\cmd;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-15.2.0_20250920\riscv32-esp-elf\bin;C:\SysGCC\esp32-master\tools\xtensa-esp-elf\esp-15.2.0_20250920\xtensa-esp-elf\bin;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Git\cmd;C:\Users\gojimmypi\AppData\Local\Microsoft\WindowsApps;C:\Users\gojimmypi\AppData\Local\Programs\Microsoft VS Code\bin;C:\ST\STM32CubeIDE_1.14.1\STM32CubeIDE\plugins\com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.win32_2.1.100.202311100844\tools\bin;C:\Program Files\Git\usr\bin\;C:\Users\gojimmypi\.dotnet\tools;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-13.2.0_20240530\riscv32-esp-elf\bin;C:\Users\gojimmypi\AppData\Local\Microsoft\WinGet\Packages\Ninja-build.Ninja_Microsoft.Winget.Source_8wekyb3d8bbwe;;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\Linux\bin\ConnectionManagerExe" -set "INCLUDE=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\VS\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\um;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\shared;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\winrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um" -set "LIB=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\lib\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\lib\x86;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x86;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\ucrt\x86;C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86" +:: Optionally hard code your paths like this: +:: set "Path=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\bin\HostX86\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\VCPackages;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\bin\Roslyn;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\;C:\Program Files (x86)\HTML Help Workshop;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Team Tools\DiagnosticsHub\Collector;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\Microsoft\CodeCoverage.Console;C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\\x86;C:\Program Files (x86)\Windows Kits\10\bin\\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\\MSBuild\Current\Bin\amd64;C:\Windows\Microsoft.NET\Framework\v4.0.30319;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Git\cmd;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-15.2.0_20250920\riscv32-esp-elf\bin;C:\SysGCC\esp32-master\tools\xtensa-esp-elf\esp-15.2.0_20250920\xtensa-esp-elf\bin;C:\Program Files (x86)\VMware\VMware Workstation\bin\;C:\Program Files\Microsoft\jdk-11.0.16.101-hotspot\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\dotnet\;C:\Program Files\Git\cmd;C:\Users\gojimmypi\AppData\Local\Microsoft\WindowsApps;C:\Users\gojimmypi\AppData\Local\Programs\Microsoft VS Code\bin;C:\ST\STM32CubeIDE_1.14.1\STM32CubeIDE\plugins\com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.win32_2.1.100.202311100844\tools\bin;C:\Program Files\Git\usr\bin\;C:\Users\gojimmypi\.dotnet\tools;C:\SysGCC\esp32-master\tools\riscv32-esp-elf\esp-13.2.0_20240530\riscv32-esp-elf\bin;C:\Users\gojimmypi\AppData\Local\Microsoft\WinGet\Packages\Ninja-build.Ninja_Microsoft.Winget.Source_8wekyb3d8bbwe;;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\VC\Linux\bin\ConnectionManagerExe" +:: set "INCLUDE=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\include;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\VS\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\um;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\shared;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\winrt;C:\Program Files (x86)\Windows Kits\10\\include\10.0.26100.0\\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um" +:: set "LIB=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\ATLMFC\lib\x86;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\lib\x86;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x86;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\ucrt\x86;C:\Program Files (x86)\Windows Kits\10\\lib\10.0.26100.0\\um\x86" + +@echo off +setlocal + +echo [INFO] Checking Visual Studio / MSVC environment... + +REM ------------------------------------------------------------------- +REM 1) Check whether Visual Studio is already on PATH +REM ------------------------------------------------------------------- +echo %PATH% | findstr /I "Microsoft Visual Studio" >nul +if errorlevel 1 ( + echo [WARN] Visual Studio not obviously found in PATH. + echo [WARN] This test is expected to run from a Visual Studio Developer Command Prompt. +) else ( + echo [INFO] Visual Studio paths detected in PATH. +) + +REM ------------------------------------------------------------------- +REM 2) Check VCToolsInstallDir +REM ------------------------------------------------------------------- +if "%VCToolsInstallDir%"=="" ( + echo [WARN] VCToolsInstallDir is not defined. + echo [WARN] You may not be running from a proper Developer Command Prompt. +) else ( + echo [INFO] VCToolsInstallDir = "%VCToolsInstallDir%" +) + +REM ------------------------------------------------------------------- +REM 3) Check INCLUDE +REM ------------------------------------------------------------------- +if "%INCLUDE%"=="" goto NO_INCLUDE + +echo %INCLUDE% | findstr /I "VC\\Tools\\MSVC\\" >nul +if errorlevel 1 goto INCLUDE_WARN + +echo [INFO] INCLUDE contains VC\Tools\MSVC\ (looks OK). +goto AFTER_INCLUDE + +:NO_INCLUDE +echo [ERROR] INCLUDE is not defined. +echo [ERROR] Please run this test from a Visual Studio Developer Command Prompt. +set VS_ENV_ERROR=1 +goto AFTER_INCLUDE + +:INCLUDE_WARN +echo [WARN] INCLUDE does not contain "VC\Tools\MSVC\". +echo [WARN] Current INCLUDE is: +echo %INCLUDE% +set VS_ENV_WARN=1 + +:AFTER_INCLUDE + +REM ------------------------------------------------------------------- +REM 4) Check LIB +REM ------------------------------------------------------------------- +if "%LIB%"=="" goto NO_LIB + +echo %LIB% | findstr /I "VC\\Tools\\MSVC\\" >nul +if errorlevel 1 goto LIB_WARN + +echo [INFO] LIB contains VC\Tools\MSVC\ (looks OK). +goto AFTER_LIB + +:NO_LIB +echo [ERROR] LIB is not defined. +echo [ERROR] Please run this test from a Visual Studio Developer Command Prompt. +set VS_ENV_ERROR=1 +goto AFTER_LIB + +:LIB_WARN +echo [WARN] LIB does not contain "VC\Tools\MSVC\". +echo [WARN] Current LIB is: +echo %LIB% +set VS_ENV_WARN=1 + +:AFTER_LIB + +REM ------------------------------------------------------------------- +REM 5) Decide exit code (for CTest) +REM ------------------------------------------------------------------- +if defined VS_ENV_ERROR ( + echo [ERROR] Visual Studio environment is incomplete. Failing test. + endlocal & exit /b 1 +) + +if defined VS_ENV_WARN ( + echo [WARN] Visual Studio environment has potential issues, but continuing. + endlocal +) + +echo [INFO] Visual Studio environment looks good. +endlocal + +exit /b 0 :: We start in /tools/scripts, but build two directories up: from wolfBoot root @@ -49,6 +144,10 @@ echo Starting %~nx0 from %CD% :: End common start directory detection +::------------------------------------------------------------------------------------ +:: CMake test +::------------------------------------------------------------------------------------ + :: Is CMake installed? where cmake >nul 2>&1 if errorlevel 1 ( @@ -58,12 +157,11 @@ if errorlevel 1 ( ) - rmdir /s /q build-stm32l4 cmake --preset stm32l4 - +:: Optional parallel build specification: :: cmake --build --preset stm32l4 --parallel 4 -v cmake --build --preset stm32l4 diff --git a/tools/scripts/config2presets.py b/tools/scripts/config2presets.py index 442a936502..2a705a38d3 100644 --- a/tools/scripts/config2presets.py +++ b/tools/scripts/config2presets.py @@ -396,6 +396,19 @@ def run_cmake_and_report_unused(preset_name: str, repo_root: Path): combined += "\n" combined += proc.stderr + # If CMake failed, show the full output first so the error is visible. + if proc.returncode != 0: + print("") + print("CMake configure for preset '{}' failed with exit code {}.".format( + preset_name, proc.returncode + )) + print("Full CMake output follows:") + print("==============================================") + print("============= BEGIN CMAKE OUTPUT =============") + print(combined) + print("============= END CMAKE OUTPUT =============") + print("==============================================") + unused = extract_unused_vars(combined) if unused: From f202980d3df243ae14fc0dc5762c2537d291376b Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Mon, 24 Nov 2025 13:06:35 -0800 Subject: [PATCH 9/9] Revert in-source build testing --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 971bc7f07f..210bedf49c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ message(STATUS "Begin [WOLFBOOT_ROOT]/CmakeLists.txt") #--------------------------------------------------------------------------------------------- # First, ensure no in-source build occurs. #--------------------------------------------------------------------------------------------- -if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") +if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") message(FATAL_ERROR "In-source builds are not allowed for wolfBoot.\ Run cmake from a separate directory from where CMakeLists.txt lives.\