1# Copyright (c) 2020-2025 Nordic Semiconductor ASA 2# SPDX-License-Identifier: Apache-2.0 3 4# This file includes extra build system logic that is enabled when 5# CONFIG_BOOTLOADER_MCUBOOT=y. 6# 7# It builds signed binaries using imgtool as a post-processing step 8# after zephyr/zephyr.elf is created in the build directory. 9# 10# Since this file is brought in via include(), we do the work in a 11# function to avoid polluting the top-level scope. 12 13function(zephyr_runner_file type path) 14 # Property magic which makes west flash choose the signed build 15 # output of a given type. 16 set_target_properties(runners_yaml_props_target PROPERTIES "${type}_file" "${path}") 17endfunction() 18 19function(zephyr_mcuboot_tasks) 20 set(keyfile "${CONFIG_MCUBOOT_SIGNATURE_KEY_FILE}") 21 set(keyfile_enc "${CONFIG_MCUBOOT_ENCRYPTION_KEY_FILE}") 22 string(CONFIGURE "${keyfile}" keyfile) 23 string(CONFIGURE "${keyfile_enc}" keyfile_enc) 24 25 if(NOT "${CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE}") 26 # Check for misconfiguration. 27 if("${keyfile}" STREQUAL "") 28 # No signature key file, no signed binaries. No error, though: 29 # this is the documented behavior. 30 message(WARNING "Neither CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE or " 31 "CONFIG_MCUBOOT_SIGNATURE_KEY_FILE are set, the generated build will not be " 32 "bootable by MCUboot unless it is signed manually/externally.") 33 return() 34 elseif(NOT (CONFIG_BUILD_OUTPUT_BIN OR CONFIG_BUILD_OUTPUT_HEX)) 35 message(FATAL_ERROR "Can't sign images for MCUboot: Neither " 36 "CONFIG_BUILD_OUTPUT_BIN nor CONFIG_BUILD_OUTPUT_HEX " 37 "is enabled, so there's nothing to sign.") 38 endif() 39 40 foreach(file keyfile keyfile_enc) 41 if("${${file}}" STREQUAL "") 42 continue() 43 endif() 44 45 # Find the key files in the order of preference for a simple search 46 # modeled by the if checks across the various locations 47 # 48 # 1. absolute 49 # 2. application config 50 # 3. west topdir (optional when the workspace is not west managed) 51 # 52 if(NOT IS_ABSOLUTE "${${file}}") 53 if(EXISTS "${APPLICATION_CONFIG_DIR}/${${file}}") 54 set(${file} "${APPLICATION_CONFIG_DIR}/${${file}}") 55 else() 56 # Relative paths are relative to 'west topdir'. 57 # 58 # This is the only file that has a relative check to topdir likely 59 # from the historical callouts to "west" itself before using 60 # imgtool. So, this is maintained here for backward compatibility 61 # 62 if(NOT WEST OR NOT WEST_TOPDIR) 63 message(FATAL_ERROR "Can't sign images for MCUboot: west workspace undefined. " 64 "To fix, ensure `west topdir` is a valid workspace directory.") 65 endif() 66 set(${file} "${WEST_TOPDIR}/${${file}}") 67 endif() 68 endif() 69 70 if(NOT EXISTS "${${file}}") 71 message(FATAL_ERROR "Can't sign images for MCUboot: can't find file ${${file}} " 72 "(Note: Relative paths are searched through " 73 "APPLICATION_CONFIG_DIR=\"${APPLICATION_CONFIG_DIR}\" " 74 "and WEST_TOPDIR=\"${WEST_TOPDIR}\")") 75 endif() 76 endforeach() 77 endif() 78 79 # No imgtool, no signed binaries. 80 if(NOT DEFINED IMGTOOL) 81 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.") 82 return() 83 endif() 84 85 # Fetch devicetree details for flash and slot information 86 dt_chosen(flash_node PROPERTY "zephyr,flash") 87 dt_nodelabel(slot0_flash NODELABEL "slot0_partition" REQUIRED) 88 dt_prop(slot_size PATH "${slot0_flash}" PROPERTY "reg" INDEX 1 REQUIRED) 89 90 # If single slot mode, or if in firmware updater mode and this is the firmware updater image, 91 # use slot 0 information 92 if(NOT CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP AND (NOT CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER OR CONFIG_MCUBOOT_APPLICATION_FIRMWARE_UPDATER) 93 AND NOT CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP_RAM_LOAD) 94 # Slot 1 size is used instead of slot 0 size 95 set(slot_size) 96 dt_nodelabel(slot1_flash NODELABEL "slot1_partition" REQUIRED) 97 dt_prop(slot_size PATH "${slot1_flash}" PROPERTY "reg" INDEX 1 REQUIRED) 98 endif() 99 100 # Basic 'imgtool sign' command with known image information. 101 set(imgtool_sign ${PYTHON_EXECUTABLE} ${IMGTOOL} sign 102 --version ${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION} --header-size ${CONFIG_ROM_START_OFFSET} 103 --slot-size ${slot_size}) 104 105 # Arguments to imgtool. 106 if(NOT CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS STREQUAL "") 107 # Separate extra arguments into the proper format for adding to 108 # extra_post_build_commands. 109 # 110 # Use UNIX_COMMAND syntax for uniform results across host 111 # platforms. 112 separate_arguments(imgtool_args UNIX_COMMAND ${CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS}) 113 else() 114 set(imgtool_args) 115 endif() 116 117 if(NOT "${keyfile}" STREQUAL "") 118 set(imgtool_args --key "${keyfile}" ${imgtool_args}) 119 endif() 120 121 if(CONFIG_MCUBOOT_IMGTOOL_OVERWRITE_ONLY) 122 # Use overwrite-only instead of swap upgrades. 123 set(imgtool_args --overwrite-only --align 1 ${imgtool_args}) 124 elseif(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD OR CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT) 125 # RAM load requires setting the location of where to load the image to 126 dt_chosen(chosen_ram PROPERTY "zephyr,sram") 127 dt_reg_addr(chosen_ram_address PATH ${chosen_ram}) 128 dt_nodelabel(slot0_partition NODELABEL "slot0_partition" REQUIRED) 129 dt_reg_addr(slot0_partition_address PATH ${slot0_partition}) 130 dt_nodelabel(slot1_partition NODELABEL "slot1_partition" REQUIRED) 131 dt_reg_addr(slot1_partition_address PATH ${slot1_partition}) 132 133 dt_prop(write_block_size PATH "${flash_node}" PROPERTY "write-block-size") 134 set(imgtool_args --align ${write_block_size} --load-addr ${chosen_ram_address} ${imgtool_args}) 135 set(imgtool_args_alt_slot ${imgtool_args} --hex-addr ${slot1_partition_address}) 136 set(imgtool_args ${imgtool_args} --hex-addr ${slot0_partition_address}) 137 elseif(CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP_RAM_LOAD) 138 dt_chosen(ram_load_dev PROPERTY "mcuboot,ram-load-dev") 139 if(DEFINED ram_load_dev) 140 dt_reg_addr(load_address PATH ${ram_load_dev}) 141 else() 142 dt_chosen(chosen_ram PROPERTY "zephyr,sram") 143 dt_reg_addr(load_address PATH ${chosen_ram}) 144 endif() 145 set(imgtool_args --align 1 --load-addr ${load_address} ${imgtool_args}) 146 else() 147 dt_prop(write_block_size PATH "${flash_node}" PROPERTY "write-block-size") 148 149 if(NOT write_block_size) 150 set(write_block_size 4) 151 message(WARNING "slot0_partition write block size devicetree parameter is missing, assuming write block size is 4") 152 endif() 153 154 set(imgtool_args --align ${write_block_size} ${imgtool_args}) 155 endif() 156 157 # Set proper hash calculation algorithm for signing 158 if(CONFIG_MCUBOOT_BOOTLOADER_SIGNATURE_TYPE_PURE) 159 set(imgtool_args --pure ${imgtool_args}) 160 elseif(CONFIG_MCUBOOT_BOOTLOADER_USES_SHA512) 161 set(imgtool_args --sha 512 ${imgtool_args}) 162 endif() 163 164 if(NOT "${keyfile_enc}" STREQUAL "") 165 if(CONFIG_MCUBOOT_ENCRYPTION_ALG_AES_256) 166 # Note: this overrides the default behavior of using AES-128 167 set(imgtool_args ${imgtool_args} --encrypt-keylen 256) 168 endif() 169 endif() 170 171 # Extensionless prefix of any output file. 172 set(output ${ZEPHYR_BINARY_DIR}/${KERNEL_NAME}) 173 174 # List of additional build byproducts. 175 set(byproducts) 176 177 # Set up .bin outputs. 178 if(CONFIG_BUILD_OUTPUT_BIN) 179 list(APPEND byproducts ${output}.signed.bin) 180 zephyr_runner_file(bin ${output}.signed.bin) 181 set(BYPRODUCT_KERNEL_SIGNED_BIN_NAME "${output}.signed.bin" 182 CACHE FILEPATH "Signed kernel bin file" FORCE 183 ) 184 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 185 ${imgtool_sign} ${imgtool_args} ${output}.bin ${output}.signed.bin) 186 187 if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) 188 list(APPEND byproducts ${output}.signed.confirmed.bin) 189 zephyr_runner_file(bin ${output}.signed.confirmed.bin) 190 set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_BIN_NAME "${output}.signed.confirmed.bin" 191 CACHE FILEPATH "Signed and confirmed kernel bin file" FORCE 192 ) 193 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 194 ${imgtool_sign} ${imgtool_args} --pad --confirm ${output}.bin 195 ${output}.signed.confirmed.bin) 196 zephyr_runner_file(bin ${output}.signed.confirmed.bin) 197 endif() 198 199 if(NOT "${keyfile_enc}" STREQUAL "") 200 list(APPEND byproducts ${output}.signed.encrypted.bin) 201 set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_BIN_NAME "${output}.signed.encrypted.bin" 202 CACHE FILEPATH "Signed and encrypted kernel bin file" FORCE 203 ) 204 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 205 ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" ${output}.bin 206 ${output}.signed.encrypted.bin) 207 endif() 208 209 if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD OR CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT) 210 list(APPEND byproducts ${output}.slot1.signed.encrypted.bin) 211 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 212 ${imgtool_sign} ${imgtool_args_alt_slot} ${output}.bin 213 ${output}.slot1.signed.bin) 214 215 if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) 216 list(APPEND byproducts ${output}.slot1.signed.confirmed.bin) 217 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 218 ${imgtool_sign} ${imgtool_args_alt_slot} --pad --confirm ${output}.bin 219 ${output}.slot1.signed.confirmed.bin) 220 endif() 221 222 if(NOT "${keyfile_enc}" STREQUAL "") 223 list(APPEND byproducts ${output}.slot1.signed.encrypted.bin) 224 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 225 ${imgtool_sign} ${imgtool_args_alt_slot} --encrypt "${keyfile_enc}" 226 ${output}.bin ${output}.slot1.signed.encrypted.bin) 227 endif() 228 endif() 229 endif() 230 231 # Set up .hex outputs. 232 if(CONFIG_BUILD_OUTPUT_HEX) 233 list(APPEND byproducts ${output}.signed.hex) 234 zephyr_runner_file(hex ${output}.signed.hex) 235 set(BYPRODUCT_KERNEL_SIGNED_HEX_NAME "${output}.signed.hex" 236 CACHE FILEPATH "Signed kernel hex file" FORCE 237 ) 238 239 if(NOT "${keyfile_enc}" STREQUAL "") 240 # When encryption is enabled, set the encrypted bit when signing the image but do not 241 # encrypt the data, this means that when the image is moved out of the primary into the 242 # secondary, it will be encrypted rather than being in unencrypted 243 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 244 ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" --clear 245 ${output}.hex ${output}.signed.hex) 246 else() 247 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 248 ${imgtool_sign} ${imgtool_args} ${output}.hex ${output}.signed.hex) 249 endif() 250 251 if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) 252 list(APPEND byproducts ${output}.signed.confirmed.hex) 253 zephyr_runner_file(hex ${output}.signed.confirmed.hex) 254 set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_HEX_NAME "${output}.signed.confirmed.hex" 255 CACHE FILEPATH "Signed and confirmed kernel hex file" FORCE 256 ) 257 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 258 ${imgtool_sign} ${imgtool_args} --pad --confirm ${output}.hex 259 ${output}.signed.confirmed.hex) 260 zephyr_runner_file(hex ${output}.signed.confirmed.hex) 261 endif() 262 263 if(NOT "${keyfile_enc}" STREQUAL "") 264 list(APPEND byproducts ${output}.signed.encrypted.hex) 265 set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_HEX_NAME "${output}.signed.encrypted.hex" 266 CACHE FILEPATH "Signed and encrypted kernel hex file" FORCE 267 ) 268 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 269 ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" ${output}.hex 270 ${output}.signed.encrypted.hex) 271 endif() 272 273 if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD OR CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD_WITH_REVERT) 274 list(APPEND byproducts ${output}.slot1.signed.hex) 275 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 276 ${imgtool_sign} ${imgtool_args_alt_slot} ${output}.hex 277 ${output}.slot1.signed.hex) 278 279 if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) 280 list(APPEND byproducts ${output}.slot1.signed.confirmed.hex) 281 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 282 ${imgtool_sign} ${imgtool_args_alt_slot} --pad --confirm ${output}.hex 283 ${output}.slot1.signed.confirmed.hex) 284 endif() 285 286 if(NOT "${keyfile_enc}" STREQUAL "") 287 list(APPEND byproducts ${output}.slot1.signed.encrypted.hex) 288 set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND 289 ${imgtool_sign} ${imgtool_args_alt_slot} --encrypt "${keyfile_enc}" 290 ${output}.hex ${output}.slot1.signed.encrypted.hex) 291 endif() 292 endif() 293 endif() 294 set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts ${byproducts}) 295endfunction() 296 297zephyr_mcuboot_tasks() 298