Skip to content

Commit eca54e8

Browse files
committed
sysbuild: Add a MCUboot manifest generator
Add a possibility to automatically generate a MCUboot manifest with all expected image's digests. Signed-off-by: Tomasz Chyrowicz <[email protected]>
1 parent dc5a11b commit eca54e8

File tree

6 files changed

+189
-2
lines changed

6 files changed

+189
-2
lines changed

cmake/sysbuild/image_signing.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ function(zephyr_mcuboot_tasks)
143143
set(imgtool_extra ${imgtool_extra} --cid "${CONFIG_MCUBOOT_IMGTOOL_UUID_CID_NAME}")
144144
endif()
145145

146+
if(CONFIG_NCS_MCUBOOT_IMGTOOL_APPEND_MANIFEST)
147+
set(imgtool_extra ${imgtool_extra} --manifest "manifest.yaml")
148+
endif()
149+
146150
set(imgtool_args ${imgtool_extra})
147151

148152
# Extensionless prefix of any output file.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
6+
include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/bootloader_dts_utils.cmake)
7+
8+
yaml_create(NAME mcuboot_manifest)
9+
yaml_set(NAME mcuboot_manifest KEY format VALUE "1")
10+
yaml_set(NAME mcuboot_manifest KEY images LIST)
11+
set(manifest_path "manifest.yaml")
12+
set(manifest_img_slot_0 "${DEFAULT_IMAGE}")
13+
14+
yaml_create(NAME mcuboot_secondary_manifest)
15+
yaml_set(NAME mcuboot_secondary_manifest KEY format VALUE "1")
16+
yaml_set(NAME mcuboot_secondary_manifest KEY images LIST)
17+
set(manifest_secondary_path "manifest_secondary.yaml")
18+
set(manifest_img_slot_1 "mcuboot_secondary_app")
19+
20+
# Since the default (merged) image is excluded from the manifest, because it contains the manifest
21+
# itself, there is no need to construct the manifest when building a merged image.
22+
if(NOT SB_CONFIG_MCUBOOT_SIGN_MERGED_BINARY)
23+
sysbuild_get(manifest_img IMAGE mcuboot VAR CONFIG_MCUBOOT_MANIFEST_IMAGE_NUMBER KCONFIG)
24+
math(EXPR manifest_slot_0 "${manifest_img} * 2")
25+
math(EXPR manifest_slot_1 "${manifest_img} * 2 + 1")
26+
dt_partition_addr(slot0_addr LABEL "slot${manifest_slot_0}_partition" TARGET mcuboot ABSOLUTE REQUIRED)
27+
dt_partition_addr(slot1_addr LABEL "slot${manifest_slot_1}_partition" TARGET mcuboot ABSOLUTE REQUIRED)
28+
29+
UpdateableImage_Get(images GROUP "DEFAULT")
30+
foreach(image ${images})
31+
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
32+
sysbuild_get(BINARY_BIN_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
33+
dt_chosen(code_flash TARGET ${image} PROPERTY "zephyr,code-partition")
34+
dt_partition_addr(code_addr PATH "${code_flash}" TARGET ${image} ABSOLUTE REQUIRED)
35+
36+
if("${code_addr}" STREQUAL "${slot0_addr}")
37+
cmake_path(APPEND BINARY_DIR "zephyr" "manifest.yaml" OUTPUT_VARIABLE manifest_path)
38+
set(manifest_img_slot_0 "${image}")
39+
continue()
40+
endif()
41+
42+
if(NOT "${SB_CONFIG_SIGNATURE_TYPE}" STREQUAL "NONE")
43+
cmake_path(APPEND BINARY_DIR "zephyr" "${BINARY_BIN_FILE}.signed.bin" OUTPUT_VARIABLE image_path)
44+
else()
45+
cmake_path(APPEND BINARY_DIR "zephyr" "${BINARY_BIN_FILE}.bin" OUTPUT_VARIABLE image_path)
46+
endif()
47+
48+
yaml_set(NAME mcuboot_manifest KEY images APPEND LIST MAP "path: ${image_path}, name: ${image}")
49+
endforeach()
50+
51+
foreach(image ${images})
52+
if("${image}" STREQUAL "${manifest_img_slot_0}")
53+
continue()
54+
endif()
55+
add_dependencies("${manifest_img_slot_0}" "${image}")
56+
endforeach()
57+
58+
UpdateableImage_Get(variants GROUP "VARIANT")
59+
foreach(image ${variants})
60+
sysbuild_get(BINARY_DIR IMAGE ${image} VAR APPLICATION_BINARY_DIR CACHE)
61+
sysbuild_get(BINARY_BIN_FILE IMAGE ${image} VAR CONFIG_KERNEL_BIN_NAME KCONFIG)
62+
dt_chosen(code_flash TARGET ${image} PROPERTY "zephyr,code-partition")
63+
dt_partition_addr(code_addr PATH "${code_flash}" TARGET ${image} ABSOLUTE REQUIRED)
64+
65+
if("${code_addr}" STREQUAL "${slot1_addr}")
66+
cmake_path(APPEND BINARY_DIR "zephyr" "manifest.yaml" OUTPUT_VARIABLE manifest_secondary_path)
67+
set(manifest_img_slot_1 "${image}")
68+
continue()
69+
endif()
70+
71+
if(NOT "${SB_CONFIG_SIGNATURE_TYPE}" STREQUAL "NONE")
72+
cmake_path(APPEND BINARY_DIR "zephyr" "${BINARY_BIN_FILE}.signed.bin" OUTPUT_VARIABLE image_path)
73+
else()
74+
cmake_path(APPEND BINARY_DIR "zephyr" "${BINARY_BIN_FILE}.bin" OUTPUT_VARIABLE image_path)
75+
endif()
76+
77+
yaml_set(NAME mcuboot_secondary_manifest KEY images APPEND LIST MAP "path: ${image_path}, name: ${image}")
78+
endforeach()
79+
80+
foreach(image ${variants})
81+
if("${image}" STREQUAL "${manifest_img_slot_1}")
82+
continue()
83+
endif()
84+
add_dependencies("${manifest_img_slot_1}" "${image}")
85+
endforeach()
86+
endif()
87+
88+
yaml_save(NAME mcuboot_manifest FILE "${manifest_path}")
89+
yaml_save(NAME mcuboot_secondary_manifest FILE "${manifest_secondary_path}")

subsys/bootloader/Kconfig

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,4 +188,27 @@ config NCS_MCUBOOT_BOOTLOADER_SIGN_MERGED_BINARY
188188
help
189189
This is a Kconfig which is informative only, the value should not be changed.
190190

191+
config NCS_MCUBOOT_MANIFEST_UPDATES
192+
bool "Enable transactional updates"
193+
help
194+
Enables support for transactional updates using manifests.
195+
This is a Kconfig which is informative only, the value should not be changed.
196+
197+
if NCS_MCUBOOT_MANIFEST_UPDATES
198+
199+
config NCS_MCUBOOT_IMGTOOL_APPEND_MANIFEST
200+
bool "MCUboot append manifest"
201+
help
202+
Append common manifest while signing the image.
203+
This is a Kconfig which is informative only, the value should not be changed.
204+
205+
config NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER
206+
int "Number of image that must include manifest"
207+
help
208+
Specifies the index of the image that must include the manifest.
209+
This is a Kconfig which is informative only, the value should not be changed.
210+
211+
endif # NCS_MCUBOOT_MANIFEST_UPDATES
212+
213+
191214
endmenu

sysbuild/CMakeLists.txt

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake)
172172
set(dfu_slots_output_names Application;Network;Wifi\ patches;QSPI\ XIP;MCUboot\ b0\ update)
173173
set(dfu_slots_output_text "-- Sysbuild assigned MCUboot image IDs:\n")
174174
set(dfu_image_index -1)
175+
set(manifest_image_target "none")
175176

176177
list(LENGTH dfu_slots_sysbuild_kconfigs test_things_size)
177178
math(EXPR test_things_size "${test_things_size} - 1")
@@ -193,6 +194,22 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake)
193194
set_config_int(${image} ${current_application_kconfig} ${value})
194195
endforeach()
195196

197+
if(SB_CONFIG_MCUBOOT_MANIFEST_UPDATES)
198+
if(${value} EQUAL ${SB_CONFIG_MCUBOOT_MANIFEST_IMAGE_NUMBER})
199+
if("${current_application_kconfig}" STREQUAL "CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER")
200+
set(manifest_image_target ${DEFAULT_IMAGE})
201+
elseif("${current_application_kconfig}" STREQUAL "CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER")
202+
set(manifest_image_target ${SB_CONFIG_NETCORE_IMAGE_NAME})
203+
else()
204+
# Unsupported indexes:
205+
# - CONFIG_MCUBOOT_WIFI_PATCHES_IMAGE_NUMBER
206+
# - CONFIG_MCUBOOT_QSPI_XIP_IMAGE_NUMBER
207+
# - CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER
208+
message(FATAL_ERROR "MCUboot manifest image can only be assigned to application or network core images")
209+
endif()
210+
endif()
211+
endif()
212+
196213
set(${current_cache_name} ${value} CACHE INTERNAL "" FORCE)
197214
endforeach()
198215

@@ -229,6 +246,25 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake)
229246
set_config_bool(mcuboot CONFIG_BOOT_IMG_HASH_ALG_SHA512 y)
230247
endif()
231248

249+
if(SB_CONFIG_MCUBOOT_MANIFEST_UPDATES)
250+
set_config_bool(mcuboot CONFIG_MCUBOOT_MANIFEST_UPDATES y)
251+
set_config_int(mcuboot CONFIG_MCUBOOT_MANIFEST_IMAGE_NUMBER
252+
${SB_CONFIG_MCUBOOT_MANIFEST_IMAGE_NUMBER})
253+
254+
if("${manifest_image_target}" STREQUAL "none")
255+
message(FATAL_ERROR "No manifest image target, cannot append manifest to image")
256+
endif()
257+
set_config_bool(${manifest_image_target} CONFIG_NCS_MCUBOOT_IMGTOOL_APPEND_MANIFEST y)
258+
if(SB_CONFIG_MCUBOOT_BUILD_DIRECT_XIP_VARIANT)
259+
if("${manifest_image_target}" STREQUAL "${DEFAULT_IMAGE}")
260+
set_config_bool(mcuboot_secondary_app CONFIG_NCS_MCUBOOT_IMGTOOL_APPEND_MANIFEST y)
261+
else()
262+
set_config_bool(${manifest_image_target}_secondary_app
263+
CONFIG_NCS_MCUBOOT_IMGTOOL_APPEND_MANIFEST y)
264+
endif()
265+
endif()
266+
endif()
267+
232268
# Apply configuration to application
233269
foreach(image ${updateable_images})
234270
foreach(mode ${application_mcuboot_modes})
@@ -239,6 +275,11 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake)
239275
endif()
240276
endforeach()
241277

278+
if(SB_CONFIG_MCUBOOT_MANIFEST_UPDATES)
279+
set_config_bool(${image} CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES y)
280+
set_config_int(${image} CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER ${SB_CONFIG_MCUBOOT_MANIFEST_IMAGE_NUMBER})
281+
endif()
282+
242283
if(SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519)
243284
set_config_bool(${image} CONFIG_MCUBOOT_BOOTLOADER_SIGNATURE_TYPE_ED25519 y)
244285
endif()
@@ -354,7 +395,9 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake)
354395
set_config_bool(mcuboot CONFIG_BOOT_FIH_PROFILE_DEFAULT_LOW y)
355396
endif()
356397

357-
if(SB_CONFIG_PARTITION_MANAGER OR SB_CONFIG_MCUBOOT_MODE_DIRECT_XIP OR SB_CONFIG_MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT OR SB_CONFIG_MCUBOOT_COMPRESSED_IMAGE_SUPPORT)
398+
if(SB_CONFIG_PARTITION_MANAGER OR SB_CONFIG_MCUBOOT_MODE_DIRECT_XIP
399+
OR SB_CONFIG_MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT OR SB_CONFIG_MCUBOOT_COMPRESSED_IMAGE_SUPPORT
400+
OR SB_CONFIG_MCUBOOT_MANIFEST_UPDATES)
358401
# Use NCS signing script with support for PM or direct XIP (NCS specific features)
359402
if(SB_CONFIG_QSPI_XIP_SPLIT_IMAGE)
360403
set(${DEFAULT_IMAGE}_SIGNING_SCRIPT "${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/image_signing_split.cmake" CACHE INTERNAL "MCUboot signing script" FORCE)
@@ -813,6 +856,10 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake)
813856
include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/mcuboot_nrf54h20.cmake)
814857
endif()
815858

859+
if(SB_CONFIG_BOOTLOADER_MCUBOOT AND SB_CONFIG_MCUBOOT_MANIFEST_UPDATES)
860+
include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/mcuboot_manifest.cmake)
861+
endif()
862+
816863
if(SB_CONFIG_DFU_ZIP)
817864
if(SB_CONFIG_BOOTLOADER_MCUBOOT)
818865
include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/zip.cmake)

sysbuild/Kconfig.mcuboot

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,30 @@ config MCUBOOT_IMAGES_ROM_END_OFFSET_AUTO
2323
(e.g. "smp_svr;ipc_radio", "mcuboot_secondary_app").
2424
If empty the default set of updateable images will be affected.
2525

26+
config MCUBOOT_MANIFEST_UPDATES
27+
bool "Enable transactional updates"
28+
help
29+
If y, enables support for transactional updates using manifests.
30+
This allows multiple images to be updated atomically. The manifest
31+
is a separate TLV which contains a list of images to update and
32+
their expected hash values. The manifest TLV is a part of an image
33+
that is signed to prevent tampering.
34+
The manifest must be transferred as part of the image with index 0.
35+
It can be a dedicated image, or part of an existing image.
36+
If the second option is selected, all updates must contain an update
37+
for image 0.
38+
39+
if MCUBOOT_MANIFEST_UPDATES
40+
41+
config MCUBOOT_MANIFEST_IMAGE_NUMBER
42+
int "Number of image that must include manifest"
43+
default 0
44+
range 0 MCUBOOT_UPDATEABLE_IMAGES
45+
help
46+
Specifies the index of the image that must include the manifest.
47+
48+
endif # MCUBOOT_MANIFEST_UPDATES
49+
2650
config MCUBOOT_BUILD_DIRECT_XIP_VARIANT
2751
bool "Build DirectXIP variant image"
2852
depends on MCUBOOT_MODE_DIRECT_XIP || MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT

west.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ manifest:
127127
compare-by-default: true
128128
- name: mcuboot
129129
repo-path: sdk-mcuboot
130-
revision: 484a6f30394abbc2b9f404e715e99271fcf926aa
130+
revision: pull/560/head
131131
path: bootloader/mcuboot
132132
- name: qcbor
133133
url: https://github.com/laurencelundblade/QCBOR

0 commit comments

Comments
 (0)