diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..c38f7b7d4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true + +[*.md] +charset = utf-8-bom +end_of_line = lf +insert_final_newline = true 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 000000000..7bf30ae8c --- /dev/null +++ b/.github/workflows/test-build-cmake-dot-config.yml @@ -0,0 +1,102 @@ +name: wolfboot CMake (.config) +on: + push: + branches: [ '*' ] + 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 -j diff --git a/.github/workflows/test-build-cmake-mac.yml b/.github/workflows/test-build-cmake-mac.yml new file mode 100644 index 000000000..989cfc355 --- /dev/null +++ b/.github/workflows/test-build-cmake-mac.yml @@ -0,0 +1,96 @@ +name: WolfBoot CMake Build (macOS) + +on: + push: + branches: [ "*" ] + 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-script.yml b/.github/workflows/test-build-cmake-script.yml new file mode 100644 index 000000000..191d4ff24 --- /dev/null +++ b/.github/workflows/test-build-cmake-script.yml @@ -0,0 +1,76 @@ +name: wolfboot CMake Script +on: + push: + branches: [ '*' ] + 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 + + ./tools/scripts/wolfboot_build.sh --CLEAN "stm32l4" + ./tools/scripts/wolfboot_build.sh --target "stm32l4" + + ./tools/scripts/wolfboot_build.sh --CLEAN "stm32g0" + ./tools/scripts/wolfboot_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 000000000..3752fa1a5 --- /dev/null +++ b/.github/workflows/test-build-cmake-windows.yml @@ -0,0 +1,117 @@ +name: WolfBoot CMake Build (Windows) + +on: + push: + branches: [ "*" ] + pull_request: + branches: [ "*" ] + +permissions: + contents: read + +jobs: + windows-cmake: + name: Build on Windows + runs-on: windows-latest + 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 + - uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a + with: + egress-policy: block + allowed-endpoints: > + developer.arm.com, + armkeil.blob.core.windows.net, + github.com, objects.githubusercontent.com, api.github.com + + # 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: bash + 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):" + cmd.exe /c "\"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe\" -latest -products * -requires Microsoft.Component.MSBuild -property installationVersion" + + - name: List Presets + shell: bash + run: | + # Check available presets in CMakePresets.json + + cmake -S . -B build-list --list-presets=configure + + - name: Configure Preset "${{ matrix.target }}" + shell: bash + run: | + # cmake runs in git bash + + cmake --preset "${{ matrix.target }}" + echo "Configured: ${{ matrix.target }}" + + - name: Build "${{ matrix.target }}" + shell: bash + 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 eb41a92e2..673a78f99 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: [ '*' ] 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,9 @@ 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 + ./tools/scripts/wolfboot_build.sh --CLEAN "stm32l4" + ./tools/scripts/wolfboot_build.sh --target "stm32l4" diff --git a/.gitignore b/.gitignore index 65b8a8dce..8f860bba5 100644 --- a/.gitignore +++ b/.gitignore @@ -144,6 +144,9 @@ IDE/IAR/Release build/ CMakeFiles/ CMakeCache.txt +# User specific presets should never be included. +# See docs: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html +/**/CMakeUserPresets.json # Stage 1 stage1/loader_stage1.ld @@ -255,3 +258,25 @@ lib/r_tsip_rx Debug/ Release/ language.settings.xml + +# Backup files +*.bak + +# Any Visual Studio / VisualGDB +/**/.vs +/**/.visualgdb/* + +# Any build directories +/**/build +/**/build-** + +/IDE/VisualGDB +/commit_squash.sh +/evars.txt +/evars_non_dev.txt +/gpg_refresh.sh +/IDE/VisualStudio/EmbeddedProject1 +/IDE/VisualStudio/wolfboot +/.gitignore.wip +/run.log +/stm32.mak diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..060d945ae --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "STM32L4 - OpenOCD", + "type": "cortex-debug", + "request": "launch", + "servertype": "openocd", + "cwd": "${workspaceFolder:wolfBoot}", + "executable": "${workspaceFolder:wolfBoot}/build-stm32l4/wolfboot.elf", + "device": "STM32L475VG", + "configFiles": [ + "interface/stlink-dap.cfg", + "target/stm32l4x.cfg" + ], + "runToMain": true, + "svdFile": "${workspaceFolder:wolfBoot}/hal/stm32l4/STM32L4x.svd", + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..1fc382aab --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "cmake.useCMakePresets": "auto", + "cmake.buildDirectory": "${workspaceFolder}/build-${buildPresetName}", + "cmake.configureOnOpen": true, + "cmake.generator": "Ninja", + "cmake.loggingLevel": "info", + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "files.encoding": "utf8", + "files.eol": "\n", + "cmake.preferredGenerators": [ "Ninja", "Visual Studio 17 2022" ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..7f6bf44fe --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,35 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "CMake: Configure (stm32l4)", + "command": "cmake", + "args": [ "--preset", "stm32l4" ], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "problemMatcher": [] + }, + { + "label": "CMake: Build (stm32l4)", + "command": "cmake", + "args": [ "--build", "--preset", "stm32l4" ], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "group": "build", + "problemMatcher": "$gcc" + }, + { + "label": "OpenOCD: Flash wolfBoot (stm32l4)", + "type": "shell", + "command": "openocd", + "args": [ + "-f", + "interface/stlink-dap.cfg", + "-f", + "target/stm32l4x.cfg", + "-c", + "program ${workspaceFolder:wolfBoot}/build-stm32l4/wolfboot.elf verify reset exit" + ], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "problemMatcher": [] + } + ] +} diff --git a/CMakeLists.txt b/CMakeLists.txt index 108b23d24..c3511f0f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,11 @@ # $ cmake --build . 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 @@ -40,14 +44,252 @@ if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") You must delete them, or cmake will refuse to work.") endif() -project(wolfBoot) +# 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_SOURCE_DIR}/cmake/toolchain_arm-none-eabi.cmake" + CACHE FILEPATH "" FORCE) + endif() +endif() -include(cmake/utils.cmake) + +#--------------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- +project(wolfBoot) +#--------------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- 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 AND NOT FOUND_HAL_BASE) + message(STATUS "Visual Studio 2022 detection active: make/vs2022_config.cmakee") + 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() + +# 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.") + find_program(HOST_CC NAMES gcc clang cl REQUIRED) + + if (HOST_CC MATCHES [[(^|[/\\])cl(\.exe)?$]]) + message(STATUS "Found CMAKE_HOST_WIN32 and .exe in HOST_CC: Setting HOST_IS_MSVC") + # 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) + # DOS/Windows detected by ".exe" extension, not to be confused with WSL and/or WinGW + set(HOST_IS_MSVC TRUE) + 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 + # 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 + endif() +else() + # POSIX hosts + find_program(HOST_CC NAMES gcc clang cc 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_LIBS "") +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}${CMAKE_SOURCE_DIR}/tools/keytools + ${HOST_I}${CMAKE_SOURCE_DIR}/lib/wolfssl + ${HOST_I}${CMAKE_SOURCE_DIR}/include + ${HOST_I}${CMAKE_CURRENT_BINARY_DIR} +) +set(HOST_DEFS + ${HOST_D}WOLFSSL_USER_SETTINGS + ${HOST_D}IMAGE_HEADER_SIZE=${IMAGE_HEADER_SIZE} + ${HOST_D}DELTA_UPDATES +) + +# --- Windows unistd.h shim for MSVC host builds --- +if(CMAKE_HOST_WIN32 AND HOST_IS_MSVC) + 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(include) include_directories(lib/wolfssl) +# TODO +if(false) # my Windows + + # Cross toolchain basics + set(CMAKE_SYSTEM_NAME Generic) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + + # Allow preset to pass the bin directory of the Arm GCC toolchain + set(ARM_GCC_BIN "" CACHE PATH "Path to Arm GNU Toolchain 'bin' folder") + + if(NOT ARM_GCC_BIN) + message(FATAL_ERROR "ARM_GCC_BIN not set. Pass it via preset cacheVariables.") + endif() + + # Normalize to CMake-style path (forward slashes) + file(TO_CMAKE_PATH "${ARM_GCC_BIN}" _ARM_GCC_BIN) + + # Point CMake compilers explicitly + set(CMAKE_C_COMPILER "${_ARM_GCC_BIN}/arm-none-eabi-gcc.exe" CACHE FILEPATH "" FORCE) + set(CMAKE_CXX_COMPILER "${_ARM_GCC_BIN}/arm-none-eabi-g++.exe" CACHE FILEPATH "" FORCE) + set(CMAKE_ASM_COMPILER "${_ARM_GCC_BIN}/arm-none-eabi-gcc.exe" CACHE FILEPATH "" FORCE) + set(CMAKE_AR "${_ARM_GCC_BIN}/arm-none-eabi-ar.exe" CACHE FILEPATH "" FORCE) + set(CMAKE_RANLIB "${_ARM_GCC_BIN}/arm-none-eabi-ranlib.exe" CACHE FILEPATH "" FORCE) + set(CMAKE_OBJCOPY "${_ARM_GCC_BIN}/arm-none-eabi-objcopy.exe" CACHE FILEPATH "" FORCE) + set(CMAKE_OBJDUMP "${_ARM_GCC_BIN}/arm-none-eabi-objdump.exe" CACHE FILEPATH "" FORCE) + set(CMAKE_SIZE "${_ARM_GCC_BIN}/arm-none-eabi-size.exe" CACHE FILEPATH "" FORCE) +endif() + + +#--------------------------------------------------------------------------------------------- +# There are different configuration modes: +# +# - Command-line options +# - Using a .config file. See load_dot_config() +# - Using CMake Presets. (preferred, use cacheVariables from CMakePresets.json) +#--------------------------------------------------------------------------------------------- + +# 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() + + +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") else() @@ -59,7 +301,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 "") @@ -158,7 +400,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) @@ -188,29 +430,65 @@ set(WOLFBOOT_SOURCES include/loader.h include/image.h src/string.c src/image.c) list(APPEND WOLFBOOT_SOURCES src/loader.c) -# 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") +if(0) + # 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") -add_custom_target(binAssemble DEPENDS ${BINASSEMBLE}) + add_custom_target(binAssemble DEPENDS "${BINASSEMBLE}") -# ----------------------------------------------------------------------------- -# Toolchain Specifications -# ----------------------------------------------------------------------------- + #----------------------------------------------------------------------------------------- + # Toolchain Specifications + #----------------------------------------------------------------------------------------- + + + if(ARCH STREQUAL "ARM") + include(cmake/toolchain_arm-none-eabi.cmake) + elseif(ARCH STREQUAL "AARCH64") + include(cmake/toolchain_aarch64-none-elf.cmake) + endif() +else() + # 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") + + add_custom_command( + OUTPUT "${BINASSEMBLE}" + COMMAND "${CMAKE_COMMAND}" -E make_directory ${BINASSEMBLE_OBJDIR} + COMMAND "${HOST_CC}" ${HOST_O2} ${HOST_WARN} + ${HOST_INCLUDES} # <-- needed for unistd.h shim + ${HOST_FO} # /Fo$ # isolate objs + ${HOST_OUT}$ + $ + ${HOST_LINK_LIBS} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + COMMENT "Building bin-assemble tool" + ) + add_custom_target(binAssemble DEPENDS ${BINASSEMBLE}) + + + + #----------------------------------------------------------------------------------------- + # Toolchain Specifications + #----------------------------------------------------------------------------------------- + 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() -if(ARCH STREQUAL "ARM") - include(cmake/toolchain_arm-none-eabi.cmake) -elseif(ARCH STREQUAL "AARCH64") - include(cmake/toolchain_aarch64-none-elf.cmake) endif() -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- # Architecture/CPU configuration -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- set(UPDATE_SOURCES src/update_flash.c) # Default flash offset @@ -301,9 +579,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") @@ -479,6 +757,10 @@ list(APPEND WOLFBOOT_DEFS ${SIGN_OPTIONS}) list(APPEND WOLFBOOT_COMPILE_OPTIONS -Wstack-usage=${STACK_USAGE} -Wno-unused) +#--------------------------------------------------------------------------------------------- +# +#--------------------------------------------------------------------------------------------- + if(PULL_LINKER_DEFINES) list(APPEND WOLFBOOT_DEFS PULL_LINKER_DEFINES) endif() @@ -568,9 +850,9 @@ 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) message(STATUS "Using SHA256 hash") @@ -586,9 +868,9 @@ if(HASH STREQUAL "SHA3") list(APPEND KEYTOOL_OPTIONS --sha3) endif() -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- # wolfboot HAL -# ----------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------- # Default SPI driver name set(SPI_TARGET ${WOLFBOOT_TARGET}) @@ -654,21 +936,175 @@ 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_SOURCE_DIR}/) + +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 +) + + +#--------------------------------------------------------------------------------------------- +# sign tool +#--------------------------------------------------------------------------------------------- +set(SIGN_TOOL ${CMAKE_CURRENT_BINARY_DIR}/sign${HOST_EXE}) +set(SIGN_OBJDIR "${CMAKE_CURRENT_BINARY_DIR}/obj_sign") +if( "${HOST_EXE}" STREQUAL "") + set(HOST_FO_SIGN "") # No /Fo for most environments +else() + # isolate objs only for Windows (.exe) + set(HOST_FO_SIGN "/Fo$") +endif() + + add_custom_command( + OUTPUT ${SIGN_TOOL} + COMMAND "${CMAKE_COMMAND}" -E make_directory ${SIGN_OBJDIR} + COMMAND "${HOST_CC}" ${HOST_O2} ${HOST_WARN} + ${HOST_INCLUDES} ${HOST_DEFS} + ${HOST_FO_SIGN} # /Fo$ # ${HOST_FO_SIGN} + $ + ${KEYTOOL_SOURCES_ABS} + ${HOST_OUT}$ + ${HOST_LINK_LIBS} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + COMMENT "Building signing tool" + ) + +add_custom_target(keytools ALL DEPENDS ${SIGN_TOOL} ${KEYGEN_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_EXE}" STREQUAL "") + set(HOST_FO_KEYGEN "") # No /Fo for most environments +else() + # isolate objs only for Windows (.exe) + set(HOST_FO_KEYGEN "/Fo$") +endif() + +add_custom_command( + OUTPUT ${KEYGEN_TOOL} + COMMAND "${CMAKE_COMMAND}" -E make_directory ${KEYGEN_OBJDIR} + COMMAND "${HOST_CC}" ${HOST_O2} ${HOST_WARN} + ${HOST_INCLUDES} ${HOST_DEFS} + ${HOST_FO_KEYGEN} + $ + ${KEYTOOL_SOURCES_ABS} + ${HOST_OUT}$ + ${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 +#--------------------------------------------------------------------------------------------- add_subdirectory(lib) if(BUILD_TEST_APPS OR BUILD_IMAGE) @@ -731,73 +1167,9 @@ target_include_directories(target BEFORE INTERFACE ${CMAKE_CURRENT_BINARY_DIR} l 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") - -add_custom_target(keytools ALL DEPENDS ${SIGN_TOOL} ${KEYGEN_TOOL}) - +#--------------------------------------------------------------------------------------------- +# +#--------------------------------------------------------------------------------------------- if(NOT SIGN STREQUAL "NONE") add_custom_target(keystore DEPENDS ${SIGN_TOOL} ${KEYGEN_TOOL} ${KEYSTORE}) @@ -805,14 +1177,14 @@ if(NOT SIGN STREQUAL "NONE") if(NOT EXISTS ${KEYSTORE}) add_custom_command( OUTPUT ${KEYSTORE} ${WOLFBOOT_SIGNING_PRIVATE_KEY} - COMMAND ${KEYGEN_TOOL} ${KEYTOOL_OPTIONS} -g ${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} + OUTPUT "${KEYSTORE}" ${WOLFBOOT_SIGNING_PRIVATE_KEY} + DEPENDS "${KEYGEN_TOOL}" APPEND) endif() @@ -831,5 +1203,5 @@ target_compile_options(wolfboot PUBLIC ${EXTRA_COMPILE_OPTIONS}) target_include_directories(wolfboot PUBLIC ${WOLFBOOT_INCLUDE_DIRS}) target_link_libraries(wolfboot wolfboothal target wolfcrypt) -# dont warn on unused code +# don't warn on unused code target_compile_options(wolfboot PRIVATE -Wno-unused ${SIM_COMPILE_OPTIONS}) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..3d9b2986e --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,288 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 22, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "binaryDir": "${sourceDir}/build-${presetName}" + }, + { + "name": "stm32", + "hidden": true, + "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": [ + "stm32h7" + ], + "binaryDir": "${sourceDir}/out/build/${presetName}", + "cacheVariables": { + "WOLFBOOT_CONFIG_MODE": "preset", + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_VERBOSE_MAKEFILE": "ON", + "CMAKE_FIND_DEBUG_MODE": "ON" + } + }, + { + "name": "stm32h7", + "displayName": "STM32H7", + "inherits": [ + "base", + "stm32" + ], + "generator": "Ninja", + "cacheVariables": { + "WOLFBOOT_CONFIG_MODE": "preset", + "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", + "SIGN": "ECC256", + "HASH": "SHA256", + "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", + "stm32" + ], + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-stm32l4", + "cacheVariables": { + "WOLFBOOT_DOWNLOADS_CMAKE": "${sourceDir}/cmake/downloads/stm32l4.cmake", + "WOLFBOOT_CONFIG_MODE": "preset", + "WOLFBOOT_TARGET": "stm32l4", + "STM32L4_PART": "STM32L475xx", + "BOARD": "B-L475E-IOT01A", + "ARCH": "ARM", + "SIGN": "ECC256", + "HASH": "SHA256", + "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" + } + }, + { + "name": "stm32c0", + "displayName": "STM32C0", + "inherits": [ + "base", + "stm32" + ], + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-stm32c0", + "cacheVariables": { + "ST_HAL_TAG": "v1.4.0", + "ST_CMSIS_TAG": "v1.3.0", + "ARCH": "ARM", + "WOLFBOOT_TARGET": "stm32c0", + "SIGN": "ED25519", + "HASH": "SHA256", + "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", + "WOLFBOOT_CONFIG_MODE": "preset" + } + }, + { + "name": "stm32f1", + "displayName": "Linux/WSL ARM (stm32f1)", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-stm32f1", + "cacheVariables": { + "ARCH": "ARM", + "WOLFBOOT_TARGET": "stm32f1", + "SIGN": "ED25519", + "HASH": "SHA256", + "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", + "WOLFBOOT_CONFIG_MODE": "preset" + } + }, + { + "name": "stm32g0", + "displayName": "stm32g0", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build-stm32g0", + "cacheVariables": { + "ARCH": "ARM", + "WOLFBOOT_TARGET": "stm32g0", + "SIGN": "ED25519", + "HASH": "SHA256", + "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", + "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", + "WOLFBOOT_CONFIG_MODE": "preset" + } + } + ], + "buildPresets": [ + { + "name": "vs-debug-trace", + "configurePreset": "vs-debug-trace", + "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" + ] + } + ] +} diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 000000000..e2a6294df --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,15 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + } + ] +} diff --git a/IDE/VSCode/README.md b/IDE/VSCode/README.md new file mode 100644 index 000000000..54ddca38e --- /dev/null +++ b/IDE/VSCode/README.md @@ -0,0 +1,71 @@ +# 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

+ +## 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) +- 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/VisualGDB/README.md b/IDE/VisualGDB/README.md new file mode 100644 index 000000000..7c0cf4bdb --- /dev/null +++ b/IDE/VisualGDB/README.md @@ -0,0 +1,85 @@ +# VisualGDB SDK wolfBoot Project + +See the [cmake/config_defaults.cmake](../../cmake/config_defaults.cmake) file. Of particular interest +are some environment configuration settings, in particular the `DETECT_VISUALGDB`: + +```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) +``` + +## Required include files + +The device manufacturer files are installed by VisualGDB in `C:\Users\%USERNAME%\AppData\Local\VisualGDB`. + +In the case of the STM32L4 needing `stm32l4xx_hal.h`, here: + +```text +C:\Users\%USERNAME%\AppData\Local\VisualGDB\EmbeddedBSPs\arm-eabi\com.sysprogs.arm.stm32\STM32L4xxxx\STM32L4xx_HAL_Driver\Inc +``` + +This is in addition to the similar files installed by the STM32CubeIDE software here (for v1.18.0): + +``` +C:\Users\%USERNAME%\STM32Cube\Repository\STM32Cube_FW_L4_V1.18.0\Drivers\STM32L4xx_HAL_Driver\Inc +``` + +Project workspace directories created by STM32CubeIDE may also have include files in `[project]` directories like there: + +``` +C:\Users\gojimmypi\STM32CubeIDE\workspace_1.14.1\[project]\Drivers\STM32L4xx_HAL_Driver\Inc +``` + + +When using VisualGDB files in WSL: + +```bash +# Base where you found stm32l4xx_hal.h +export HAL_BASE="/mnt/c/Users/$USER/AppData/Local/VisualGDB/EmbeddedBSPs/arm-eabi/com.sysprogs.arm.stm32/STM32L4xxxx" + +# HAL driver includes: +export HAL_INC="$HAL_BASE/STM32L4xx_HAL_Driver/Inc" + +# (Legacy headers are sometimes needed by HAL) +export HAL_INC_LEGACY="$HAL_BASE/STM32L4xx_HAL_Driver/Inc/Legacy" + +# The CMSIS *core* is usually in the Cortex pack VisualGDB ships separately: +# Find the CMSIS *device* (stm32l4xx.h) and *core* (core_cm4.h) include dirs: +export CMSIS_DEV="$(dirname "$(find "$HAL_BASE" -type f -name stm32l4xx.h | head -n1)")" +export CMSIS_CORE="$(dirname "$(find "$HAL_BASE" -type f -name core_cm4.h | head -n1)")" + +# Peek at results +echo "HAL_INC = $HAL_INC" +echo "HAL_INC_LEGACY = $HAL_INC_LEGACY" +echo "CMSIS_DEV = $CMSIS_DEV" +echo "CMSIS_CORE = $CMSIS_CORE" + +# Sanity check to ensure files found +ls "$HAL_INC/stm32l4xx_hal.h" +ls "$CMSIS_DEV/stm32l4xx.h" +ls "$CMSIS_CORE/core_cm4.h" + +# 1) Expose the include paths to GCC (so no Makefile changes needed) +export C_INCLUDE_PATH="$HAL_INC:$HAL_INC/Legacy:$CMSIS_DEV:$CMSIS_CORE" +export CPLUS_INCLUDE_PATH="$C_INCLUDE_PATH" + +echo "C_INCLUDE_PATH = $C_INCLUDE_PATH" +echo "CPLUS_INCLUDE_PATH = $CPLUS_INCLUDE_PATH" + +# 2) Build wolfBoot for STM32L4 with your exact device macro +make TARGET=stm32l4 V=1 CFLAGS+=" -DUSE_HAL_DRIVER -DSTM32L475xx" +``` + +The `.config` file needs to be edited. See the [visualgdb-stm32l4.config](../config/examples/visualgdb-stm32l4.config) example for the STM32-L4. + diff --git a/IDE/VisualGDB/wolfBoot.sln b/IDE/VisualGDB/wolfBoot.sln new file mode 100644 index 000000000..3d17cf78c --- /dev/null +++ b/IDE/VisualGDB/wolfBoot.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36518.9 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wolfBoot", "wolfBoot.vcxproj", "{B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC}.Debug|x64.ActiveCfg = Debug|x64 + {B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC}.Debug|x64.Build.0 = Debug|x64 + {B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC}.Debug|x86.ActiveCfg = Debug|Win32 + {B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC}.Debug|x86.Build.0 = Debug|Win32 + {B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC}.Release|x64.ActiveCfg = Release|x64 + {B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC}.Release|x64.Build.0 = Release|x64 + {B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC}.Release|x86.ActiveCfg = Release|Win32 + {B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F94F2BC6-653D-4E7C-B79F-ECB97184C928} + EndGlobalSection +EndGlobal diff --git a/IDE/VisualGDB/wolfBoot.vcxproj b/IDE/VisualGDB/wolfBoot.vcxproj new file mode 100644 index 000000000..2a56945b6 --- /dev/null +++ b/IDE/VisualGDB/wolfBoot.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + {B6C57BD0-E030-2488-DAD8-8BCE4B8E8FAC} + Win32Proj + + + + Application + true + v143 + + + Application + false + v143 + + + Application + true + v143 + + + Application + false + v143 + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + Level3 + + + true + Console + + + + + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + Level3 + + + true + Console + + + + + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + Level3 + + + true + Console + true + true + + + + + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + Level3 + + + true + Console + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IDE/VisualStudio/EmbeddedProject1/stm32.xml b/IDE/VisualStudio/EmbeddedProject1/stm32.xml new file mode 100644 index 000000000..0f35427a1 --- /dev/null +++ b/IDE/VisualStudio/EmbeddedProject1/stm32.xml @@ -0,0 +1,25 @@ + + + com.visualgdb.arm-eabi + + 10.3.1 + 10.2.90 + 1 + + com.sysprogs.arm.stm32 + 2025.06 + STM32L475VG + STM32L4xxxx/DeviceDefinitions/stm32l475xx.xml + + + + Device-specific files + stm32.mak + + + + + + + + \ No newline at end of file diff --git a/IDE/VisualStudio/README.md b/IDE/VisualStudio/README.md new file mode 100644 index 000000000..5d7f7f536 --- /dev/null +++ b/IDE/VisualStudio/README.md @@ -0,0 +1,44 @@ +# wolfboot Visual Studio + +Users of Visual Studio can open the `WOLFBOOT_ROOT` directory without the need for a project file. + +Visual Studio is "cmake-aware" and recognizes the [CMakePresets.json](../../CMakePresets.json) + +Select a device from the ribbon bar, shown here for the `stm32l4` + +image

+ + +From `Solution Explorer`, right-click `CmakeLists.txt` and then select `Configure wolfBoot`. + +image

+ +To build, follow the same steps to right click, and select `Build`. + +View the CMake and Build messages in the `Output` Window. Noter the dropdown to select view: + +image

+ +## Additional Configuration Defaults + +See the [cmake/config_defaults.cmake](../../cmake/config_defaults.cmake) file. Of particular interest +are some environment configuration settings, in particular the `DETECT_VISUALGDB`: + +```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) +``` + + +For more details, see the [cmake/README](../../cmake/README.md) file. diff --git a/IDE/VisualStudio/wolfboot/CMakeLists.txt b/IDE/VisualStudio/wolfboot/CMakeLists.txt new file mode 100644 index 000000000..586849e2e --- /dev/null +++ b/IDE/VisualStudio/wolfboot/CMakeLists.txt @@ -0,0 +1,21 @@ +# CMakeList.txt : CMake project for wolfboot, include source and define +# project specific logic here. +# +cmake_minimum_required (VERSION 3.8) + +# Enable Hot Reload for MSVC compilers if supported. +if (POLICY CMP0141) + cmake_policy(SET CMP0141 NEW) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") +endif() + +project ("wolfboot") + +# Add source to this project's executable. +add_executable (wolfboot "wolfboot.cpp" "wolfboot.h") + +if (CMAKE_VERSION VERSION_GREATER 3.12) + set_property(TARGET wolfboot PROPERTY CXX_STANDARD 20) +endif() + +# TODO: Add tests and install targets if needed. diff --git a/IDE/VisualStudio/wolfboot/CMakePresets.json b/IDE/VisualStudio/wolfboot/CMakePresets.json new file mode 100644 index 000000000..fd1640568 --- /dev/null +++ b/IDE/VisualStudio/wolfboot/CMakePresets.json @@ -0,0 +1,101 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "windows-base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_C_COMPILER": "cl.exe", + "CMAKE_CXX_COMPILER": "cl.exe" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "x64-debug", + "displayName": "x64 Debug", + "inherits": "windows-base", + "architecture": { + "value": "x64", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "x64-release", + "displayName": "x64 Release", + "inherits": "x64-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "x86-debug", + "displayName": "x86 Debug", + "inherits": "windows-base", + "architecture": { + "value": "x86", + "strategy": "external" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "x86-release", + "displayName": "x86 Release", + "inherits": "x86-debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "linux-debug", + "displayName": "Linux Debug", + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + }, + "vendor": { + "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { + "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" + } + } + }, + { + "name": "macos-debug", + "displayName": "macOS Debug", + "generator": "Ninja", + "binaryDir": "${sourceDir}/out/build/${presetName}", + "installDir": "${sourceDir}/out/install/${presetName}", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + }, + "vendor": { + "microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { + "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" + } + } + } + ] +} diff --git a/IDE/VisualStudio/wolfboot/wolfboot.cpp b/IDE/VisualStudio/wolfboot/wolfboot.cpp new file mode 100644 index 000000000..680ecbd5f --- /dev/null +++ b/IDE/VisualStudio/wolfboot/wolfboot.cpp @@ -0,0 +1,12 @@ +// wolfboot.cpp : Defines the entry point for the application. +// + +#include "wolfboot.h" + +using namespace std; + +int main() +{ + cout << "Hello CMake." << endl; + return 0; +} diff --git a/IDE/VisualStudio/wolfboot/wolfboot.h b/IDE/VisualStudio/wolfboot/wolfboot.h new file mode 100644 index 000000000..84b5adb76 --- /dev/null +++ b/IDE/VisualStudio/wolfboot/wolfboot.h @@ -0,0 +1,8 @@ +// wolfboot.h : Include file for standard system include files, +// or project specific include files. + +#pragma once + +#include + +// TODO: Reference additional headers your program requires here. diff --git a/IDE/Windows/README.md b/IDE/Windows/README.md new file mode 100644 index 000000000..0174e100d --- /dev/null +++ b/IDE/Windows/README.md @@ -0,0 +1,29 @@ +# 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) +- [Visual Studio](../VisualStudio/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 + +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 4ebe75a88..133fa1a89 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/Makefile b/Makefile index 534e7dba2..59e38ff8c 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ else endif endif -WOLFCRYPT_OBJS:= +WOLFCRYPT_OBJS?= SECURE_OBJS:= PUBLIC_KEY_OBJS:= WOLFHSM_OBJS:= @@ -92,7 +92,71 @@ include arch.mk # Parse config options include options.mk -OBJS+=$(WOLFCRYPT_OBJS) + +# ==== VisualGDB remap (opt-in) ============================================== +# Only active if VISUALGDB=1 is set (e.g., in .config or on the CLI). +ifeq ($(VISUALGDB),1) + + # 1) Strip stale Cube includes/macros that may come from options.mk + CFLAGS := $(filter-out -I/home/%/STM32Cube/Repository/%,$(CFLAGS)) + CFLAGS := $(filter-out -DSTM32L4A6xx,$(CFLAGS)) + + # 2) Inject the correct VisualGDB include paths + MCU macro + CFLAGS += \ + -I$(VISUALGDB_BASE)/STM32L4xx_HAL_Driver/Inc \ + -I$(VISUALGDB_BASE)/STM32L4xx_HAL_Driver/Inc/Legacy \ + -I$(VISUALGDB_BASE)/CMSIS_HAL/Core/Include \ + -I$(VISUALGDB_BASE)/CMSIS_HAL/Device/ST/STM32L4xx/Include \ + -DUSE_HAL_DRIVER -D$(STM32L4_PART) + + # --- Finalize crypto objects (dedupe & add once) ---------------------------- + # Normalize paths so filter-out can match both "x.o" and "./x.o" + override WOLFCRYPT_OBJS := $(patsubst ./%,%,$(WOLFCRYPT_OBJS)) + override MATH_OBJS := $(patsubst ./%,%,$(MATH_OBJS)) + + # Remove any pre-existing copies in OBJS, then add the union once + override OBJS := $(filter-out $(WOLFCRYPT_OBJS) $(MATH_OBJS),$(OBJS)) + override OBJS += $(sort $(WOLFCRYPT_OBJS) $(MATH_OBJS)) + # --------------------------------------------------------------------------- + + # Where to read sources from in the VisualGDB pack: + VISUALGDB_HAL_SRC ?= $(VISUALGDB_BASE)/STM32L4xx_HAL_Driver/Src + VISUALGDB_CMSIS_SRC ?= $(VISUALGDB_BASE)/CMSIS_HAL/Device/ST/STM32L4xx/Source/Templates + + # Local object output dirs (inside this repo; not touching VisualGDB files): + HAL_LOCAL_OBJ_DIR ?= build/vis_hal + CMSIS_LOCAL_OBJ_DIR ?= build/vis_cmsis + + # options.mk added classic-Cube object paths under $(STM32CUBE)/Drivers/.../Src/*.o + # Rewrite those object targets to our local obj dirs: + override OBJS := $(patsubst $(STM32CUBE)/Drivers/STM32L4xx_HAL_Driver/Src/%.o,\ + $(HAL_LOCAL_OBJ_DIR)/%.o,$(OBJS)) + override OBJS := $(patsubst $(STM32CUBE)/Drivers/CMSIS/Device/ST/STM32L4xx/Source/Templates/%.o,\ + $(CMSIS_LOCAL_OBJ_DIR)/%.o,$(OBJS)) + + # Pattern rules to actually build them from the VisualGDB sources: + $(HAL_LOCAL_OBJ_DIR)/%.o: $(VISUALGDB_HAL_SRC)/%.c + @mkdir -p $(HAL_LOCAL_OBJ_DIR) + $(CC) $(CFLAGS) -c $< -o $@ + + $(CMSIS_LOCAL_OBJ_DIR)/%.o: $(VISUALGDB_CMSIS_SRC)/%.c + @mkdir -p $(CMSIS_LOCAL_OBJ_DIR) + $(CC) $(CFLAGS) -c $< -o $@ +else + OBJS+=$(WOLFCRYPT_OBJS) +endif +# ============================================================================ + +-include .config + +$(info WOLFCRYPT_OBJS=$(WOLFCRYPT_OBJS)) +$(info MATH_OBJS=$(MATH_OBJS)) + + +$(info SIGN=$(SIGN)) +$(info WOLFCRYPT_OBJS=$(WOLFCRYPT_OBJS)) + + OBJS+=$(PUBLIC_KEY_OBJS) OBJS+=$(WOLFHSM_OBJS) @@ -102,6 +166,8 @@ CFLAGS+= \ -D"WOLFSSL_USER_SETTINGS" \ -D"WOLFTPM_USER_SETTINGS" +CFLAGS += $(EXTRA_CFLAGS) + # Setup default optimizations (for GCC) ifeq ($(USE_GCC_HEADLESS),1) CFLAGS+=-Wall -Wextra -Wno-main -ffreestanding -Wno-unused -nostartfiles @@ -134,6 +200,7 @@ SIGN_ENV=IMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE) \ MAIN_TARGET=factory.bin TARGET_H_TEMPLATE:=include/target.h.in +# TZEN only for TrustZone-capable parts (L5/U5/H5) ifeq ($(TZEN),1) ifeq ($(TARGET),stm32l5) # Don't build a contiguous image @@ -374,6 +441,10 @@ factory_wstage1.bin: $(BINASSEMBLE) stage1/loader_stage1.bin wolfboot.bin $(BOOT wolfboot_stage1.bin: wolfboot.elf stage1/loader_stage1.bin $(Q) cp stage1/loader_stage1.bin wolfboot_stage1.bin +lib/wolfssl/wolfcrypt/src/%.o: lib/wolfssl/wolfcrypt/src/%.c + @mkdir -p $(dir $@) + $(CC) $(CFLAGS) -c $< -o $@ + wolfboot.elf: include/target.h $(LSCRIPT) $(OBJS) $(BINASSEMBLE) FORCE $(Q)(test $(SIGN) = NONE) || (test $(FLASH_OTP_KEYSTORE) = 1) || (grep -q $(SIGN_ALG) src/keystore.c) || \ (echo "Key mismatch: please run 'make keysclean' to remove all keys if you want to change algorithm" && false) diff --git a/README.md b/README.md index d07c084a7..91dd68984 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,38 @@ -# wolfBoot - -wolfSSL Secure Bootloader ([Home page](https://www.wolfssl.com/products/wolfboot/)) +# wolfBoot + +Some interim notes on progress in various environments: + +## CMake Dev Status: + +|Status | Environment | Test With +|-------| ------------------------- | -------- +| ✅ | VS 2022 | Right-Click on [CMakeLists.txt](./CMakeLists.txt), Build +| ✅ | WSL | [./tools/scripts/cmake_test.sh](./tools/scripts/cmake_test.sh) +| ✅ | Mac | [test-build-cmake-mac.yml](./github/workflows/test-build-cmake-mac.yml) +| ✅ | VS Code, Dev Prompt | Click "build" on bottom toolbar ribbon +| ✅ | DOS Prompt, Dev Prompt | [.\tools\scripts\cmake_dev_prompt_test.bat](./tools/scripts/cmake_dev_prompt_test.bat) +| ✅ | PowerShell, Dev Prompt | [.\tools\scripts\cmake_dev_prompt_test.bat](./tools/scripts/cmake_dev_prompt_test.bat) +| ✅ | DOS Prompt, direct launch | [.\tools\scripts\cmake_test.bat](./tools/scripts/cmake_test.bat) (needs toolchain path) +| ✅ | PowerShell, direct launch | [.\tools\scripts\cmake_test.bat](./tools/scripts/cmake_test.bat) (needs toolchain path) +| ✅ | VS Code, direct launch | Click "build" + +## Make Dev Status: + +|Status | Environment | Test With +|-------| ------------------------- | -------- +| ? | VS 2022 | N/A (?) +| ✅ | WSL | `./tools/scripts/wolfboot_build.sh --target stm32l4` +| ⚠️ | Mac | [test-build-cmake-mac.yml](./github/workflows/test-build-cmake-mac.yml) +| ? | VS Code, Dev Prompt | N/A (?) +| ❌ | DOS Prompt, Dev Prompt | +| ❌ | PowerShell, Dev Prompt | +| ❌ | DOS Prompt, direct launch | +| ❌ | PowerShell, direct launch | +| ? | VS Code, direct launch | N/A (?) + +--- + +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 +71,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 +158,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 +329,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 +344,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 +384,13 @@ 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 + +```text +sp_c32.c : fatal error C1083: Cannot open compiler generated file: '... sp_c32.obj': Permission denied +``` + + ## Release Notes ### v1.0 (2018-12-04) @@ -690,12 +784,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 +819,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/CMakeUserPresets.json.sample b/cmake/CMakeUserPresets.json.sample new file mode 100644 index 000000000..cd7155310 --- /dev/null +++ b/cmake/CMakeUserPresets.json.sample @@ -0,0 +1,18 @@ +{ + "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/cmake/README.md b/cmake/README.md new file mode 100644 index 000000000..015b805a2 --- /dev/null +++ b/cmake/README.md @@ -0,0 +1,514 @@ +# wolfBoot Cmake + +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 + +- [../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. + +- [../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" }`. + +- [../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. + +- [CMakeUserPresets.json.sample](./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. + +--- + +### Build with cmake using `.config` files + +Presets are preferred, 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 +``` + + +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' +``` + + +## 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 000000000..c2aab5899 --- /dev/null +++ b/cmake/config_defaults.cmake @@ -0,0 +1,68 @@ +# 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() + + + +# 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) + +include(cmake/current_user.cmake) + +get_current_user(CURRENT_USER) +message(STATUS "Current user detected: ${CURRENT_USER}") + + +# 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") + +# set(ARM_GCC_BIN "") + + +message(STATUS "config.defaults:") +message(STATUS "-- HAL_DRV: ${HAL_DRV}") +message(STATUS "-- HAL_CMSIS_DEV: ${HAL_CMSIS_DEV}") +message(STATUS "-- HAL_CMSIS_CORE:${HAL_CMSIS_CORE}") + +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 000000000..f762b2f4b --- /dev/null +++ b/cmake/cube_ide_config.cmake @@ -0,0 +1,416 @@ +# 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() + +# 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/ + +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() + +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 000000000..19a3c6f52 --- /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 000000000..81e7b682b --- /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 000000000..0900963ed --- /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 9fe006c16..ea3930a9a 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 000000000..4a5840829 --- /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/stm32_hal_download.cmake b/cmake/stm32_hal_download.cmake new file mode 100644 index 000000000..4df82a17c --- /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 4c3de5c54..7155e16ba 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 c2438f835..bc31a6c89 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,101 @@ 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) + 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() + 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() +# 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 +157,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 +187,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 +213,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_ARM_NONE_EABI_CMAKE_INCLUDED true) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 60e2bbf6c..58838fc82 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 @@ -72,3 +83,5 @@ macro(gen_bin_target_outputs TARGET) # 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 000000000..24fad6534 --- /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 000000000..3b6e7e749 --- /dev/null +++ b/cmake/vs2022_config.cmake @@ -0,0 +1,136 @@ +# 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) + +# 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\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(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 +]=]) + + + +# 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 ) + + 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) + list(APPEND _final "${_p}") + list(APPEND _seen "${_p}") + 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 cae75bf9f..9c9474161 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}) @@ -119,3 +129,5 @@ function(gen_wolfboot_factory_image PLATFORM_NAME TARGET) multiconfigfileinstall(${BOOTLOADER_OUTPUTS} bin) endfunction() + +set(WOLFBOOT_CMAKE_INCLUDED true) diff --git a/config/examples/README.md b/config/examples/README.md new file mode 100644 index 000000000..b65ec3dea --- /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_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 000000000..2bb6aed08 --- /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 000000000..6f156f8dd --- /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 9eb0caa26..a6b2a1cb8 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 000000000..3ecd13c5e --- /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 000000000..afbb6931d --- /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_build.sh --CLEAN +./tools/scripts/wolfboot_build.sh --CLEAN stm32h7 +./tools/scripts/wolfboot_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/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 8f78520d1..28e255e54 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 @@ -178,14 +178,14 @@ 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. By default, the sign tool appends the sha of the base image to the manifest header, so wolfBoot will refuse to start a delta update if the sha does not match the one of the existing image. However, this takes up 32 to 48 bytes extra in the - manifest header, so this option is available to provide compatibility on + manifest header, so this option is available to provide compatibility on existing installations without this feature, where the header size does not allow to accommodate the field diff --git a/hal/stm32l4xx_hal_conf.h b/hal/stm32l4xx_hal_conf.h index 85b39c2bd..32c6f4b17 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/test-app/CMakeLists.txt b/test-app/CMakeLists.txt index 353514d47..a0b8a1291 100644 --- a/test-app/CMakeLists.txt +++ b/test-app/CMakeLists.txt @@ -1,4 +1,4 @@ -# CMakeLists.txt +# wolfboot test-app/CMakeLists.txt # # Copyright (C) 2025 wolfSSL Inc. # diff --git a/test-app/Makefile b/test-app/Makefile index 3b232f7b2..c1e2b95d2 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -121,6 +121,53 @@ else APP_OBJS+=../hal/$(TARGET).o endif +# ==== VisualGDB remap for STM32L4 (opt-in) =================================== +# Requires VISUALGDB=1 and VISUALGDB_BASE in ../.config +ifeq ($(VISUALGDB),1) + # VisualGDB pack source locations + VISUALGDB_HAL_SRC ?= $(VISUALGDB_BASE)/STM32L4xx_HAL_Driver/Src + VISUALGDB_CMSIS_SRC ?= $(VISUALGDB_BASE)/CMSIS_HAL/Device/ST/STM32L4xx/Source/Templates + + # Local object output dirs (kept inside this repo) + HAL_LOCAL_OBJ_DIR ?= build/vis_hal + CMSIS_LOCAL_OBJ_DIR ?= build/vis_cmsis + + # Include dirs + MCU macro fix (use L475 without editing pack files) + CFLAGS += \ + -I$(VISUALGDB_BASE)/STM32L4xx_HAL_Driver/Inc \ + -I$(VISUALGDB_BASE)/STM32L4xx_HAL_Driver/Inc/Legacy \ + -I$(VISUALGDB_BASE)/CMSIS_HAL/Core/Include \ + -I$(VISUALGDB_BASE)/CMSIS_HAL/Device/ST/STM32L4xx/Include \ + -USTM32L4A6xx -DSTM32L475xx -DUSE_HAL_DRIVER + + # For stm32l4, ensure we build the needed HAL Flash objs locally + ifeq ($(TARGET),stm32l4) + # If anything in APP_OBJS still references STM32Cube objects, rewrite them: + override APP_OBJS := $(patsubst $(STM32CUBE)/Drivers/STM32L4xx_HAL_Driver/Src/%.o,\ + $(HAL_LOCAL_OBJ_DIR)/%.o,$(APP_OBJS)) + + # Make sure these two are present (the test-app needs them): + APP_OBJS+=$(STM32CUBE)/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.o + APP_OBJS+=$(STM32CUBE)/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.o + + APP_OBJS += \ + $(HAL_LOCAL_OBJ_DIR)/stm32l4xx_hal_flash.o \ + $(HAL_LOCAL_OBJ_DIR)/stm32l4xx_hal_flash_ex.o + endif + + # Pattern rules to compile VisualGDB pack sources into our local obj dirs + $(HAL_LOCAL_OBJ_DIR)/%.o: $(VISUALGDB_HAL_SRC)/%.c + @mkdir -p $(HAL_LOCAL_OBJ_DIR) + $(CC) $(CFLAGS) -c $< -o $@ + + $(CMSIS_LOCAL_OBJ_DIR)/%.o: $(VISUALGDB_CMSIS_SRC)/%.c + @mkdir -p $(CMSIS_LOCAL_OBJ_DIR) + $(CC) $(CFLAGS) -c $< -o $@ +endif +# ============================================================================= + + + ifeq ($(ARCH),RISCV) APP_OBJS+=startup_riscv.o vector_riscv.o endif diff --git a/tools/keytools/sign.c b/tools/keytools/sign.c index 712b1c8ba..fafd3ab4e 100644 --- a/tools/keytools/sign.c +++ b/tools/keytools/sign.c @@ -2830,9 +2830,9 @@ int main(int argc, char** argv) } printf("Input image: %s\n", CMD.image_file); printf("Selected cipher: %s\n", sign_str); - printf("Selected hash : %s\n", hash_str); + printf("Selected hash: %s\n", hash_str); if (CMD.sign != NO_SIGN) { - printf("Private key: %s\n", CMD.key_file); + printf("Private key: %s\n", CMD.key_file); } if (CMD.hybrid) { printf("Secondary cipher: %s\n", secondary_sign_str); @@ -2853,7 +2853,7 @@ int main(int argc, char** argv) if (CMD.encrypt) { printf("Encrypted output: %s\n", CMD.output_encrypted_image_file); } - printf("Target partition id : %hu ", CMD.partition_id); + printf("Target partition id: %hu ", CMD.partition_id); if (CMD.partition_id == HDR_IMG_TYPE_WOLFBOOT) printf("(bootloader)"); printf("\n"); diff --git a/tools/scripts/cmake_dev_prompt_test.bat b/tools/scripts/cmake_dev_prompt_test.bat new file mode 100644 index 000000000..67a6e4f13 --- /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 000000000..c0a787fca --- /dev/null +++ b/tools/scripts/cmake_dot_config.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# cmake_dot_config.sh +# +# Example for using cmake with .config +# +# Reminder for WSL: +# git update-index --chmod=+x wolfboot_build.sh +# git commit -m "Make wolfboot_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" +cp ./config/examples/stm32h7.config ./.config +ls .config +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 -j diff --git a/tools/scripts/cmake_test.bat b/tools/scripts/cmake_test.bat new file mode 100644 index 000000000..f54ea546a --- /dev/null +++ b/tools/scripts/cmake_test.bat @@ -0,0 +1,80 @@ +::!/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) + +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 000000000..c7753c2c8 --- /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 000000000..0dd96c447 --- /dev/null +++ b/tools/scripts/config2presets.py @@ -0,0 +1,226 @@ +#!/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), + ("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_build.sh b/tools/scripts/wolfboot_build.sh new file mode 100755 index 000000000..99ee49634 --- /dev/null +++ b/tools/scripts/wolfboot_build.sh @@ -0,0 +1,306 @@ +#!/bin/bash + +# wolfboot_build.sh +# +# ./tools/scripts/wolfboot_build.sh --CLEAN [your target] +# ./tools/scripts/wolfboot_build.sh --target [your target] +# ./tools/scripts/wolfboot_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_build.sh +# git commit -m "Make wolfboot_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 + + 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 + + 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 diff --git a/wolfBoot.code-workspace b/wolfBoot.code-workspace new file mode 100644 index 000000000..6aee7c3f7 --- /dev/null +++ b/wolfBoot.code-workspace @@ -0,0 +1,83 @@ +{ + "folders": [ + { + "name": "wolfBoot", + "path": "./" + } + ], + "settings": { + // Drive CMake Tools from the repo root folder: + "cmake.useCMakePresets": "always", + "cmake.sourceDirectory": "${workspaceFolder:wolfBoot}", + "cmake.buildDirectory": "${workspaceFolder:wolfBoot}/build-${buildPresetName}", + + // Nice-to-haves: + "cmake.generator": "Ninja", + "cmake.configureOnOpen": true, + "cmake.loggingLevel": "info", + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "files.encoding": "utf8", + "files.eol": "\n" + }, + "extensions": { + "recommendations": [ + "ms-vscode.cmake-tools", + "ms-vscode.cpptools", + "marus25.cortex-debug" + ] + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "STM32L4 - OpenOCD", + "type": "cortex-debug", + "request": "launch", + "servertype": "openocd", + "cwd": "${workspaceFolder:wolfBoot}", + "executable": "${workspaceFolder:wolfBoot}/build-stm32l4/wolfboot.elf", + "device": "STM32L475VG", + "configFiles": [ + "interface/stlink-dap.cfg", + "target/stm32l4x.cfg" + ], + "runToMain": true, + "svdFile": "${workspaceFolder:wolfBoot}/hal/stm32l4/STM32L4x.svd", + "preLaunchTask": "CMake: Build (stm32l4)" + } + ] + }, + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "CMake: Configure (stm32l4)", + "command": "cmake", + "args": ["--preset", "stm32l4"], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "problemMatcher": [] + }, + { + "label": "CMake: Build (stm32l4)", + "command": "cmake", + "args": ["--build", "--preset", "stm32l4"], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "group": "build", + "problemMatcher": "$gcc" + }, + { + "label": "OpenOCD: Flash wolfBoot (stm32l4)", + "type": "shell", + "command": "openocd", + "args": [ + "-f", "interface/stlink-dap.cfg", + "-f", "target/stm32l4x.cfg", + "-c", + "program ${workspaceFolder:wolfBoot}/build-stm32l4/wolfboot.elf verify reset exit" + ], + "options": { "cwd": "${workspaceFolder:wolfBoot}" }, + "problemMatcher": [] + } + ] + } +}