|  | # Copyright (c) 2020-2025 Nordic Semiconductor ASA | 
|  | # SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | # This file includes extra build system logic that is enabled when | 
|  | # CONFIG_BOOTLOADER_MCUBOOT=y. | 
|  | # | 
|  | # It builds signed binaries using imgtool as a post-processing step | 
|  | # after zephyr/zephyr.elf is created in the build directory. | 
|  | # | 
|  | # Since this file is brought in via include(), we do the work in a | 
|  | # function to avoid polluting the top-level scope. | 
|  |  | 
|  | function(zephyr_runner_file type path) | 
|  | # Property magic which makes west flash choose the signed build | 
|  | # output of a given type. | 
|  | set_target_properties(runners_yaml_props_target PROPERTIES "${type}_file" "${path}") | 
|  | endfunction() | 
|  |  | 
|  | function(zephyr_mcuboot_tasks) | 
|  | set(keyfile "${CONFIG_MCUBOOT_SIGNATURE_KEY_FILE}") | 
|  | set(keyfile_enc "${CONFIG_MCUBOOT_ENCRYPTION_KEY_FILE}") | 
|  | string(CONFIGURE "${keyfile}" keyfile) | 
|  | string(CONFIGURE "${keyfile_enc}" keyfile_enc) | 
|  |  | 
|  | if(NOT "${CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE}") | 
|  | # Check for misconfiguration. | 
|  | if("${keyfile}" STREQUAL "") | 
|  | # No signature key file, no signed binaries. No error, though: | 
|  | # this is the documented behavior. | 
|  | message(WARNING "Neither CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE or " | 
|  | "CONFIG_MCUBOOT_SIGNATURE_KEY_FILE are set, the generated build will not be " | 
|  | "bootable by MCUboot unless it is signed manually/externally.") | 
|  | return() | 
|  | elseif(NOT (CONFIG_BUILD_OUTPUT_BIN OR CONFIG_BUILD_OUTPUT_HEX)) | 
|  | message(FATAL_ERROR "Can't sign images for MCUboot: Neither " | 
|  | "CONFIG_BUILD_OUTPUT_BIN nor CONFIG_BUILD_OUTPUT_HEX " | 
|  | "is enabled, so there's nothing to sign.") | 
|  | endif() | 
|  |  | 
|  | foreach(file keyfile keyfile_enc) | 
|  | if("${${file}}" STREQUAL "") | 
|  | continue() | 
|  | endif() | 
|  |  | 
|  | # Find the key files in the order of preference for a simple search | 
|  | # modeled by the if checks across the various locations | 
|  | # | 
|  | #  1. absolute | 
|  | #  2. application config | 
|  | #  3. west topdir (optional when the workspace is not west managed) | 
|  | # | 
|  | if(NOT IS_ABSOLUTE "${${file}}") | 
|  | if(EXISTS "${APPLICATION_CONFIG_DIR}/${${file}}") | 
|  | set(${file} "${APPLICATION_CONFIG_DIR}/${${file}}") | 
|  | else() | 
|  | # Relative paths are relative to 'west topdir'. | 
|  | # | 
|  | # This is the only file that has a relative check to topdir likely | 
|  | # from the historical callouts to "west" itself before using | 
|  | # imgtool. So, this is maintained here for backward compatibility | 
|  | # | 
|  | if(NOT WEST OR NOT WEST_TOPDIR) | 
|  | message(FATAL_ERROR "Can't sign images for MCUboot: west workspace undefined. " | 
|  | "To fix, ensure `west topdir` is a valid workspace directory.") | 
|  | endif() | 
|  | set(${file} "${WEST_TOPDIR}/${${file}}") | 
|  | endif() | 
|  | endif() | 
|  |  | 
|  | if(NOT EXISTS "${${file}}") | 
|  | message(FATAL_ERROR "Can't sign images for MCUboot: can't find file ${${file}} " | 
|  | "(Note: Relative paths are searched through " | 
|  | "APPLICATION_CONFIG_DIR=\"${APPLICATION_CONFIG_DIR}\" " | 
|  | "and WEST_TOPDIR=\"${WEST_TOPDIR}\")") | 
|  | endif() | 
|  |  | 
|  | # Add key file as CMake dependency so a file change will rerun the build | 
|  | set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${${file}}) | 
|  | endforeach() | 
|  | endif() | 
|  |  | 
|  | # No imgtool, no signed binaries. | 
|  | if(NOT DEFINED IMGTOOL) | 
|  | message(FATAL_ERROR "Can't sign images for MCUboot: can't find imgtool. To fix, install imgtool with pip3, or add the mcuboot repository to the west manifest and ensure it has a scripts/imgtool.py file.") | 
|  | return() | 
|  | endif() | 
|  |  | 
|  | # Fetch devicetree details for flash and slot information | 
|  | dt_chosen(flash_node PROPERTY "zephyr,flash") | 
|  | dt_nodelabel(slot0_flash NODELABEL "slot0_partition" REQUIRED) | 
|  | dt_prop(slot_size PATH "${slot0_flash}" PROPERTY "reg" INDEX 1 REQUIRED) | 
|  |  | 
|  | # If single slot mode, or if in firmware updater mode and this is the firmware updater image, | 
|  | # use slot 0 information | 
|  | if(NOT CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP AND (NOT CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER OR CONFIG_MCUBOOT_APPLICATION_FIRMWARE_UPDATER) | 
|  | AND NOT CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP_RAM_LOAD) | 
|  | # Slot 1 size is used instead of slot 0 size | 
|  | set(slot_size) | 
|  | dt_nodelabel(slot1_flash NODELABEL "slot1_partition" REQUIRED) | 
|  | dt_prop(slot_size PATH "${slot1_flash}" PROPERTY "reg" INDEX 1 REQUIRED) | 
|  | endif() | 
|  |  | 
|  | # Basic 'imgtool sign' command with known image information. | 
|  | set(imgtool_sign ${PYTHON_EXECUTABLE} ${IMGTOOL} sign | 
|  | --version ${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION} --header-size ${CONFIG_ROM_START_OFFSET} | 
|  | --slot-size ${slot_size}) | 
|  |  | 
|  | # Arguments to imgtool. | 
|  | if(NOT CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS STREQUAL "") | 
|  | # Separate extra arguments into the proper format for adding to | 
|  | # extra_post_build_commands. | 
|  | # | 
|  | # Use UNIX_COMMAND syntax for uniform results across host | 
|  | # platforms. | 
|  | separate_arguments(imgtool_args UNIX_COMMAND ${CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS}) | 
|  | else() | 
|  | set(imgtool_args) | 
|  | endif() | 
|  |  | 
|  | if(NOT "${keyfile}" STREQUAL "") | 
|  | set(imgtool_args --key "${keyfile}" ${imgtool_args}) | 
|  | endif() | 
|  |  | 
|  | if(CONFIG_MCUBOOT_IMGTOOL_UUID_VID) | 
|  | set(imgtool_args ${imgtool_args} --vid "${CONFIG_MCUBOOT_IMGTOOL_UUID_VID_NAME}") | 
|  | endif() | 
|  |  | 
|  | if(CONFIG_MCUBOOT_IMGTOOL_UUID_CID) | 
|  | set(imgtool_args ${imgtool_args} --cid "${CONFIG_MCUBOOT_IMGTOOL_UUID_CID_NAME}") | 
|  | endif() | 
|  |  | 
|  | if(CONFIG_MCUBOOT_IMGTOOL_OVERWRITE_ONLY) | 
|  | # Use overwrite-only instead of swap upgrades. | 
|  | set(imgtool_args --overwrite-only --align 1 ${imgtool_args}) | 
|  | elseif(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD OR CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT) | 
|  | # RAM load requires setting the location of where to load the image to | 
|  | dt_chosen(chosen_ram PROPERTY "zephyr,sram") | 
|  | dt_reg_addr(chosen_ram_address PATH ${chosen_ram}) | 
|  | dt_nodelabel(slot0_partition NODELABEL "slot0_partition" REQUIRED) | 
|  | dt_reg_addr(slot0_partition_address PATH ${slot0_partition}) | 
|  | dt_nodelabel(slot1_partition NODELABEL "slot1_partition" REQUIRED) | 
|  | dt_reg_addr(slot1_partition_address PATH ${slot1_partition}) | 
|  |  | 
|  | dt_prop(write_block_size PATH "${flash_node}" PROPERTY "write-block-size") | 
|  | if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) | 
|  | set(imgtool_args --align 1 --load-addr ${chosen_ram_address} ${imgtool_args}) | 
|  | else() # CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT | 
|  | set(imgtool_args --align ${write_block_size} --load-addr ${chosen_ram_address} ${imgtool_args}) | 
|  | endif() | 
|  | set(imgtool_args_alt_slot ${imgtool_args} --hex-addr ${slot1_partition_address}) | 
|  | set(imgtool_args ${imgtool_args} --hex-addr ${slot0_partition_address}) | 
|  | elseif(CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP_RAM_LOAD) | 
|  | dt_chosen(ram_load_dev PROPERTY "mcuboot,ram-load-dev") | 
|  | if(DEFINED ram_load_dev) | 
|  | dt_reg_addr(load_address PATH ${ram_load_dev}) | 
|  | else() | 
|  | dt_chosen(chosen_ram PROPERTY "zephyr,sram") | 
|  | dt_reg_addr(load_address PATH ${chosen_ram}) | 
|  | endif() | 
|  | set(imgtool_args --align 1 --load-addr ${load_address} ${imgtool_args}) | 
|  | else() | 
|  | dt_prop(write_block_size PATH "${flash_node}" PROPERTY "write-block-size") | 
|  |  | 
|  | if(NOT write_block_size) | 
|  | set(write_block_size 4) | 
|  | message(WARNING "slot0_partition write block size devicetree parameter is missing, assuming write block size is 4") | 
|  | endif() | 
|  |  | 
|  | set(imgtool_args --align ${write_block_size} ${imgtool_args}) | 
|  | endif() | 
|  |  | 
|  | # Set proper hash calculation algorithm for signing | 
|  | if(CONFIG_MCUBOOT_BOOTLOADER_SIGNATURE_TYPE_PURE) | 
|  | set(imgtool_args --pure ${imgtool_args}) | 
|  | elseif(CONFIG_MCUBOOT_BOOTLOADER_USES_SHA512) | 
|  | set(imgtool_args --sha 512 ${imgtool_args}) | 
|  | endif() | 
|  |  | 
|  | if(NOT "${keyfile_enc}" STREQUAL "") | 
|  | if(CONFIG_MCUBOOT_ENCRYPTION_ALG_AES_256) | 
|  | # Note: this overrides the default behavior of using AES-128 | 
|  | set(imgtool_args ${imgtool_args} --encrypt-keylen 256) | 
|  | endif() | 
|  | endif() | 
|  |  | 
|  | # Extensionless prefix of any output file. | 
|  | set(output ${ZEPHYR_BINARY_DIR}/${KERNEL_NAME}) | 
|  |  | 
|  | # List of additional build byproducts. | 
|  | set(byproducts) | 
|  |  | 
|  | # Set up .bin outputs. | 
|  | if(CONFIG_BUILD_OUTPUT_BIN) | 
|  | list(APPEND byproducts ${output}.signed.bin) | 
|  | zephyr_runner_file(bin ${output}.signed.bin) | 
|  | set(BYPRODUCT_KERNEL_SIGNED_BIN_NAME "${output}.signed.bin" | 
|  | CACHE FILEPATH "Signed kernel bin file" FORCE | 
|  | ) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args} ${output}.bin ${output}.signed.bin) | 
|  |  | 
|  | if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) | 
|  | list(APPEND byproducts ${output}.signed.confirmed.bin) | 
|  | zephyr_runner_file(bin ${output}.signed.confirmed.bin) | 
|  | set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_BIN_NAME "${output}.signed.confirmed.bin" | 
|  | CACHE FILEPATH "Signed and confirmed kernel bin file" FORCE | 
|  | ) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args} --pad --confirm ${output}.bin | 
|  | ${output}.signed.confirmed.bin) | 
|  | zephyr_runner_file(bin ${output}.signed.confirmed.bin) | 
|  | endif() | 
|  |  | 
|  | if(NOT "${keyfile_enc}" STREQUAL "") | 
|  | list(APPEND byproducts ${output}.signed.encrypted.bin) | 
|  | set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_BIN_NAME "${output}.signed.encrypted.bin" | 
|  | CACHE FILEPATH "Signed and encrypted kernel bin file" FORCE | 
|  | ) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" ${output}.bin | 
|  | ${output}.signed.encrypted.bin) | 
|  | endif() | 
|  |  | 
|  | if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD OR CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT) | 
|  | list(APPEND byproducts ${output}.slot1.signed.encrypted.bin) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args_alt_slot} ${output}.bin | 
|  | ${output}.slot1.signed.bin) | 
|  |  | 
|  | if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) | 
|  | list(APPEND byproducts ${output}.slot1.signed.confirmed.bin) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args_alt_slot} --pad --confirm ${output}.bin | 
|  | ${output}.slot1.signed.confirmed.bin) | 
|  | endif() | 
|  |  | 
|  | if(NOT "${keyfile_enc}" STREQUAL "") | 
|  | list(APPEND byproducts ${output}.slot1.signed.encrypted.bin) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args_alt_slot} --encrypt "${keyfile_enc}" | 
|  | ${output}.bin ${output}.slot1.signed.encrypted.bin) | 
|  | endif() | 
|  | endif() | 
|  | endif() | 
|  |  | 
|  | # Set up .hex outputs. | 
|  | if(CONFIG_BUILD_OUTPUT_HEX) | 
|  | list(APPEND byproducts ${output}.signed.hex) | 
|  | zephyr_runner_file(hex ${output}.signed.hex) | 
|  | set(BYPRODUCT_KERNEL_SIGNED_HEX_NAME "${output}.signed.hex" | 
|  | CACHE FILEPATH "Signed kernel hex file" FORCE | 
|  | ) | 
|  |  | 
|  | if(NOT "${keyfile_enc}" STREQUAL "") | 
|  | # When encryption is enabled, set the encrypted bit when signing the image but do not | 
|  | # encrypt the data, this means that when the image is moved out of the primary into the | 
|  | # secondary, it will be encrypted rather than being in unencrypted | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" --clear | 
|  | ${output}.hex ${output}.signed.hex) | 
|  | else() | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args} ${output}.hex ${output}.signed.hex) | 
|  | endif() | 
|  |  | 
|  | if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) | 
|  | list(APPEND byproducts ${output}.signed.confirmed.hex) | 
|  | zephyr_runner_file(hex ${output}.signed.confirmed.hex) | 
|  | set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_HEX_NAME "${output}.signed.confirmed.hex" | 
|  | CACHE FILEPATH "Signed and confirmed kernel hex file" FORCE | 
|  | ) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args} --pad --confirm ${output}.hex | 
|  | ${output}.signed.confirmed.hex) | 
|  | zephyr_runner_file(hex ${output}.signed.confirmed.hex) | 
|  | endif() | 
|  |  | 
|  | if(NOT "${keyfile_enc}" STREQUAL "") | 
|  | list(APPEND byproducts ${output}.signed.encrypted.hex) | 
|  | set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_HEX_NAME "${output}.signed.encrypted.hex" | 
|  | CACHE FILEPATH "Signed and encrypted kernel hex file" FORCE | 
|  | ) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" ${output}.hex | 
|  | ${output}.signed.encrypted.hex) | 
|  | endif() | 
|  |  | 
|  | if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD OR CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT) | 
|  | list(APPEND byproducts ${output}.slot1.signed.hex) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args_alt_slot} ${output}.hex | 
|  | ${output}.slot1.signed.hex) | 
|  |  | 
|  | if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) | 
|  | list(APPEND byproducts ${output}.slot1.signed.confirmed.hex) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args_alt_slot} --pad --confirm ${output}.hex | 
|  | ${output}.slot1.signed.confirmed.hex) | 
|  | endif() | 
|  |  | 
|  | if(NOT "${keyfile_enc}" STREQUAL "") | 
|  | list(APPEND byproducts ${output}.slot1.signed.encrypted.hex) | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND | 
|  | ${imgtool_sign} ${imgtool_args_alt_slot} --encrypt "${keyfile_enc}" | 
|  | ${output}.hex ${output}.slot1.signed.encrypted.hex) | 
|  | endif() | 
|  | endif() | 
|  | endif() | 
|  | set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts ${byproducts}) | 
|  | endfunction() | 
|  |  | 
|  | zephyr_mcuboot_tasks() |