Skip to content

Commit 042defe

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 260975d commit 042defe

File tree

5 files changed

+127
-1
lines changed

5 files changed

+127
-1
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: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,10 @@ config MCUBOOT_BOOTLOADER_SIGNATURE_TYPE_PURE
170170
help
171171
This is a Kconfig which is informative only, the value should not be changed.
172172

173+
config NCS_MCUBOOT_IMGTOOL_APPEND_MANIFEST
174+
bool "MCUboot append manifest"
175+
help
176+
Append common manifest while signing the image.
177+
This is a Kconfig which is informative only, the value should not be changed.
178+
173179
endmenu

sysbuild/CMakeLists.txt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,14 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake)
229229
set_config_bool(mcuboot CONFIG_BOOT_IMG_HASH_ALG_SHA512 y)
230230
endif()
231231

232+
if(SB_CONFIG_MCUBOOT_MANIFEST_UPDATES)
233+
set_config_bool(mcuboot CONFIG_MCUBOOT_MANIFEST_UPDATES y)
234+
set_config_bool(${DEFAULT_IMAGE} CONFIG_NCS_MCUBOOT_IMGTOOL_APPEND_MANIFEST y)
235+
if(SB_CONFIG_MCUBOOT_BUILD_DIRECT_XIP_VARIANT)
236+
set_config_bool(mcuboot_secondary_app CONFIG_NCS_MCUBOOT_IMGTOOL_APPEND_MANIFEST y)
237+
endif()
238+
endif()
239+
232240
# Apply configuration to application
233241
foreach(image ${updateable_images})
234242
foreach(mode ${application_mcuboot_modes})
@@ -331,7 +339,9 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake)
331339
set_config_bool(mcuboot CONFIG_BOOT_FIH_PROFILE_DEFAULT_LOW y)
332340
endif()
333341

334-
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)
342+
if(SB_CONFIG_PARTITION_MANAGER OR SB_CONFIG_MCUBOOT_MODE_DIRECT_XIP
343+
OR SB_CONFIG_MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT OR SB_CONFIG_MCUBOOT_COMPRESSED_IMAGE_SUPPORT
344+
OR SB_CONFIG_MCUBOOT_MANIFEST_UPDATES)
335345
# Use NCS signing script with support for PM or direct XIP (NCS specific features)
336346
if(SB_CONFIG_QSPI_XIP_SPLIT_IMAGE)
337347
set(${DEFAULT_IMAGE}_SIGNING_SCRIPT "${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/image_signing_split.cmake" CACHE INTERNAL "MCUboot signing script" FORCE)
@@ -801,6 +811,10 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake)
801811
include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/mcuboot_nrf54h20.cmake)
802812
endif()
803813

814+
if(SB_CONFIG_BOOTLOADER_MCUBOOT AND SB_CONFIG_MCUBOOT_MANIFEST_UPDATES)
815+
include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/mcuboot_manifest.cmake)
816+
endif()
817+
804818
if(SB_CONFIG_DFU_ZIP)
805819
if(SB_CONFIG_BOOTLOADER_MCUBOOT)
806820
include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/zip.cmake)

sysbuild/Kconfig.mcuboot

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

25+
config MCUBOOT_MANIFEST_UPDATES
26+
bool "Enable transactional updates"
27+
help
28+
If y, enables support for transactional updates using manifests.
29+
This allows multiple images to be updated atomically. The manifest
30+
is a separate TLV which contains a list of images to update and
31+
their expected hash values. The manifest TLV is a part of an image
32+
that is signed to prevent tampering.
33+
The manifest must be transferred as part of the image with index 0.
34+
It can be a dedicated image, or part of an existing image.
35+
If the second option is selected, all updates must contain an update
36+
for image 0.
37+
2538
config MCUBOOT_BUILD_DIRECT_XIP_VARIANT
2639
bool "Build DirectXIP variant image"
2740
depends on MCUBOOT_MODE_DIRECT_XIP || MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT

0 commit comments

Comments
 (0)