1# Copyright (c) 2020 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  # Check for misconfiguration.
24  if("${keyfile}" STREQUAL "")
25    # No signature key file, no signed binaries. No error, though:
26    # this is the documented behavior.
27    return()
28  endif()
29
30  if(NOT WEST)
31    # This feature requires west.
32    message(FATAL_ERROR "Can't sign images for MCUboot: west not found. To fix, install west and ensure it's on PATH.")
33  endif()
34
35  foreach(file keyfile keyfile_enc)
36    if(NOT "${${file}}" STREQUAL "")
37      if(NOT IS_ABSOLUTE "${${file}}")
38        # Relative paths are relative to 'west topdir'.
39        set(${file} "${WEST_TOPDIR}/${${file}}")
40      endif()
41
42      if(NOT EXISTS "${${file}}")
43        message(FATAL_ERROR "west sign can't find file ${${file}} (Note: Relative paths are relative to the west workspace topdir \"${WEST_TOPDIR}\")")
44      elseif(NOT (CONFIG_BUILD_OUTPUT_BIN OR CONFIG_BUILD_OUTPUT_HEX))
45        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.")
46      endif()
47    endif()
48  endforeach()
49
50  # Find imgtool. Even though west is installed, imgtool might not be.
51  # The user may also have a custom manifest which doesn't include
52  # MCUboot.
53  #
54  # Therefore, go with an explicitly installed imgtool first, falling
55  # back on mcuboot/scripts/imgtool.py.
56  if(IMGTOOL)
57    set(imgtool_path "${IMGTOOL}")
58  elseif(DEFINED ZEPHYR_MCUBOOT_MODULE_DIR)
59    set(IMGTOOL_PY "${ZEPHYR_MCUBOOT_MODULE_DIR}/scripts/imgtool.py")
60    if(EXISTS "${IMGTOOL_PY}")
61      set(imgtool_path "${IMGTOOL_PY}")
62    endif()
63  endif()
64
65  # No imgtool, no signed binaries.
66  if(NOT DEFINED imgtool_path)
67    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.")
68    return()
69  endif()
70
71  # Basic 'west sign' command and output format independent arguments.
72  set(west_sign ${WEST} sign --quiet --tool imgtool
73    --tool-path "${imgtool_path}"
74    --build-dir "${APPLICATION_BINARY_DIR}")
75
76  # Arguments to imgtool.
77  if(NOT CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS STREQUAL "")
78    # Separate extra arguments into the proper format for adding to
79    # extra_post_build_commands.
80    #
81    # Use UNIX_COMMAND syntax for uniform results across host
82    # platforms.
83    separate_arguments(imgtool_extra UNIX_COMMAND ${CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS})
84  else()
85    set(imgtool_extra)
86  endif()
87  set(imgtool_args -- --key "${keyfile}" ${imgtool_extra})
88
89  # Extensionless prefix of any output file.
90  set(output ${ZEPHYR_BINARY_DIR}/${KERNEL_NAME})
91
92  # List of additional build byproducts.
93  set(byproducts)
94
95  # 'west sign' arguments for confirmed, unconfirmed and encrypted images.
96  set(unconfirmed_args)
97  set(confirmed_args)
98  set(encrypted_args)
99
100  # Set up .bin outputs.
101  if(CONFIG_BUILD_OUTPUT_BIN)
102    list(APPEND unconfirmed_args --bin --sbin ${output}.signed.bin)
103    list(APPEND byproducts ${output}.signed.bin)
104    zephyr_runner_file(bin ${output}.signed.bin)
105
106    if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
107      list(APPEND confirmed_args --bin --sbin ${output}.signed.confirmed.bin)
108      list(APPEND byproducts ${output}.signed.confirmed.bin)
109    endif()
110
111    if(NOT "${keyfile_enc}" STREQUAL "")
112      list(APPEND encrypted_args --bin --sbin ${output}.signed.encrypted.bin)
113      list(APPEND byproducts ${output}.signed.encrypted.bin)
114    endif()
115  endif()
116
117  # Set up .hex outputs.
118  if(CONFIG_BUILD_OUTPUT_HEX)
119    list(APPEND unconfirmed_args --hex --shex ${output}.signed.hex)
120    list(APPEND byproducts ${output}.signed.hex)
121    zephyr_runner_file(hex ${output}.signed.hex)
122
123    if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE)
124      list(APPEND confirmed_args --hex --shex ${output}.signed.confirmed.hex)
125      list(APPEND byproducts ${output}.signed.confirmed.hex)
126    endif()
127
128    if(NOT "${keyfile_enc}" STREQUAL "")
129      list(APPEND encrypted_args --hex --shex ${output}.signed.encrypted.hex)
130      list(APPEND byproducts ${output}.signed.encrypted.hex)
131    endif()
132  endif()
133
134  # Add the west sign calls and their byproducts to the post-processing
135  # steps for zephyr.elf.
136  #
137  # CMake guarantees that multiple COMMANDs given to
138  # add_custom_command() are run in order, so adding the 'west sign'
139  # calls to the "extra_post_build_commands" property ensures they run
140  # after the commands which generate the unsigned versions.
141  set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
142    ${west_sign} ${unconfirmed_args} ${imgtool_args})
143  if(confirmed_args)
144    set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
145      ${west_sign} ${confirmed_args} ${imgtool_args} --pad --confirm)
146  endif()
147  if(encrypted_args)
148    set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND
149      ${west_sign} ${encrypted_args} ${imgtool_args} --encrypt "${keyfile_enc}")
150  endif()
151  set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts ${byproducts})
152endfunction()
153
154zephyr_mcuboot_tasks()
155