1# Copyright (c) 2020-2023 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
23  if(NOT "${CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE}")
24    # Check for misconfiguration.
25    if("${keyfile}" STREQUAL "")
26      # No signature key file, no signed binaries. No error, though:
27      # this is the documented behavior.
28      message(WARNING "Neither CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE or "
29                      "CONFIG_MCUBOOT_SIGNATURE_KEY_FILE are set, the generated build will not be "
30                      "bootable by MCUboot unless it is signed manually/externally.")
31      return()
32    endif()
33  endif()
34
35  if(NOT WEST)
36    # This feature requires west.
37    message(FATAL_ERROR "Can't sign images for MCUboot: west not found. To fix, install west and ensure it's on PATH.")
38  endif()
39
40  foreach(file keyfile keyfile_enc)
41    if(NOT "${${file}}" STREQUAL "")
42      if(NOT IS_ABSOLUTE "${${file}}")
43        # Relative paths are relative to 'west topdir'.
44        set(${file} "${WEST_TOPDIR}/${${file}}")
45      endif()
46
47      if(NOT EXISTS "${${file}}" AND NOT "${CONFIG_MCUBOOT_GENERATE_UNSIGNED_IMAGE}")
48        message(FATAL_ERROR "west sign can't find file ${${file}} (Note: Relative paths are relative to the west workspace topdir \"${WEST_TOPDIR}\")")
49      elseif(NOT (CONFIG_BUILD_OUTPUT_BIN OR CONFIG_BUILD_OUTPUT_HEX))
50        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.")
51      endif()
52    endif()
53  endforeach()
54
55  # Find imgtool. Even though west is installed, imgtool might not be.
56  # The user may also have a custom manifest which doesn't include
57  # MCUboot.
58  #
59  # Therefore, go with an explicitly installed imgtool first, falling
60  # back on mcuboot/scripts/imgtool.py.
61  if(IMGTOOL)
62    set(imgtool_path "${IMGTOOL}")
63  elseif(DEFINED ZEPHYR_MCUBOOT_MODULE_DIR)
64    set(IMGTOOL_PY "${ZEPHYR_MCUBOOT_MODULE_DIR}/scripts/imgtool.py")
65    if(EXISTS "${IMGTOOL_PY}")
66      set(imgtool_path "${IMGTOOL_PY}")
67    endif()
68  endif()
69
70  # No imgtool, no signed binaries.
71  if(NOT DEFINED imgtool_path)
72    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.")
73    return()
74  endif()
75
76  # Fetch devicetree details for flash and slot information
77  dt_chosen(flash_node PROPERTY "zephyr,flash")
78  dt_nodelabel(slot0_flash NODELABEL "slot0_partition" REQUIRED)
79  dt_prop(slot_size PATH "${slot0_flash}" PROPERTY "reg" INDEX 1 REQUIRED)
80  dt_prop(write_block_size PATH "${flash_node}" PROPERTY "write-block-size")
81
82  if(NOT write_block_size)
83    set(write_block_size 4)
84    message(WARNING "slot0_partition write block size devicetree parameter is missing, assuming write block size is 4")
85  endif()
86
87  # If single slot mode, or if in firmware updater mode and this is the firmware updater image,
88  # use slot 0 information
89  if(NOT CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP AND (NOT CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER OR CONFIG_MCUBOOT_APPLICATION_FIRMWARE_UPDATER))
90    # Slot 1 size is used instead of slot 0 size
91    set(slot_size)
92    dt_nodelabel(slot1_flash NODELABEL "slot1_partition" REQUIRED)
93    dt_prop(slot_size PATH "${slot1_flash}" PROPERTY "reg" INDEX 1 REQUIRED)
94  endif()
95
96  # Basic 'imgtool sign' command with known image information.
97  set(imgtool_sign ${PYTHON_EXECUTABLE} ${imgtool_path} sign
98      --version ${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION} --header-size ${CONFIG_ROM_START_OFFSET}
99      --slot-size ${slot_size})
100
101  # Arguments to imgtool.
102  if(NOT CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS STREQUAL "")
103    # Separate extra arguments into the proper format for adding to
104    # extra_post_build_commands.
105    #
106    # Use UNIX_COMMAND syntax for uniform results across host
107    # platforms.
108    separate_arguments(imgtool_args UNIX_COMMAND ${CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS})
109  else()
110    set(imgtool_args)
111  endif()
112
113  if(NOT "${keyfile}" STREQUAL "")
114    set(imgtool_args --key "${keyfile}" ${imgtool_args})
115  endif()
116
117  if(CONFIG_MCUBOOT_IMGTOOL_OVERWRITE_ONLY)
118    # Use overwrite-only instead of swap upgrades.
119    set(imgtool_args --overwrite-only --align 1 ${imgtool_args})
120  elseif(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD)
121    # RAM load requires setting the location of where to load the image to
122    dt_chosen(chosen_ram PROPERTY "zephyr,sram")
123    dt_reg_addr(chosen_ram_address PATH ${chosen_ram})
124    dt_nodelabel(slot0_partition NODELABEL "slot0_partition" REQUIRED)
125    dt_reg_addr(slot0_partition_address PATH ${slot0_partition})
126    dt_nodelabel(slot1_partition NODELABEL "slot1_partition" REQUIRED)
127    dt_reg_addr(slot1_partition_address PATH ${slot1_partition})
128
129    set(imgtool_args --align 1 --load-addr ${chosen_ram_address} ${imgtool_args})
130    set(imgtool_args_alt_slot ${imgtool_args} --hex-addr ${slot1_partition_address})
131    set(imgtool_args ${imgtool_args} --hex-addr ${slot0_partition_address})
132  else()
133    set(imgtool_args --align ${write_block_size} ${imgtool_args})
134  endif()
135
136  # Extensionless prefix of any output file.
137  set(output ${ZEPHYR_BINARY_DIR}/${KERNEL_NAME})
138
139  # List of additional build byproducts.
140  set(byproducts)
141
142  # Set up .bin outputs.
143  if(CONFIG_BUILD_OUTPUT_BIN)
144    list(APPEND byproducts ${output}.signed.bin)
145    zephyr_runner_file(bin ${output}.signed.bin)
146    set(BYPRODUCT_KERNEL_SIGNED_BIN_NAME "${output}.signed.bin"
147        CACHE FILEPATH "Signed kernel bin file" FORCE
148    )
149    set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
150                 ${imgtool_sign} ${imgtool_args} ${output}.bin ${output}.signed.bin)
151
152    if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
153      list(APPEND byproducts ${output}.signed.confirmed.bin)
154      set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_BIN_NAME "${output}.signed.confirmed.bin"
155          CACHE FILEPATH "Signed and confirmed kernel bin file" FORCE
156      )
157      set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
158                   ${imgtool_sign} ${imgtool_args} --pad --confirm ${output}.bin
159                   ${output}.signed.confirmed.bin)
160    endif()
161
162    if(NOT "${keyfile_enc}" STREQUAL "")
163      list(APPEND byproducts ${output}.signed.encrypted.bin)
164      set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_BIN_NAME "${output}.signed.encrypted.bin"
165          CACHE FILEPATH "Signed and encrypted kernel bin file" FORCE
166      )
167      set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
168                   ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" ${output}.bin
169                   ${output}.signed.encrypted.bin)
170    endif()
171
172    if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD)
173      list(APPEND byproducts ${output}.slot1.signed.encrypted.bin)
174      set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
175                   ${imgtool_sign} ${imgtool_args_alt_slot} ${output}.bin
176                   ${output}.slot1.signed.bin)
177
178      if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
179        list(APPEND byproducts ${output}.slot1.signed.confirmed.bin)
180        set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
181                     ${imgtool_sign} ${imgtool_args_alt_slot} --pad --confirm ${output}.bin
182                     ${output}.slot1.signed.confirmed.bin)
183      endif()
184
185      if(NOT "${keyfile_enc}" STREQUAL "")
186        list(APPEND byproducts ${output}.slot1.signed.encrypted.bin)
187        set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
188                     ${imgtool_sign} ${imgtool_args_alt_slot} --encrypt "${keyfile_enc}"
189                     ${output}.bin ${output}.slot1.signed.encrypted.bin)
190      endif()
191    endif()
192  endif()
193
194  # Set up .hex outputs.
195  if(CONFIG_BUILD_OUTPUT_HEX)
196    list(APPEND byproducts ${output}.signed.hex)
197    zephyr_runner_file(hex ${output}.signed.hex)
198    set(BYPRODUCT_KERNEL_SIGNED_HEX_NAME "${output}.signed.hex"
199        CACHE FILEPATH "Signed kernel hex file" FORCE
200    )
201    set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
202                 ${imgtool_sign} ${imgtool_args} ${output}.hex ${output}.signed.hex)
203
204    if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
205      list(APPEND byproducts ${output}.signed.confirmed.hex)
206      set(BYPRODUCT_KERNEL_SIGNED_CONFIRMED_HEX_NAME "${output}.signed.confirmed.hex"
207          CACHE FILEPATH "Signed and confirmed kernel hex file" FORCE
208      )
209      set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
210                   ${imgtool_sign} ${imgtool_args} --pad --confirm ${output}.hex
211                   ${output}.signed.confirmed.hex)
212    endif()
213
214    if(NOT "${keyfile_enc}" STREQUAL "")
215      list(APPEND byproducts ${output}.signed.encrypted.hex)
216      set(BYPRODUCT_KERNEL_SIGNED_ENCRYPTED_HEX_NAME "${output}.signed.encrypted.hex"
217          CACHE FILEPATH "Signed and encrypted kernel hex file" FORCE
218      )
219      set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
220                   ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" ${output}.hex
221                   ${output}.signed.encrypted.hex)
222    endif()
223
224    if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD)
225      list(APPEND byproducts ${output}.slot1.signed.hex)
226      set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
227                   ${imgtool_sign} ${imgtool_args_alt_slot} ${output}.hex
228                   ${output}.slot1.signed.hex)
229
230      if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
231        list(APPEND byproducts ${output}.slot1.signed.confirmed.hex)
232        set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
233                     ${imgtool_sign} ${imgtool_args_alt_slot} --pad --confirm ${output}.hex
234                     ${output}.slot1.signed.confirmed.hex)
235      endif()
236
237      if(NOT "${keyfile_enc}" STREQUAL "")
238        list(APPEND byproducts ${output}.slot1.signed.encrypted.hex)
239        set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
240                     ${imgtool_sign} ${imgtool_args_alt_slot} --encrypt "${keyfile_enc}"
241                     ${output}.hex ${output}.slot1.signed.encrypted.hex)
242      endif()
243    endif()
244  endif()
245  set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts ${byproducts})
246endfunction()
247
248zephyr_mcuboot_tasks()
249