diff --git a/CODEOWNERS b/CODEOWNERS index 3b27b99208a3..59a118dbb5ad 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -52,6 +52,7 @@ /boards/nordic/nrf54l*/ @nrfconnect/ncs-co-boards @kl-cruz /boards/nordic/nrf52* @nrfconnect/ncs-co-boards @nrfconnect/ncs-si-bluebagel /boards/nordic/thingy91* @nrfconnect/ncs-co-boards @nrfconnect/ncs-cia +/boards/nordic/nrf54h20dk/ @nrfconnect/ncs-charon /boards/shields/coverage_support/ @nrfconnect/ncs-low-level-test /boards/shields/nrf2220ek/ @nrfconnect/ncs-radio-sw /boards/shields/nrf2240ek/ @nrfconnect/ncs-radio-sw @@ -345,6 +346,7 @@ /include/dfu/dfu_target_suit.h @nrfconnect/ncs-charon /include/dfu/suit_dfu_fetch_source.h @nrfconnect/ncs-charon /include/dfu/suit_dfu.h @nrfconnect/ncs-charon +/include/bl_partitions.h @nrfconnect/ncs-charon /include/drivers/flash/ @nrfconnect/ncs-co-drivers /include/drivers/flash/flash_ipuc.h @nrfconnect/ncs-co-drivers @nrfconnect/ncs-charon /include/drivers/gpio/ @nrfconnect/ncs-co-drivers @nrfconnect/ncs-ll-ursus @@ -688,6 +690,7 @@ /samples/zephyr/sensor/qdec/ @nrfconnect/ncs-low-level-test /samples/zephyr/subsys/settings/ @nrfconnect/ncs-low-level-test /samples/zephyr/subsys/usb/ @nrfconnect/ncs-low-level-test +/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/ @nrfconnect/ncs-charon /samples/**/*.svg @nrfconnect/ncs-doc-leads /samples/**/*.png @nrfconnect/ncs-doc-leads diff --git a/boards/nordic/nrf54h20dk/Kconfig.defconfig b/boards/nordic/nrf54h20dk/Kconfig.defconfig new file mode 100644 index 000000000000..b7b7732de430 --- /dev/null +++ b/boards/nordic/nrf54h20dk/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Nordic Semiconductor +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +if BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON_B0_MCUBOOT + +config ROM_START_OFFSET + default 0x800 if BOOTLOADER_MCUBOOT || (MCUBOOT && SECURE_BOOT) + +endif # BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON_B0_MCUBOOT diff --git a/boards/nordic/nrf54h20dk/Kconfig.nrf54h20dk b/boards/nordic/nrf54h20dk/Kconfig.nrf54h20dk new file mode 100644 index 000000000000..65334deb47c5 --- /dev/null +++ b/boards/nordic/nrf54h20dk/Kconfig.nrf54h20dk @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Nordic Semiconductor +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +config BOARD_NRF54H20DK + select SOC_NRF54H20_CPUAPP if (BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON_B0_MCUBOOT) + select SOC_NRF54H20_IRON if (BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON_B0_MCUBOOT) diff --git a/boards/nordic/nrf54h20dk/Kconfig.sysbuild b/boards/nordic/nrf54h20dk/Kconfig.sysbuild new file mode 100644 index 000000000000..43d58ed786dc --- /dev/null +++ b/boards/nordic/nrf54h20dk/Kconfig.sysbuild @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Nordic Semiconductor +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +config SECURE_BOOT_APPCORE + default y if BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON_B0_MCUBOOT + +choice BOOTLOADER + default BOOTLOADER_MCUBOOT if BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON_B0_MCUBOOT + +endchoice diff --git a/boards/nordic/nrf54h20dk/board.cmake b/boards/nordic/nrf54h20dk/board.cmake new file mode 100644 index 000000000000..9aae4be6c0df --- /dev/null +++ b/boards/nordic/nrf54h20dk/board.cmake @@ -0,0 +1,18 @@ +# +# Copyright (c) 2025 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake) + +if(CONFIG_BOARD_NRF54H20DK_NRF54H20_CPUAPP_IRON_B0_MCUBOOT) + if(CONFIG_SOC_NRF54H20_CPUAPP) + set(JLINKSCRIPTFILE ${CMAKE_CURRENT_LIST_DIR}/support/nrf54h20_cpuapp.JLinkScript) + else() + set(JLINKSCRIPTFILE ${CMAKE_CURRENT_LIST_DIR}/support/nrf54h20_cpurad.JLinkScript) + endif() + + board_runner_args(jlink "--device=CORTEX-M33" "--speed=4000" "--tool-opt=-jlinkscriptfile ${JLINKSCRIPTFILE}") + include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) +endif() diff --git a/boards/nordic/nrf54h20dk/board.yml b/boards/nordic/nrf54h20dk/board.yml new file mode 100644 index 000000000000..6977b24b4e57 --- /dev/null +++ b/boards/nordic/nrf54h20dk/board.yml @@ -0,0 +1,5 @@ +board: + extend: nrf54h20dk + variants: + - name: b0/mcuboot + qualifier: nrf54h20/cpuapp/iron diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-memory_map_iron_b0_mcuboot.dtsi b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-memory_map_iron_b0_mcuboot.dtsi new file mode 100644 index 000000000000..6f7ccc78f41a --- /dev/null +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-memory_map_iron_b0_mcuboot.dtsi @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + + +/* This file is to be merged with the original memory_map.dtsi in the future. + * The following nodes will be replaced: + */ +/delete-node/ &cpuapp_cpusec_ipc_shm; +/delete-node/ &cpuapp_cpusys_ipc_shm; +/delete-node/ &cpurad_cpusec_ipc_shm; +/delete-node/ &cpurad_cpusys_ipc_shm; +/delete-node/ &cpusec_cpuapp_ipc_shm; +/delete-node/ &cpusec_cpurad_ipc_shm; +/delete-node/ &cpusys_cpuapp_ipc_shm; +/delete-node/ &cpusys_cpurad_ipc_shm; +/delete-node/ &cpuapp_rw_partitions; +/delete-node/ &cpuapp_rx_partitions; +/delete-node/ &cpurad_rx_partitions; + +/ { + reserved-memory { + cpuapp_cpusys_ipc_shm: memory@2f88f600 { + reg = <0x2f88f600 0x80>; + }; + + cpusys_cpuapp_ipc_shm: memory@2f88f680 { + reg = <0x2f88f680 0x80>; + }; + + cpurad_cpusys_ipc_shm: memory@2f88f700 { + reg = <0x2f88f700 0x80>; + }; + + cpusys_cpurad_ipc_shm: memory@2f88f780 { + reg = <0x2f88f780 0x80>; + }; + + cpusec_cpurad_ipc_shm: memory@2f88f800 { + reg = <0x2f88f800 0x80>; + }; + + cpurad_ironside_se_event_report: memory@2f88f880 { + reg = <0x2f88f880 0x100>; + }; + + cpurad_ironside_se_boot_report: memory@2f88f980 { + reg = <0x2f88f980 0x200>; + }; + + cpusec_cpuapp_ipc_shm: memory@2f88fb80 { + reg = <0x2f88fb80 0x80>; + }; + + cpuapp_ironside_se_event_report: memory@2f88fc00 { + reg = <0x2f88fc00 0x100>; + }; + + cpuapp_ironside_se_boot_report: memory@2f88fd00 { + reg = <0x2f88fd00 0x200>; + }; + }; +}; + +&mram1x { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + cpuapp_b0_partition: partition@2c000 { + reg = <0x2c000 DT_SIZE_K(62)>; + }; + + cpuapp_provision_partition: partition@3b800 { + reg = <0x3b800 DT_SIZE_K(2)>; + }; + + cpuapp_s0_partition: partition@3c000 { + reg = <0x3c000 DT_SIZE_K(64)>; + }; + + cpuapp_s1_partition: partition@4c000 { + reg = <0x4c000 DT_SIZE_K(64)>; + }; + + cpuapp_slot0_partition: partition@5c000 { + reg = <0x5c000 DT_SIZE_K(336)>; + }; + + cpurad_slot0_partition: partition@b0000 { + reg = <0xb0000 DT_SIZE_K(272)>; + }; + + cpuppr_code_partition: partition@f4000 { + reg = <0xf4000 DT_SIZE_K(64)>; + }; + + cpuflpr_code_partition: partition@104000 { + reg = <0x104000 DT_SIZE_K(48)>; + }; + + cpuapp_slot1_partition: partition@110000 { + reg = <0x110000 DT_SIZE_K(336)>; + }; + + cpurad_slot1_partition: partition@164000 { + reg = <0x164000 DT_SIZE_K(272)>; + }; + + storage_partition: partition@1a8000 { + reg = <0x1a8000 DT_SIZE_K(40)>; + }; + }; +}; diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot.dts b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot.dts new file mode 100644 index 000000000000..27e8cb42186f --- /dev/null +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot.dts @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "../../../../zephyr/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp.dts" +#include "../../../../zephyr/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20-ipc_conf_iron.dtsi" +#include "nrf54h20dk_nrf54h20-memory_map_iron_b0_mcuboot.dtsi" + +/delete-node/ &cpusec_cpurad_ipc; + +/ { + chosen { + zephyr,code-partition = &slot0_partition; + zephyr,uart-mcumgr = &uart136; + }; +}; + +&cpusec_bellboard { + status = "okay"; +}; + +&cpusec_cpuapp_ipc { + mbox-names = "tx", "rx"; + status = "okay"; +}; + +b0_partition: &cpuapp_b0_partition { + label = "b0"; +}; + +provision_partition: &cpuapp_provision_partition { + label = "provision"; +}; + +s0_partition: &cpuapp_s0_partition { +}; + +s1_partition: &cpuapp_s1_partition { + label = "s1-image"; +}; + +slot0_partition: &cpuapp_slot0_partition { + label = "image-0"; +}; + +slot1_partition: &cpuapp_slot1_partition { + label = "image-1"; +}; + +boot_partition: &s0_partition { + label = "mcuboot"; +}; diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot_0_9_0.yaml b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot_0_9_0.yaml new file mode 100644 index 000000000000..6fe854fe20af --- /dev/null +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot_0_9_0.yaml @@ -0,0 +1,25 @@ +# Copyright (c) 2025 Nordic Semiconductor +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +identifier: nrf54h20dk/nrf54h20/cpuapp/iron/b0/mcuboot +name: nRF54H20-DK-nRF54H20-Application (IRONside compatible) with MCUBOOT and NSIB (revision 0.9.0) +type: mcu +arch: arm +toolchain: + - gnuarmemb + - xtools + - zephyr +sysbuild: true +ram: 256 +flash: 480 +supported: + - adc + - can + - counter + - gpio + - i2c + - pwm + - retained_mem + - spi + - watchdog + - usbd diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot_defconfig b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot_defconfig new file mode 100644 index 000000000000..f73f82c1e4a0 --- /dev/null +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot_defconfig @@ -0,0 +1,29 @@ +# Copyright (c) 2025 Nordic Semiconductor +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +# Enable UART driver +CONFIG_SERIAL=y + +# Enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable hardware stack protection +CONFIG_HW_STACK_PROTECTION=y + +# MPU-based null-pointer dereferencing detection cannot be applied +# as the (0x0 - 0x400) region is unmapped for this target. +CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y + +# Enable cache +CONFIG_CACHE_MANAGEMENT=y +CONFIG_EXTERNAL_CACHE=y + +# Enable GPIO +CONFIG_GPIO=y + +# UICR generation is not supported, and when reintroduced will not use nrf-regtool. +CONFIG_NRF_REGTOOL_GENERATE_UICR=n diff --git a/cmake/sysbuild/b0_mcuboot_signing.cmake b/cmake/sysbuild/b0_mcuboot_signing.cmake index ba30c21a1015..41ad341dc6c5 100644 --- a/cmake/sysbuild/b0_mcuboot_signing.cmake +++ b/cmake/sysbuild/b0_mcuboot_signing.cmake @@ -10,6 +10,8 @@ # Since this file is brought in via include(), we do the work in a # function to avoid polluting the top-level scope. +include(${CMAKE_CURRENT_LIST_DIR}/bootloader_dts_utils.cmake) + function(ncs_secure_boot_mcuboot_sign application bin_files signed_targets prefix) find_program(IMGTOOL imgtool.py HINTS ${ZEPHYR_MCUBOOT_MODULE_DIR}/scripts/ NAMES imgtool NAMES_PER_DIR) set(keyfile "${SB_CONFIG_BOOT_SIGNATURE_KEY_FILE}") @@ -26,7 +28,20 @@ function(ncs_secure_boot_mcuboot_sign application bin_files signed_targets prefi sysbuild_get(CONFIG_BUILD_OUTPUT_HEX IMAGE ${application} VAR CONFIG_BUILD_OUTPUT_HEX KCONFIG) string(TOUPPER "${application}" application_uppercase) - set(imgtool_sign ${PYTHON_EXECUTABLE} ${IMGTOOL} sign --version ${SB_CONFIG_SECURE_BOOT_MCUBOOT_VERSION} --align 4 --slot-size $ --pad-header --header-size ${SB_CONFIG_PM_MCUBOOT_PAD}) + if(SB_CONFIG_PARTITION_MANAGER) + set(slot_size $) + set(mcuboot_pad ${SB_CONFIG_PM_MCUBOOT_PAD}) + set(pad_header "--pad-header") + else() + dt_chosen(code_partition_node TARGET ${application} PROPERTY "zephyr,code-partition") + dt_reg_size(slot_size TARGET ${application} PATH ${code_partition_node}) + sysbuild_get(mcuboot_pad IMAGE ${application} VAR CONFIG_ROM_START_OFFSET KCONFIG) + + # The padding has already been added to the image by CONFIG_ROM_START_OFFSET + set(pad_header) + endif() + + set(imgtool_sign ${PYTHON_EXECUTABLE} ${IMGTOOL} sign --version ${SB_CONFIG_SECURE_BOOT_MCUBOOT_VERSION} --align 4 --slot-size ${slot_size} ${pad_header} --header-size ${mcuboot_pad}) if(SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) set(imgtool_extra --security-counter ${SB_CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_VALUE}) @@ -101,6 +116,11 @@ function(ncs_secure_boot_mcuboot_sign application bin_files signed_targets prefi ${application_image_dir}/zephyr/.config ${CMAKE_BINARY_DIR}/signed_by_b0_${application}.hex ) + + set_property( + GLOBAL APPEND PROPERTY NORDIC_SECURE_BOOT_HEX_FILES_TO_MERGE + ${output}.hex + ) endif() # Add the west sign calls and their byproducts to the post-processing @@ -132,7 +152,12 @@ if(SB_CONFIG_BOOTLOADER_MCUBOOT) if(SB_CONFIG_SECURE_BOOT_BUILD_S1_VARIANT_IMAGE) ncs_secure_boot_mcuboot_sign(s1_image "${bin_files}" "${signed_targets}" "") - set(extra_bin_data "signed_by_mcuboot_and_b0_s1_image.binload_address=$;signed_by_mcuboot_and_b0_s1_image.binslot=1") + if(SB_CONFIG_PARTITION_MANAGER) + set(slot1_addr $) + else() + nsib_get_s1_address(slot1_addr) + endif() + set(extra_bin_data "signed_by_mcuboot_and_b0_s1_image.binload_address=${slot1_addr};signed_by_mcuboot_and_b0_s1_image.binslot=1") endif() if(bin_files) @@ -140,13 +165,19 @@ if(SB_CONFIG_BOOTLOADER_MCUBOOT) include(${ZEPHYR_NRF_MODULE_DIR}/cmake/fw_zip.cmake) + if(SB_CONFIG_PARTITION_MANAGER) + set(slot0_addr $) + else() + nsib_get_s0_address(slot0_addr) + endif() + generate_dfu_zip( OUTPUT ${CMAKE_BINARY_DIR}/dfu_mcuboot.zip BIN_FILES ${bin_files} TYPE mcuboot IMAGE mcuboot SCRIPT_PARAMS - "signed_by_mcuboot_and_b0_mcuboot.binload_address=$" + "signed_by_mcuboot_and_b0_mcuboot.binload_address=${slot0_addr}" ${extra_bin_data} "version_MCUBOOT=${SB_CONFIG_SECURE_BOOT_MCUBOOT_VERSION}" "version_B0=${mcuboot_fw_info_firmware_version}" diff --git a/cmake/sysbuild/bootloader_dts_utils.cmake b/cmake/sysbuild/bootloader_dts_utils.cmake new file mode 100644 index 000000000000..f16006494cbe --- /dev/null +++ b/cmake/sysbuild/bootloader_dts_utils.cmake @@ -0,0 +1,137 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + +# This file contains utility functions used for handling +# data coming from the devicetree for configurations using +# a bootloader. +# It contains helper functions used to get the addresses of +# specific bootloader patitions as well as +# functions that are used to verify the +# that devicetrees of the images are consistent with each other +# and with the current bootloader configuration. + +function(get_address_from_dt_partition_nodelabel label address) + dt_nodelabel(partition_node TARGET ${DEFAULT_IMAGE} NODELABEL ${label} REQUIRED) + dt_reg_addr(partition_offset TARGET ${DEFAULT_IMAGE} PATH ${partition_node}) + + # Get the parent "two levels up" (../../) of the partition node + # This is the partition flash area node + string(REPLACE "/" ";" partition_node_split ${partition_node}) + list(LENGTH partition_node_split child_path_length) + math(EXPR parent_path_length "${child_path_length} - 2") + list(SUBLIST partition_node_split 0 ${parent_path_length} parent_path_split) + string(REPLACE ";" "/" flash_area_node "${parent_path_split}") + + dt_reg_addr(flash_area_addr TARGET ${DEFAULT_IMAGE} PATH ${flash_area_node}) + + math(EXPR ${address} "${flash_area_addr} + ${partition_offset}") + set(${address} ${${address}} PARENT_SCOPE) +endfunction() + +# +# Verify that the code partition for a given image matches a specific node label. +# +function(code_partition_matches_label_verify label image) + dt_nodelabel(label_node TARGET ${image} NODELABEL ${label}) + dt_chosen(code_partition_node TARGET ${image} PROPERTY "zephyr,code-partition") + + if (NOT "${code_partition_node}" STREQUAL "${label_node}") + message(FATAL_ERROR " + ERROR: zephyr,code-partition for image ${image} + does not match label ${label}. + This is required by the current bootloader configuration. + zephyr,code-partition node: + ${code_partition_node} + ${label} node: + ${label_node} + \n" + ) + endif() +endfunction() + +# +# Verify that the required node labels for all images point to the same nodes +# as for the default image +# +function(labels_match_for_all_images_verify labels) + foreach(label ${labels}) + dt_nodelabel(default_image_node TARGET ${DEFAULT_IMAGE} NODELABEL ${label} REQUIRED) + foreach(image ${IMAGES}) + dt_nodelabel(node TARGET ${image} NODELABEL ${label} REQUIRED) + if (NOT "${node}" STREQUAL "${default_image_node}") + message(FATAL_ERROR " + ERROR: Node pointed by ${label} for image ${image} + does not match the node for the default image ${DEFAULT_IMAGE}. + Node for default image ${DEFAULT_IMAGE}: ${default_image_node} + Node for image ${image}: ${label_node} + \n" + ) + endif() + endforeach() + endforeach() +endfunction() + +function(verify_bootloader_dts_configuration) + set(required_labels_list) + set(nordic_bootloader_vars_names) + + # Create a list of all devicetree labels that are required for + # the current bootloader configuration. + if(SB_CONFIG_SECURE_BOOT) + list(APPEND required_labels_list "b0_partition" "provision_partition" "s0_partition") + endif() + if(SB_CONFIG_BOOTLOADER_MCUBOOT) + list(APPEND required_labels_list "boot_partition") + list(APPEND required_labels_list "slot0_partition") + list(APPEND required_labels_list "slot1_partition") + endif() + if(SB_CONFIG_SECURE_BOOT_BUILD_S1_VARIANT_IMAGE) + list(APPEND required_labels_list "s1_partition") + endif() + + # Check that the labels are present for all images and that they point to the same nodes + # for each of the images. + # This way we can treat a devicetree from any of the images as the source of truth for + # the whole system when it comes to the required node labels. + labels_match_for_all_images_verify("${required_labels_list}") + + # Verify that the zephyr,code-partition chosen node for each of the images + # points to the expected node labels + if(SB_CONFIG_BOOTLOADER_MCUBOOT) + code_partition_matches_label_verify("slot0_partition" "${DEFAULT_IMAGE}") + elseif(SB_CONFIG_SECURE_BOOT) + code_partition_matches_label_verify("s0_partition" "${DEFAULT_IMAGE}") + endif() + + if(SB_CONFIG_SECURE_BOOT) + code_partition_matches_label_verify("b0_partition" "b0") + endif() + if(SB_CONFIG_SECURE_BOOT_BUILD_S1_VARIANT_IMAGE) + code_partition_matches_label_verify("s1_partition" "s1_image") + endif() + + if(SB_CONFIG_BOOTLOADER_MCUBOOT) + code_partition_matches_label_verify("boot_partition" "mcuboot") + if(SB_CONFIG_SECURE_BOOT) + # In the B0 + MCUBOOT configuration s0_partition points to boot_partition + code_partition_matches_label_verify("s0_partition" "mcuboot") + endif() + endif() +endfunction() + +function(nsib_get_s0_address address) + set(s0_label "s0_partition") + get_address_from_dt_partition_nodelabel(${s0_label} ${address}) + set(${address} ${${address}} PARENT_SCOPE) +endfunction() + +function(nsib_get_s1_address address) + set(s1_label "s1_partition") + get_address_from_dt_partition_nodelabel(${s1_label} ${address}) + set(${address} ${${address}} PARENT_SCOPE) +endfunction() + +function(nsib_get_provision_address address) + get_address_from_dt_partition_nodelabel("provision_partition" ${address}) + set(${address} ${${address}} PARENT_SCOPE) +endfunction() diff --git a/cmake/sysbuild/image_signing.cmake b/cmake/sysbuild/image_signing.cmake index 485a19b9167d..98e015f53982 100644 --- a/cmake/sysbuild/image_signing.cmake +++ b/cmake/sysbuild/image_signing.cmake @@ -58,7 +58,7 @@ function(zephyr_mcuboot_tasks) # Fetch devicetree details for flash and slot information dt_chosen(flash_node PROPERTY "zephyr,flash") dt_nodelabel(slot0_flash NODELABEL "slot0_partition" REQUIRED) - dt_prop(slot_size PATH "${slot0_flash}" PROPERTY "reg" INDEX 1 REQUIRED) + dt_reg_size(slot_size PATH "${slot0_flash}" REQUIRED) dt_prop(write_block_size PATH "${flash_node}" PROPERTY "write-block-size") if(NOT write_block_size) @@ -81,13 +81,17 @@ function(zephyr_mcuboot_tasks) endif() endif() - # Split fields, imgtool_sign_sysbuild is stored in cache which will have fields updated by - # sysbuild, imgtool_sign must not be stored in cache because it would then prevent those fields - # from being updated without a pristine build - # TODO: NCSDK-28461 sysbuild PM fields cannot be updated without a pristine build, will become - # invalid if a static PM file is updated without pristine build - set(imgtool_sign_sysbuild --slot-size @PM_MCUBOOT_PRIMARY_SIZE@ --pad-header --header-size @PM_MCUBOOT_PAD_SIZE@ ${imgtool_rom_command} CACHE STRING "imgtool sign sysbuild replacement") - set(imgtool_sign ${PYTHON_EXECUTABLE} ${IMGTOOL} sign --version ${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION} --align ${write_block_size} ${imgtool_sign_sysbuild}) + if(CONFIG_PARTITION_MANAGER_ENABLED) + # Split fields, imgtool_sign_sysbuild is stored in cache which will have fields updated by + # sysbuild, imgtool_sign must not be stored in cache because it would then prevent those fields + # from being updated without a pristine build + # TODO: NCSDK-28461 sysbuild PM fields cannot be updated without a pristine build, will become + # invalid if a static PM file is updated without pristine build + set(imgtool_sign_sysbuild --slot-size @PM_MCUBOOT_PRIMARY_SIZE@ --pad-header --header-size @PM_MCUBOOT_PAD_SIZE@ ${imgtool_rom_command} CACHE STRING "imgtool sign sysbuild replacement") + set(imgtool_sign ${PYTHON_EXECUTABLE} ${IMGTOOL} sign --version ${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION} --align ${write_block_size} ${imgtool_sign_sysbuild}) + else() + set(imgtool_sign ${PYTHON_EXECUTABLE} ${IMGTOOL} sign --version ${CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION} --align ${write_block_size} --slot-size ${slot_size} --header-size ${CONFIG_ROM_START_OFFSET} ${imgtool_rom_command}) + endif() # Arguments to imgtool. if(NOT CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS STREQUAL "") diff --git a/cmake/sysbuild/provision_hex.cmake b/cmake/sysbuild/provision_hex.cmake index d8002fc33a42..f43f92f2da93 100644 --- a/cmake/sysbuild/provision_hex.cmake +++ b/cmake/sysbuild/provision_hex.cmake @@ -9,6 +9,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/sign.cmake) include(${CMAKE_CURRENT_LIST_DIR}/debug_keys.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/bootloader_dts_utils.cmake) function(provision application prefix_name) ExternalProject_Get_Property(${application} BINARY_DIR) @@ -18,7 +19,8 @@ function(provision application prefix_name) set(PROVISION_HEX_NAME ${prefix_name}provision.hex) set(PROVISION_HEX ${CMAKE_BINARY_DIR}/${PROVISION_HEX_NAME}) - if(CONFIG_SOC_SERIES_NRF54LX) + # TODO: decide on the OTP word size for nRF54H + if(CONFIG_SOC_SERIES_NRF54LX OR CONFIG_SOC_SERIES_NRF54HX) set(otp_write_width 4) # OTP writes are in words (4 bytes) else() set(otp_write_width 2) # OTP writes are in half-words (2 bytes) @@ -31,8 +33,7 @@ function(provision application prefix_name) endif() # Skip signing if MCUBoot is to be booted and its not built from source - if((CONFIG_SB_VALIDATE_FW_SIGNATURE OR CONFIG_SB_VALIDATE_FW_HASH) AND - NCS_SYSBUILD_PARTITION_MANAGER) + if(CONFIG_SB_VALIDATE_FW_SIGNATURE OR CONFIG_SB_VALIDATE_FW_HASH) if (${SB_CONFIG_SECURE_BOOT_DEBUG_SIGNATURE_PUBLIC_KEY_LAST}) message(WARNING @@ -61,17 +62,32 @@ function(provision application prefix_name) ) endif() - # Adjustment to be able to load into sysbuild - if(CONFIG_SOC_NRF5340_CPUNET OR "${domain}" STREQUAL "CPUNET") - set(partition_manager_target partition_manager_CPUNET) - set(s0_arg --s0-addr $) - set(s1_arg) - set(cpunet_target y) - else() - set(partition_manager_target partition_manager) - set(s0_arg --s0-addr $) - set(s1_arg --s1-addr $) + if(CONFIG_PARTITION_MANAGER_ENABLED) + get_property(TARGETS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS) + # Adjustment to be able to load into sysbuild + if(CONFIG_SOC_NRF5340_CPUNET OR "${domain}" STREQUAL "CPUNET") + set(partition_manager_target partition_manager_CPUNET) + set(s0_arg --s0-addr $) + set(s1_arg) + set(cpunet_target y) + else() + set(partition_manager_target partition_manager) + set(s0_arg --s0-addr $) + set(s1_arg --s1-addr $) + set(cpunet_target n) + endif() + set(provision_arg --provision-addr $) + elseif(CONFIG_SOC_SERIES_NRF54HX) + nsib_get_provision_address(provision_addr) + nsib_get_s0_address(s0_addr) + nsib_get_s1_address(s1_addr) + set(s0_arg --s0-addr ${s0_addr}) + set(s1_arg --s1-addr ${s1_addr}) + set(provision_arg --provision-addr ${provision_addr}) + set(cpunet_target n) + else() + message(FATAL_ERROR "NSIB without partition manager is currently only supported for nRF54H.") endif() if(SB_CONFIG_SECURE_BOOT_DEBUG_NO_VERIFY_HASHES) @@ -101,7 +117,7 @@ function(provision application prefix_name) ${ZEPHYR_NRF_MODULE_DIR}/scripts/bootloader/provision.py ${s0_arg} ${s1_arg} - --provision-addr $ + ${provision_arg} ${public_keys_file_arg} --output ${PROVISION_HEX} --max-size ${CONFIG_PM_PARTITION_SIZE_PROVISION} @@ -144,57 +160,62 @@ function(provision application prefix_name) ) endif() - add_custom_target( - ${prefix_name}provision_target - DEPENDS - ${PROVISION_HEX} - ${PROVISION_DEPENDS} - ) - - get_property( - ${prefix_name}provision_set - GLOBAL PROPERTY ${prefix_name}provision_PM_HEX_FILE SET - ) - - if(NOT ${prefix_name}provision_set) - # Set hex file and target for the 'provision' placeholder partition. - # This includes the hex file (and its corresponding target) to the build. - set_property( - GLOBAL PROPERTY - ${prefix_name}provision_PM_HEX_FILE + if(CONFIG_PARTITION_MANAGER_ENABLED) + add_custom_target( + ${prefix_name}provision_target + DEPENDS ${PROVISION_HEX} + ${PROVISION_DEPENDS} ) - set_property( - GLOBAL PROPERTY - ${prefix_name}provision_PM_TARGET - ${prefix_name}provision_target + get_property( + ${prefix_name}provision_set + GLOBAL PROPERTY ${prefix_name}provision_PM_HEX_FILE SET ) + + if(NOT ${prefix_name}provision_set) + # Set hex file and target for the 'provision' placeholder partition. + # This includes the hex file (and its corresponding target) to the build. + set_property( + GLOBAL PROPERTY + ${prefix_name}provision_PM_HEX_FILE + ${PROVISION_HEX} + ) + + set_property( + GLOBAL PROPERTY + ${prefix_name}provision_PM_TARGET + ${prefix_name}provision_target + ) + endif() + else() + set_property( + GLOBAL APPEND PROPERTY NORDIC_SECURE_BOOT_HEX_FILES_TO_MERGE + ${PROVISION_HEX} + ) endif() endfunction() -if(NCS_SYSBUILD_PARTITION_MANAGER) - b0_gen_keys() +b0_gen_keys() - # Get the main app of the domain that secure boot should handle. - if(SB_CONFIG_SECURE_BOOT AND SB_CONFIG_SECURE_BOOT_APPCORE) - if(SB_CONFIG_BOOTLOADER_MCUBOOT) - provision("mcuboot" "app_") - else() - provision("${DEFAULT_IMAGE}" "app_") - endif() - elseif(SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) +# Get the main app of the domain that secure boot should handle. +if(SB_CONFIG_SECURE_BOOT AND SB_CONFIG_SECURE_BOOT_APPCORE) + if(SB_CONFIG_BOOTLOADER_MCUBOOT) + provision("mcuboot" "app_") + else() provision("${DEFAULT_IMAGE}" "app_") endif() +elseif(SB_CONFIG_MCUBOOT_HARDWARE_DOWNGRADE_PREVENTION) + provision("${DEFAULT_IMAGE}" "app_") +endif() - if(SB_CONFIG_SECURE_BOOT_NETCORE) - get_property(main_app GLOBAL PROPERTY DOMAIN_APP_CPUNET) - - if(NOT main_app) - message(FATAL_ERROR "Secure boot is enabled on domain CPUNET" - " but no image is selected for this domain.") - endif() +if(SB_CONFIG_SECURE_BOOT_NETCORE) + get_property(main_app GLOBAL PROPERTY DOMAIN_APP_CPUNET) - provision("${main_app}" "net_") + if(NOT main_app) + message(FATAL_ERROR "Secure boot is enabled on domain CPUNET" + " but no image is selected for this domain.") endif() + + provision("${main_app}" "net_") endif() diff --git a/cmake/sysbuild/secureboot_merge.cmake b/cmake/sysbuild/secureboot_merge.cmake new file mode 100644 index 000000000000..23083bcc0e0a --- /dev/null +++ b/cmake/sysbuild/secureboot_merge.cmake @@ -0,0 +1,61 @@ +# +# Copyright (c) 2025 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +function(update_runner) + cmake_parse_arguments(RUNNER "" "IMAGE;HEX" "" ${ARGN}) + + check_arguments_required("update_runner" RUNNER IMAGE) + check_arguments_required("update_runner" RUNNER HEX) + + get_target_property(bin_dir ${RUNNER_IMAGE} _EP_BINARY_DIR) + set(runners_file ${bin_dir}/zephyr/runners.yaml) + + set(runners_content_update) + file(STRINGS ${runners_file} runners_content) + foreach(line IN LISTS runners_content) + if("${line}" MATCHES "^.*hex_file: .*$") + string(REGEX REPLACE "(.*hex_file:) .*" "\\1 ${RUNNER_HEX}" line ${line}) + set(${RUNNER_IMAGE}_NCS_RUNNER_HEX "${RUNNER_HEX}" CACHE INTERNAL + "nRF Connect SDK NSIB controlled hex file" + ) + endif() + list(APPEND runners_content_update "${line}\n") + endforeach() + file(WRITE ${runners_file} ${runners_content_update}) + + # NCS has updated the cache with an NCS_RUNNER file, thus re-create the sysbuild cache. + # No need for CMAKE_RERUN in this case, as runners.yaml has been updated above. + sysbuild_cache(CREATE APPLICATION ${RUNNER_IMAGE}) +endfunction() + +get_property( + hex_files_to_merge + GLOBAL PROPERTY + NORDIC_SECURE_BOOT_HEX_FILES_TO_MERGE +) + +sysbuild_get(BINARY_DIR IMAGE b0 VAR APPLICATION_BINARY_DIR CACHE) +sysbuild_get(BINARY_FILE IMAGE b0 VAR CONFIG_KERNEL_BIN_NAME KCONFIG) +list(APPEND hex_files_to_merge ${BINARY_DIR}/zephyr/${BINARY_FILE}.hex) + +if(SB_CONFIG_BOOTLOADER_MCUBOOT) + sysbuild_get(default_image_hex IMAGE ${DEFAULT_IMAGE} VAR BYPRODUCT_KERNEL_SIGNED_HEX_NAME CACHE) + list(APPEND hex_files_to_merge ${default_image_hex}) +endif() + +add_custom_target( + create_secure_boot_merged_hex + ALL + COMMAND + ${PYTHON_EXECUTABLE} + ${ZEPHYR_BASE}/scripts/build/mergehex.py + -o ${CMAKE_BINARY_DIR}/merged.hex + ${hex_files_to_merge} + DEPENDS + ${hex_files_to_merge} +) + +update_runner(IMAGE ${DEFAULT_IMAGE} HEX ${CMAKE_BINARY_DIR}/merged.hex) diff --git a/cmake/sysbuild/sign.cmake b/cmake/sysbuild/sign.cmake index ceae91bc6a5e..2feea1ccaf23 100644 --- a/cmake/sysbuild/sign.cmake +++ b/cmake/sysbuild/sign.cmake @@ -96,42 +96,48 @@ function(b0_sign_image slot cpunet_target) set(signed_hex ${CMAKE_BINARY_DIR}/signed_by_b0_${slot}.hex) set(signed_bin ${CMAKE_BINARY_DIR}/signed_by_b0_${slot}.bin) - if(NCS_SYSBUILD_PARTITION_MANAGER) - # A container can be merged, in which case we should use old style below, - # or it may be an actual image, where we know everything. - # Initial support disregards the merged hex files. - # In parent-child, everything is merged, even when having a single image in a - # container (where the original image == the merged image). - if(TARGET ${slot}) - # If slot is a target of it's own, then it means we target the hex directly and not a merged hex. - sysbuild_get(${slot}_image_dir IMAGE ${slot} VAR APPLICATION_BINARY_DIR CACHE) - sysbuild_get(${slot}_kernel_name IMAGE ${slot} VAR CONFIG_KERNEL_BIN_NAME KCONFIG) - sysbuild_get(${slot}_kernel_elf IMAGE ${slot} VAR CONFIG_KERNEL_ELF_NAME KCONFIG) - sysbuild_get(${slot}_crypto_id IMAGE ${slot} VAR CONFIG_SB_VALIDATION_INFO_CRYPTO_ID KCONFIG) - sysbuild_get(${slot}_validation_offset IMAGE ${slot} VAR CONFIG_SB_VALIDATION_METADATA_OFFSET KCONFIG) - - set(slot_bin ${${slot}_image_dir}/zephyr/${${slot}_kernel_name}.bin) - set(slot_hex ${${slot}_image_dir}/zephyr/${${slot}_kernel_name}.hex) - set(sign_depends ${${slot}_image_dir}/zephyr/${${slot}_kernel_name}.elf) - set(target_name ${slot}) - elseif("${slot}" STREQUAL "s0_image") - if(SB_CONFIG_BOOTLOADER_MCUBOOT) - set(target_name mcuboot) - else() - set(target_name ${DEFAULT_IMAGE}) - endif() - - sysbuild_get(${target_name}_image_dir IMAGE ${target_name} VAR APPLICATION_BINARY_DIR CACHE) - sysbuild_get(${target_name}_kernel_name IMAGE ${target_name} VAR CONFIG_KERNEL_BIN_NAME KCONFIG) - sysbuild_get(${slot}_crypto_id IMAGE ${target_name} VAR CONFIG_SB_VALIDATION_INFO_CRYPTO_ID KCONFIG) - sysbuild_get(${slot}_validation_offset IMAGE ${target_name} VAR CONFIG_SB_VALIDATION_METADATA_OFFSET KCONFIG) - - set(slot_bin ${${target_name}_image_dir}/zephyr/${${target_name}_kernel_name}.bin) - set(slot_hex ${${target_name}_image_dir}/zephyr/${${target_name}_kernel_name}.hex) - set(sign_depends ${target_name} ${${target_name}_image_dir}/zephyr/${${target_name}_kernel_name}.elf) + # A container can be merged, in which case we should use old style below, + # or it may be an actual image, where we know everything. + # Initial support disregards the merged hex files. + # In parent-child, everything is merged, even when having a single image in a + # container (where the original image == the merged image). + if(TARGET ${slot}) + # If slot is a target of it's own, then it means we target the hex directly and not a merged hex. + sysbuild_get(${slot}_image_dir IMAGE ${slot} VAR APPLICATION_BINARY_DIR CACHE) + sysbuild_get(${slot}_kernel_name IMAGE ${slot} VAR CONFIG_KERNEL_BIN_NAME KCONFIG) + sysbuild_get(${slot}_kernel_elf IMAGE ${slot} VAR CONFIG_KERNEL_ELF_NAME KCONFIG) + sysbuild_get(${slot}_crypto_id IMAGE ${slot} VAR CONFIG_SB_VALIDATION_INFO_CRYPTO_ID KCONFIG) + sysbuild_get(${slot}_validation_offset IMAGE ${slot} VAR CONFIG_SB_VALIDATION_METADATA_OFFSET KCONFIG) + if(NOT CONFIG_PARTITION_MANAGER_ENABLED) + sysbuild_get(input_data_start_offset_hex IMAGE ${slot} VAR CONFIG_ROM_START_OFFSET KCONFIG) + # CONFIG_ROM_START_OFFSET is a hex string, we need to convert it to a decimal integer + math(EXPR ${slot}_input_data_start_offset "${input_data_start_offset_hex}") + endif() + + set(slot_bin ${${slot}_image_dir}/zephyr/${${slot}_kernel_name}.bin) + set(slot_hex ${${slot}_image_dir}/zephyr/${${slot}_kernel_name}.hex) + set(sign_depends ${${slot}_image_dir}/zephyr/${${slot}_kernel_name}.elf) + set(target_name ${slot}) + elseif("${slot}" STREQUAL "s0_image") + if(SB_CONFIG_BOOTLOADER_MCUBOOT) + set(target_name mcuboot) else() - message(FATAL_ERROR "Not supported") + set(target_name ${DEFAULT_IMAGE}) + endif() + + sysbuild_get(${target_name}_image_dir IMAGE ${target_name} VAR APPLICATION_BINARY_DIR CACHE) + sysbuild_get(${target_name}_kernel_name IMAGE ${target_name} VAR CONFIG_KERNEL_BIN_NAME KCONFIG) + sysbuild_get(${slot}_crypto_id IMAGE ${target_name} VAR CONFIG_SB_VALIDATION_INFO_CRYPTO_ID KCONFIG) + sysbuild_get(${slot}_validation_offset IMAGE ${target_name} VAR CONFIG_SB_VALIDATION_METADATA_OFFSET KCONFIG) + if(NOT CONFIG_PARTITION_MANAGER_ENABLED) + sysbuild_get(input_data_start_offset_hex IMAGE ${target_name} VAR CONFIG_ROM_START_OFFSET KCONFIG) + # CONFIG_ROM_START_OFFSET is a hex string, we need to convert it to a decimal integer + math(EXPR ${slot}_input_data_start_offset "${input_data_start_offset_hex}") endif() + + set(slot_bin ${${target_name}_image_dir}/zephyr/${${target_name}_kernel_name}.bin) + set(slot_hex ${${target_name}_image_dir}/zephyr/${${target_name}_kernel_name}.hex) + set(sign_depends ${target_name} ${${target_name}_image_dir}/zephyr/${${target_name}_kernel_name}.elf) else() message(FATAL_ERROR "Not supported") endif() @@ -164,10 +170,16 @@ function(b0_sign_image slot cpunet_target) if(sign_cmd_hash_type) set(to_sign ${slot_hex}) + if(NOT CONFIG_PARTITION_MANAGER_ENABLED) + set(sign_start_offset_arg --start-offset ${${slot}_input_data_start_offset}) + else() + set(sign_start_offset_arg) + endif() set(hash_cmd ${PYTHON_EXECUTABLE} ${ZEPHYR_NRF_MODULE_DIR}/scripts/bootloader/hash.py --in ${to_sign} ${hash_cmd_type} + ${sign_start_offset_arg} > ${hash_file} ) endif() @@ -178,12 +190,18 @@ function(b0_sign_image slot cpunet_target) else() set(sign_cmd_signature_type) endif() + if(NOT sign_cmd_hash_type AND NOT CONFIG_PARTITION_MANAGER_ENABLED) + set(sign_start_offset_arg --start-offset ${${slot}_input_data_start_offset}) + else() + set(sign_start_offset_arg) + endif() set(sign_cmd ${PYTHON_EXECUTABLE} ${ZEPHYR_NRF_MODULE_DIR}/scripts/bootloader/do_sign.py --private-key ${SIGNATURE_PRIVATE_KEY_FILE} --in ${hash_file} ${sign_cmd_signature_type} + ${sign_start_offset_arg} > ${signature_file} ) elseif(SB_CONFIG_SECURE_BOOT_SIGNING_OPENSSL) @@ -269,6 +287,12 @@ function(b0_sign_image slot cpunet_target) set(validation_signature_cmd) endif() + if(NOT CONFIG_PARTITION_MANAGER_ENABLED) + set(input_data_offset_arg --input-data-offset ${${slot}_input_data_start_offset}) + else() + set(input_data_offset_arg) + endif() + add_custom_command( OUTPUT ${signed_hex} @@ -283,6 +307,7 @@ function(b0_sign_image slot cpunet_target) --signature ${signature_file} --public-key ${SIGNATURE_PUBLIC_KEY_FILE} --magic-value "${VALIDATION_INFO_MAGIC}" + ${input_data_offset_arg} DEPENDS ${SIGN_KEY_FILE_DEPENDS} ${signature_file} @@ -303,17 +328,26 @@ function(b0_sign_image slot cpunet_target) signature_public_key_file_target ) - # Set hex file and target for the ${slot) (s0/s1) container partition. - # This includes the hex file (and its corresponding target) to the build. - set_property( - GLOBAL PROPERTY - ${target_name}_PM_HEX_FILE - ${signed_hex} - ) + if(CONFIG_PARTITION_MANAGER_ENABLED) + # Set hex file and target for the ${slot) (s0/s1) container partition. + # This includes the hex file (and its corresponding target) to the build. + set_property( + GLOBAL PROPERTY + ${target_name}_PM_HEX_FILE + ${signed_hex} + ) - set_property( - GLOBAL PROPERTY - ${target_name}_PM_TARGET - ${slot}_signed_kernel_hex_target - ) + set_property( + GLOBAL PROPERTY + ${target_name}_PM_TARGET + ${slot}_signed_kernel_hex_target + ) + else() + if(NOT SB_CONFIG_BOOTLOADER_MCUBOOT) + set_property( + GLOBAL APPEND PROPERTY NORDIC_SECURE_BOOT_HEX_FILES_TO_MERGE + ${signed_hex} + ) + endif() + endif() endfunction() diff --git a/include/bl_partitions.h b/include/bl_partitions.h new file mode 100644 index 000000000000..7d66830f5fad --- /dev/null +++ b/include/bl_partitions.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef BL_PARTITIONS_H +#define BL_PARTITIONS_H + +#if defined(CONFIG_PARTITION_MANAGER_ENABLED) + +#include +#define NSIB_B0_ADDRESS PM_B0_ADDRESS +#define NSIB_B0_SIZE PM_B0_SIZE +#define NSIB_PROVISION_ADDRESS PM_PROVISION_ADDRESS +#define NSIB_PROVISION_SIZE PM_PROVISION_SIZE + +#if defined(PM_S0_ADDRESS) +#define NSIB_S0_ADDRESS PM_S0_ADDRESS +#define NSIB_S0_SIZE PM_S0_SIZE +#endif +#if defined(PM_S1_ADDRESS) +#define NSIB_S1_ADDRESS PM_S1_ADDRESS +#define NSIB_S1_SIZE PM_S1_SIZE +#endif + +#else /* defined(CONFIG_PARTITION_MANAGER_ENABLED) */ + +#define NSIB_B0_CONTAINER_NODE B0 DT_GPARENT(DT_NODELABEL(b0_partition)) +#define NSIB_B0_CONTAINER_ADDRESS DT_REG_ADDR(NSIB_B0_CONTAINER_NODE) +#define NSIB_B0_CONTAINER_SIZE DT_REG_SIZE(SOC_NV_FLASH_NODE_B0) +#define NSIB_B0_OFFSET DT_REG_ADDR(DT_NODELABEL(b0_partition)) +#define NSIB_B0_ADDRESS (NSIB_B0_CONTAINER_ADDRESS + NSIB_B0_OFFSET) +#define NSIB_B0_SIZE DT_REG_SIZE(DT_NODELABEL(b0_partition)) + +#define NSIB_PROVISION_CONTAINER_NODE DT_GPARENT(DT_NODELABEL(provision_partition)) +#define NSIB_PROVISION_CONTAINER_ADDRESS DT_REG_ADDR(NSIB_PROVISION_CONTAINER_NODE) +#define NSIB_PROVISION_OFFSET DT_REG_ADDR(DT_NODELABEL(provision_partition)) +#define NSIB_PROVISION_ADDRESS (NSIB_PROVISION_CONTAINER_ADDRESS + NSIB_PROVISION_OFFSET) +#define NSIB_PROVISION_SIZE DT_REG_SIZE(DT_NODELABEL(provision_partition)) + +#define NSIB_S0_SIZE DT_REG_SIZE(DT_NODELABEL(s0_partition)) +#define NSIB_S1_SIZE DT_REG_SIZE(DT_NODELABEL(s1_partition)) + +#endif /* defined(CONFIG_PARTITION_MANAGER_ENABLED) */ + +#endif /* BL_PARTITIONS_H */ diff --git a/include/bl_storage.h b/include/bl_storage.h index 1a9c26657afc..e096e2eccdf4 100644 --- a/include/bl_storage.h +++ b/include/bl_storage.h @@ -15,11 +15,13 @@ #include #elif defined(CONFIG_NRFX_RRAMC) #include +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) +/* No includes needed */ #else #error "No NRFX storage technology supported backend selected" #endif #include -#include +#include #ifdef __cplusplus @@ -35,6 +37,10 @@ typedef uint16_t lcs_reserved_t; typedef uint32_t counter_t; typedef uint32_t lcs_data_t; typedef uint32_t lcs_reserved_t; +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) +typedef uint32_t counter_t; +typedef uint32_t lcs_data_t; +typedef uint32_t lcs_reserved_t; #endif #define EHASHFF 113 /* A hash contains too many 0xFs. */ @@ -173,7 +179,7 @@ struct bl_storage_data { */ }; -#define BL_STORAGE ((const volatile struct bl_storage_data *)(PM_PROVISION_ADDRESS)) +#define BL_STORAGE ((const volatile struct bl_storage_data *)(NSIB_PROVISION_ADDRESS)) /* This must be 32 bytes according to the IETF PSA token specification */ #define BL_STORAGE_IMPLEMENTATION_ID_SIZE 32 diff --git a/include/fw_info.h b/include/fw_info.h index 79124e5d673c..d0252ced07bb 100644 --- a/include/fw_info.h +++ b/include/fw_info.h @@ -135,6 +135,7 @@ BUILD_ASSERT(sizeof(struct fw_info) == offsetof(struct fw_info, ext_apis), /* Find the difference between the start of the current image and the address * from which the firmware info offset is calculated. */ +#if defined(CONFIG_PARTITION_MANAGER_ENABLED) #if defined(PM_S0_PAD_SIZE) && (PM_ADDRESS == PM_S0_IMAGE_ADDRESS) #define FW_INFO_VECTOR_OFFSET PM_S0_PAD_SIZE #elif defined(PM_S1_PAD_SIZE) && (PM_ADDRESS == PM_S1_IMAGE_ADDRESS) @@ -145,6 +146,9 @@ BUILD_ASSERT(sizeof(struct fw_info) == offsetof(struct fw_info, ext_apis), #else #define FW_INFO_VECTOR_OFFSET 0 #endif +#else + #define FW_INFO_VECTOR_OFFSET CONFIG_ROM_START_OFFSET +#endif /* defined(CONFIG_PARTITION_MANAGER_ENABLED) */ /** @cond diff --git a/samples/bootloader/CMakeLists.txt b/samples/bootloader/CMakeLists.txt index 764d1c717842..7376271edc2b 100644 --- a/samples/bootloader/CMakeLists.txt +++ b/samples/bootloader/CMakeLists.txt @@ -10,3 +10,5 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(bootloader) zephyr_library_sources(src/main.c) + +zephyr_compile_options("-include${CMAKE_CURRENT_LIST_DIR}/include//bl_partitions_dummy.h") diff --git a/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf b/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf new file mode 100644 index 000000000000..d12991ef9255 --- /dev/null +++ b/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf @@ -0,0 +1,12 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_BOOT_BANNER=n +CONFIG_NCS_BOOT_BANNER=n +CONFIG_FPROTECT=n +CONFIG_SOC_NRF54H20_GPD=n +CONFIG_NRFS=n +CONFIG_USE_DT_CODE_PARTITION=y diff --git a/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay b/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay new file mode 100644 index 000000000000..39fb220523bb --- /dev/null +++ b/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + chosen { + zephyr,code-partition = &b0_partition; + }; +}; diff --git a/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot.conf b/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot.conf new file mode 100644 index 000000000000..d12991ef9255 --- /dev/null +++ b/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot.conf @@ -0,0 +1,12 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_BOOT_BANNER=n +CONFIG_NCS_BOOT_BANNER=n +CONFIG_FPROTECT=n +CONFIG_SOC_NRF54H20_GPD=n +CONFIG_NRFS=n +CONFIG_USE_DT_CODE_PARTITION=y diff --git a/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot.overlay b/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot.overlay new file mode 100644 index 000000000000..39fb220523bb --- /dev/null +++ b/samples/bootloader/boards/nrf54h20dk_nrf54h20_cpuapp_iron_b0_mcuboot.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + chosen { + zephyr,code-partition = &b0_partition; + }; +}; diff --git a/samples/bootloader/include/bl_partitions_dummy.h b/samples/bootloader/include/bl_partitions_dummy.h new file mode 100644 index 000000000000..10a4acea6986 --- /dev/null +++ b/samples/bootloader/include/bl_partitions_dummy.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/* DUMMY FILE ONLY TO BE USED FOR TESTING */ +#ifndef BL_PARTITIONS_H +#define BL_PARTITIONS_H + +#define NSIB_B0_ADDRESS 0x8000 +#define NSIB_B0_SIZE 0x1000 +#define NSIB_PROVISION_ADDRESS 0x7000 +#define NSIB_PROVISION_SIZE 0x1000 + +#define NSIB_S0_SIZE 0x10000 +#define NSIB_S1_SIZE 0x10000 + +#endif /* BL_PARTITIONS_H */ diff --git a/samples/bootloader/src/main.c b/samples/bootloader/src/main.c index 0b8e59b6c1a4..6ff4bb346e55 100644 --- a/samples/bootloader/src/main.c +++ b/samples/bootloader/src/main.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #if defined(CONFIG_FPROTECT) #include @@ -19,10 +18,13 @@ #include #include #include +#include #if defined(CONFIG_NRFX_NVMC) #include #elif defined(CONFIG_NRFX_RRAMC) #include +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) +/* No includes needed */ #else #error "No NRFX memory backend selected" #endif @@ -44,6 +46,8 @@ int load_huk(void) nrfx_nvmc_word_write(huk_flag_addr, 0); #elif defined(CONFIG_NRFX_RRAMC) nrfx_rramc_word_write(huk_flag_addr, 0); +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) + memcpy((void *)huk_flag_addr, (void *)&(uint32_t){0}, sizeof(uint32_t)); #endif return 0; } @@ -132,7 +136,7 @@ int main(void) { #if defined(CONFIG_FPROTECT) - int err = fprotect_area(PM_B0_ADDRESS, PM_B0_SIZE); + int err = fprotect_area(NSIB_B0_ADDRESS, NSIB_B0_SIZE); if (err) { printk("Failed to protect B0 flash, cancel startup.\r\n"); diff --git a/samples/bootloader/sysbuild/s1_image.overlay b/samples/bootloader/sysbuild/s1_image.overlay new file mode 100644 index 000000000000..fc08932d87ab --- /dev/null +++ b/samples/bootloader/sysbuild/s1_image.overlay @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +/ { + chosen { + zephyr,code-partition = &s1_partition; + }; +}; diff --git a/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/CMakeLists.txt b/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/CMakeLists.txt new file mode 100644 index 000000000000..b44c4016e4c0 --- /dev/null +++ b/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(smp_svr) + +target_sources(app PRIVATE ${ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src/main.c) +target_sources_ifdef(CONFIG_MCUMGR_TRANSPORT_BT app PRIVATE + ${ZEPHYR_BASE}/samples/subsys/mgmt/mcumgt/smp_svr/src/bluetooth.c) diff --git a/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/README.txt b/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/README.txt new file mode 100644 index 000000000000..e239e97a29e6 --- /dev/null +++ b/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/README.txt @@ -0,0 +1,5 @@ +This sample extends the same-named Zephyr sample to verify it +with Nordic development kits. + +Source code and basic configuration files can be found in the corresponding folder structure in +zephyr/samples/subsys/mgmt/mcumgr/smp_svr. diff --git a/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/prj.conf b/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/prj.conf new file mode 100644 index 000000000000..925ac0c93a27 --- /dev/null +++ b/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/prj.conf @@ -0,0 +1,41 @@ +# Enable MCUmgr and dependencies. +CONFIG_NET_BUF=y +CONFIG_ZCBOR=y +CONFIG_CRC=y +CONFIG_MCUMGR=y +CONFIG_STREAM_FLASH=y +CONFIG_FLASH_MAP=y + +# Some command handlers require a large stack. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304 +CONFIG_MAIN_STACK_SIZE=2176 + +# Ensure an MCUboot-compatible binary is generated. +CONFIG_BOOTLOADER_MCUBOOT=y + +# Enable flash operations. +CONFIG_FLASH=y + +# Required by the `taskstat` command. +CONFIG_THREAD_MONITOR=y + +# Support for taskstat command +CONFIG_MCUMGR_GRP_OS_TASKSTAT=y + +# Enable statistics and statistic names. +CONFIG_STATS=y +CONFIG_STATS_NAMES=y + +# Enable most core commands. +CONFIG_FLASH=y +CONFIG_IMG_MANAGER=y +CONFIG_MCUMGR_GRP_IMG=y +CONFIG_MCUMGR_GRP_OS=y +CONFIG_MCUMGR_GRP_STAT=y + +# Enable logging +CONFIG_LOG=y +CONFIG_MCUBOOT_UTIL_LOG_LEVEL_WRN=y + +# Disable debug logging +CONFIG_LOG_MAX_LEVEL=3 diff --git a/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/sample.yaml b/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/sample.yaml new file mode 100644 index 000000000000..753a5cc5c006 --- /dev/null +++ b/samples/zephyr/subsys/mgmt/mcumgr/smp_svr/sample.yaml @@ -0,0 +1,12 @@ +sample: + description: Simple Management Protocol sample + name: smp svr +common: + sysbuild: true + build_only: true +tests: + nrf.extended.sample.mcumgr.smp_svr.serial: + extra_args: + - EXTRA_CONF_FILE="${ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/overlay-serial.conf" + platform_allow: + - nrf54h20dk/nrf54h20/cpuapp/iron/b0/mcuboot diff --git a/scripts/bootloader/do_sign.py b/scripts/bootloader/do_sign.py index 2b8c8deaab2d..037c2cea34f0 100755 --- a/scripts/bootloader/do_sign.py +++ b/scripts/bootloader/do_sign.py @@ -40,6 +40,11 @@ def parse_args(argv=None): help='Signing algorithm (default: %(default)s)', action='store', choices=['ecdsa', 'ed25519'], default='ecdsa', ) + parser.add_argument( + '--start-offset', dest='start_offset', + help='An offset in the data from which to start calculating the signature', + action='store', default=0, type=int + ) args = parser.parse_args(argv) @@ -66,7 +71,8 @@ def hex_to_binary(input_hex_file: str) -> bytes: def sign_with_ecdsa( - private_key_file: Path, input_file: Path, output_file: Path | None = None + private_key_file: Path, input_file: Path, output_file: Path | None = None, + start_offset: int = 0 ) -> int: with open(private_key_file, 'rb') as f: private_key = load_pem_private_key(f.read(), password=None) @@ -75,6 +81,7 @@ def sign_with_ecdsa( with open(input_file, 'rb') as f: data = f.read() + data = data[start_offset:] signature = private_key.sign(data, ec.ECDSA(hashes.SHA256())) asn1_signature_bytes = parse_asn1_signature(signature) with open_stream(output_file) as stream: @@ -92,7 +99,8 @@ def parse_asn1_signature(signature: bytes, length=32) -> bytes: def sign_with_ed25519( - private_key_file: Path, input_file: Path, output_file: Path | None = None + private_key_file: Path, input_file: Path, output_file: Path | None = None, + start_offset: int = 0 ) -> int: with open(private_key_file, 'rb') as f: private_key = load_pem_private_key(f.read(), password=None) @@ -104,6 +112,7 @@ def sign_with_ed25519( else: with open(input_file, 'rb') as f: data = f.read() + data = data[start_offset:] signature = private_key.sign(data) with open_stream(output_file) as stream: stream.write(signature) @@ -119,7 +128,7 @@ def sign_with_ed25519( def main(argv=None) -> int: args = parse_args(argv) sign_function = ALGORITHMS[args.algorithm] - return sign_function(args.private_key, args.infile, args.outfile) + return sign_function(args.private_key, args.infile, args.outfile, args.start_offset) if __name__ == '__main__': diff --git a/scripts/bootloader/hash.py b/scripts/bootloader/hash.py index dc53f5e5ee28..39d14e200c01 100755 --- a/scripts/bootloader/hash.py +++ b/scripts/bootloader/hash.py @@ -36,11 +36,15 @@ def parse_args(): '--type', '-t', dest='hash_function', help='Hash function (default: %(default)s)', action='store', choices=HASH_FUNCTION_FACTORY.keys(), default='sha256' ) + parser.add_argument( + '--start-offset', dest='start_offset', help='An offset in the data to start hashing from', + action='store', default=0, type=int + ) return parser.parse_args() -def generate_hash_digest(file: str, hash_function_name: str) -> bytes: +def generate_hash_digest(file: str, hash_function_name: str, start_offset: int) -> bytes: if file.endswith('.hex'): ih = IntelHex(file) ih.padding = 0xff # Allows hashing with empty regions @@ -48,13 +52,15 @@ def generate_hash_digest(file: str, hash_function_name: str) -> bytes: else: to_hash = open(file, 'rb').read() + to_hash = to_hash[start_offset:] + hash_function = HASH_FUNCTION_FACTORY[hash_function_name] return hash_function(to_hash).digest() def main(): args = parse_args() - sys.stdout.buffer.write(generate_hash_digest(args.infile, args.hash_function)) + sys.stdout.buffer.write(generate_hash_digest(args.infile, args.hash_function, args.start_offset)) return 0 diff --git a/scripts/bootloader/tests/validation_data_test.py b/scripts/bootloader/tests/validation_data_test.py index 3ab2d4fb42bd..5835f6381dc6 100644 --- a/scripts/bootloader/tests/validation_data_test.py +++ b/scripts/bootloader/tests/validation_data_test.py @@ -58,7 +58,7 @@ def test_data_validation_for_ec(tmpdir, utils): keys_generator.write_public_key_pem(public_key_file) zephyr_hex_file.write(DUMMY_ZEPHYR_HEX) - hash_digest = generate_hash_digest(str(zephyr_hex_file), 'sha256') + hash_digest = generate_hash_digest(str(zephyr_hex_file), 'sha256', 0) utils.write_bytes(hash_file, hash_digest) do_sign.sign_with_ecdsa(private_key_file, hash_file, message_signature_file) @@ -71,7 +71,8 @@ def test_data_validation_for_ec(tmpdir, utils): offset=OFFSET, output_hex=output_hex_file.open('w'), output_bin=output_bin_file.open('wb'), - magic_value=MAGIC_VALUE + magic_value=MAGIC_VALUE, + input_data_offset=0 ) assert utils.read_bytes(message_signature_file) in utils.read_bytes(output_bin_file) # check with CLI command too @@ -84,7 +85,8 @@ def test_data_validation_for_ec(tmpdir, utils): '--offset', OFFSET, '--output-hex', str(output_hex_file), '--output-bin', str(output_bin_file), - '--magic-value', MAGIC_VALUE + '--magic-value', MAGIC_VALUE, + '--input-data-offset', 0 ] ) == 0 assert utils.read_bytes(message_signature_file) in utils.read_bytes(output_bin_file) @@ -106,7 +108,7 @@ def test_data_validation_for_ec_with_openssl(tmpdir, utils): zephyr_hex_file.write(DUMMY_ZEPHYR_HEX) # Generate sha256 hash - hash_digest = generate_hash_digest(str(zephyr_hex_file), 'sha256') + hash_digest = generate_hash_digest(str(zephyr_hex_file), 'sha256', 0) utils.write_bytes(hash_file, hash_digest) # sign hex file @@ -123,7 +125,8 @@ def test_data_validation_for_ec_with_openssl(tmpdir, utils): offset=OFFSET, output_hex=output_hex_file.open('w'), output_bin=output_bin_file.open('wb'), - magic_value=MAGIC_VALUE + magic_value=MAGIC_VALUE, + input_data_offset=0 ) assert utils.read_bytes(asn1_signature_file) in utils.read_bytes(output_bin_file) # check with CLI command too @@ -136,7 +139,8 @@ def test_data_validation_for_ec_with_openssl(tmpdir, utils): '--offset', OFFSET, '--output-hex', str(output_hex_file), '--output-bin', str(output_bin_file), - '--magic-value', MAGIC_VALUE + '--magic-value', MAGIC_VALUE, + '--input-data-offset', 0 ] ) == 0 assert utils.read_bytes(asn1_signature_file) in utils.read_bytes(output_bin_file) @@ -154,7 +158,7 @@ def test_data_validation_for_ed25519_with_sha512(tmpdir, utils): keys_generator.write_private_key_pem(private_key_file) zephyr_hex_file.write(DUMMY_ZEPHYR_HEX) - hash_digits = generate_hash_digest(str(zephyr_hex_file), 'sha512') + hash_digits = generate_hash_digest(str(zephyr_hex_file), 'sha512', 0) utils.write_bytes(hash_file, hash_digits) do_sign.sign_with_ed25519(private_key_file, hash_file, message_signature_file) @@ -166,7 +170,8 @@ def test_data_validation_for_ed25519_with_sha512(tmpdir, utils): offset=OFFSET, output_hex=output_hex_file.open('w'), output_bin=output_bin_file.open('wb'), - magic_value=MAGIC_VALUE + magic_value=MAGIC_VALUE, + input_data_offset=0 ) assert utils.read_bytes(message_signature_file) in utils.read_bytes(output_bin_file) @@ -201,7 +206,8 @@ def test_data_validation_for_ed25519_no_hash(tmpdir, utils): offset=OFFSET, output_hex=output_hex_file.open('w'), output_bin=output_bin_file.open('wb'), - magic_value=MAGIC_VALUE + magic_value=MAGIC_VALUE, + input_data_offset=0, ) assert utils.read_bytes(message_signature_file) in utils.read_bytes(output_bin_file) @@ -215,7 +221,8 @@ def test_data_validation_for_ed25519_no_hash(tmpdir, utils): '--offset', OFFSET, '--output-hex', str(output_hex_file), '--output-bin', str(output_bin_file), - '--magic-value', MAGIC_VALUE + '--magic-value', MAGIC_VALUE, + '--input-data-offset', 0 ] ) == 0 assert utils.read_bytes(message_signature_file) in utils.read_bytes(output_bin_file) diff --git a/scripts/bootloader/validation_data.py b/scripts/bootloader/validation_data.py index 8743b53d604f..adf45c1ead69 100755 --- a/scripts/bootloader/validation_data.py +++ b/scripts/bootloader/validation_data.py @@ -39,8 +39,8 @@ def __init__(self, hashfunc=None) -> None: """ self.hashfunc = hashfunc - def get_hash(self, input_hex: IntelHex) -> bytes: - firmware_bytes = input_hex.tobinstr() + def get_hash(self, input_hex: IntelHex, input_data_offset: int) -> bytes: + firmware_bytes = (input_hex.tobinstr())[input_data_offset:] return self.hashfunc(firmware_bytes).digest() @abc.abstractmethod @@ -56,16 +56,17 @@ def get_validation_data( signature_bytes: bytes, input_hex: IntelHex, public_key, - magic_value: bytes + magic_value: bytes, + input_data_offset: int ) -> bytes: - hash_bytes = self.get_hash(input_hex) + hash_bytes = self.get_hash(input_hex, input_data_offset) public_key_bytes = self.to_string(public_key) # Will raise an exception if it fails self.verify(public_key, signature_bytes, hash_bytes) validation_bytes = magic_value - validation_bytes += struct.pack(' None: with open(input_file, 'r', encoding='UTF-8') as f: ih = IntelHex(f) @@ -98,7 +100,8 @@ def append_validation_data( signature_bytes=signature_bytes, input_hex=ih, public_key=public_key, - magic_value=parsed_magic_value + magic_value=parsed_magic_value, + input_data_offset=input_data_offset ) validation_data_hex = IntelHex() @@ -141,16 +144,17 @@ def get_validation_data( signature_bytes: bytes, input_hex: IntelHex, public_key, - magic_value: bytes + magic_value: bytes, + input_data_offset: int ) -> bytes: - hash_bytes = self.get_hash(input_hex) + hash_bytes = self.get_hash(input_hex, input_data_offset) public_key_bytes = self.to_string(public_key) # Will raise an exception if it fails self.verify(public_key, signature_bytes, hash_bytes) validation_bytes = magic_value - validation_bytes += struct.pack(' bytes: if self.hashfunc: return super().get_validation_data( signature_bytes=signature_bytes, input_hex=input_hex, public_key=public_key, - magic_value=magic_value + magic_value=magic_value, + input_data_offset=input_data_offset ) validation_bytes = magic_value - validation_bytes += struct.pack(' None: if self.hashfunc: return super().append_validation_data( @@ -238,7 +245,8 @@ def append_validation_data( offset=offset, output_hex=output_hex, output_bin=output_bin, - magic_value=magic_value + magic_value=magic_value, + input_data_offset=input_data_offset ) with open(input_file, 'r', encoding='UTF-8') as f: @@ -256,13 +264,14 @@ def append_validation_data( self.verify( public_key=public_key, signature_bytes=signature_bytes, - message_bytes=ih.tobinstr() + message_bytes=(ih.tobinstr())[input_data_offset:] ) validation_data = self.get_validation_data( signature_bytes=signature_bytes, input_hex=ih, public_key=public_key, - magic_value=parsed_magic_value + magic_value=parsed_magic_value, + input_data_offset=input_data_offset ) validation_data_hex = IntelHex() @@ -309,6 +318,8 @@ def parse_args(argv=None): help='.bin output file name.') parser.add_argument('--hash', default=None, choices=['sha512'], help='Hash algorithm to use with ed25519.') + parser.add_argument('--input-data-offset', required=False, default=0, + type=int, help='The offset in the input data that the validation data corresponds to.') args = parser.parse_args(argv) if args.output_hex is None: @@ -337,7 +348,8 @@ def main(argv=None) -> int: offset=args.offset, output_hex=args.output_hex, output_bin=args.output_bin, - magic_value=args.magic_value + magic_value=args.magic_value, + input_data_offset=args.input_data_offset ) return 0 diff --git a/subsys/bootloader/Kconfig b/subsys/bootloader/Kconfig index 6bdc0c682d23..772f9cb35a3e 100644 --- a/subsys/bootloader/Kconfig +++ b/subsys/bootloader/Kconfig @@ -11,6 +11,8 @@ config SECURE_BOOT depends on !IS_SECURE_BOOTLOADER select FW_INFO select SW_VECTOR_RELAY if SOC_SERIES_NRF51X + select USE_DT_CODE_PARTITION if SOC_NRF54H20 + select EXPERIMENTAL if SOC_NRF54H20 help Set this option to enable the first stage bootloader which verifies the signature of the app. @@ -85,6 +87,7 @@ menuconfig IS_SECURE_BOOTLOADER select SECURE_BOOT_VALIDATION select SECURE_BOOT_STORAGE select SW_VECTOR_RELAY if SOC_SERIES_NRF51X + select USE_DT_CODE_PARTITION if SOC_NRF54H20 imply NRFX_NVMC if !SOC_SERIES_NRF54LX help This option is set by the first stage bootloader app to include all diff --git a/subsys/bootloader/bl_boot/bl_boot.c b/subsys/bootloader/bl_boot/bl_boot.c index 6f6158a8483c..12beb771fea9 100644 --- a/subsys/bootloader/bl_boot/bl_boot.c +++ b/subsys/bootloader/bl_boot/bl_boot.c @@ -7,10 +7,12 @@ #include #include #include -#include +#include #include #include +#ifdef CONFIG_NRFX_CLOCK #include +#endif #ifdef CONFIG_UART_NRFX_UART #include #endif @@ -18,6 +20,9 @@ #include #include #endif +#ifdef CONFIG_NRF_GRTC_TIMER +#include +#endif #if defined(CONFIG_SB_DISABLE_SELF_RWX) /* Disabling R_X has to be done while running from RAM for obvious reasons. @@ -75,9 +80,17 @@ static void uninit_used_peripherals(void) #if defined(CONFIG_HAS_HW_NRF_UARTE20) uninit_used_uarte(NRF_UARTE20); #endif +#if defined(CONFIG_HAS_HW_NRF_UARTE136) + uninit_used_uarte(NRF_UARTE136); +#endif #endif /* CONFIG_UART_NRFX */ +#ifdef CONFIG_NRFX_CLOCK nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); +#endif +#ifdef CONFIG_NRF_GRTC_TIMER + nrfx_grtc_uninit(); +#endif } #ifdef CONFIG_SW_VECTOR_RELAY @@ -102,7 +115,7 @@ void bl_boot(const struct fw_info *fw_info) * application. */ #if defined(CONFIG_FPROTECT) - int err = fprotect_area(PM_PROVISION_ADDRESS, PM_PROVISION_SIZE); + int err = fprotect_area(NSIB_PROVISION_ADDRESS, NSIB_PROVISION_SIZE); if (err) { printk("Failed to protect bootloader storage.\n\r"); diff --git a/subsys/bootloader/bl_storage/bl_storage.c b/subsys/bootloader/bl_storage/bl_storage.c index 5cff41a3938d..061f8d488d93 100644 --- a/subsys/bootloader/bl_storage/bl_storage.c +++ b/subsys/bootloader/bl_storage/bl_storage.c @@ -48,6 +48,9 @@ static counter_t bl_storage_counter_get(uint32_t address) return ~nrfx_nvmc_otp_halfword_read(address); #elif defined(CONFIG_NRFX_RRAMC) return ~nrfx_rramc_otp_word_read(index_from_address(address)); +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) + /* TODO - proper OTP for nRF54H */ + return ~(*(counter_t *)address); #endif } @@ -57,6 +60,10 @@ static void bl_storage_counter_set(uint32_t address, counter_t value) nrfx_nvmc_halfword_write((uint32_t)address, ~value); #elif defined(CONFIG_NRFX_RRAMC) nrfx_rramc_otp_word_write(index_from_address((uint32_t)address), ~value); +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) + /* TODO - proper OTP for nRF54H */ + value = ~value; + memcpy((void *)address, &value, sizeof(value)); #endif } @@ -66,6 +73,8 @@ static uint32_t bl_storage_word_read(uint32_t address) return nrfx_nvmc_uicr_word_read((uint32_t *)address); #elif defined(CONFIG_NRFX_RRAMC) return nrfx_rramc_word_read(address); +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) + return *(uint32_t *)address; #endif } @@ -77,6 +86,9 @@ static uint32_t bl_storage_word_write(uint32_t address, uint32_t value) #elif defined(CONFIG_NRFX_RRAMC) nrfx_rramc_word_write(address, value); return 0; +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) + memcpy((void *)address, &value, sizeof(value)); + return 0; #endif } @@ -93,6 +105,9 @@ static uint16_t bl_storage_otp_halfword_read(uint32_t address) } else { halfword = (uint16_t)(word >> 16); /* Shift the upper half down */ } +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) + /* TODO - proper OTP for nRF54H */ + return *(uint16_t *)address; #endif return halfword; } @@ -396,6 +411,9 @@ static lcs_data_t bl_storage_lcs_get(uint32_t address) return nrfx_nvmc_otp_halfword_read(address); #elif defined(CONFIG_NRFX_RRAMC) return nrfx_rramc_otp_word_read(index_from_address(address)); +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) + /* TODO - not supported yet, will be probably handled by SSF */ + return 0; #endif } diff --git a/subsys/bootloader/bl_validation/bl_validation.c b/subsys/bootloader/bl_validation/bl_validation.c index 29c0d014f3dc..a878ae7a6a07 100644 --- a/subsys/bootloader/bl_validation/bl_validation.c +++ b/subsys/bootloader/bl_validation/bl_validation.c @@ -416,6 +416,8 @@ static bool validate_firmware(uint32_t fw_dst_address, uint32_t fw_src_address, uint16_t stored_version; #elif defined(CONFIG_NRFX_RRAMC) uint32_t stored_version; +#elif defined(CONFIG_DT_HAS_NORDIC_MRAM_ENABLED) + uint32_t stored_version; #endif int err = get_monotonic_version(&stored_version); @@ -445,10 +447,11 @@ static bool validate_firmware(uint32_t fw_dst_address, uint32_t fw_src_address, return false; } -#if defined(PM_S0_SIZE) && defined(PM_S1_SIZE) - BUILD_ASSERT(PM_S0_SIZE == PM_S1_SIZE, - "B0's slots aren't the same size. Check pm.yml."); - if ((fwinfo->size > (PM_S0_SIZE)) +#if defined(NSIB_S0_SIZE) && defined(NSIB_S1_SIZE) + BUILD_ASSERT(NSIB_S0_SIZE == NSIB_S1_SIZE, + "B0's slots aren't the same size." + "Check devicetree or pm.yml (if using partition manager)."); + if ((fwinfo->size > (NSIB_S0_SIZE)) || (fwinfo->total_size > fwinfo->size)) { if (!external) { LOG_ERR("Invalid size or total_size in firmware info."); diff --git a/subsys/fw_info/Kconfig b/subsys/fw_info/Kconfig index 536e2d3657ff..f8198c35f9d6 100644 --- a/subsys/fw_info/Kconfig +++ b/subsys/fw_info/Kconfig @@ -19,6 +19,7 @@ config FW_INFO_API config FW_INFO_OFFSET hex "The location of firmware info inside this firmware" default 0x600 if SOC_SERIES_NRF54LX + default 0x800 if SOC_SERIES_NRF54HX default 0x200 help The location of firmware information inside the current firmware @@ -77,6 +78,7 @@ config FW_INFO_HARDWARE_ID default 52 if SOC_SERIES_NRF52X default 53 if SOC_SERIES_NRF53X default 54 if SOC_SERIES_NRF54LX + default 154 if SOC_SERIES_NRF54HX default 91 if SOC_SERIES_NRF91X default 0 if BOARD_NATIVE_SIM help diff --git a/subsys/fw_info/fw_info.c b/subsys/fw_info/fw_info.c index 3f25fa329859..7c1e113be910 100644 --- a/subsys/fw_info/fw_info.c +++ b/subsys/fw_info/fw_info.c @@ -35,10 +35,10 @@ const struct fw_info m_firmware_info = { .magic = {FIRMWARE_INFO_MAGIC}, .total_size = (uint32_t)_fw_info_size, - .size = ((uint32_t)_flash_used), + .size = ((uint32_t)_flash_used) - CONFIG_ROM_START_OFFSET, .version = CONFIG_FW_INFO_FIRMWARE_VERSION, - .address = ((uint32_t)__rom_region_start), - .boot_address = (uint32_t)__rom_region_start, + .address = ((uint32_t)__rom_region_start) + CONFIG_ROM_START_OFFSET, + .boot_address = (uint32_t)__rom_region_start + CONFIG_ROM_START_OFFSET, .valid = CONFIG_FW_INFO_VALID_VAL, .reserved = {0, 0, 0, 0}, .ext_api_num = (uint32_t)_ext_apis_size, diff --git a/subsys/fw_info/fw_info.ld b/subsys/fw_info/fw_info.ld index 6b44b3b64c87..8beba04f6db8 100644 --- a/subsys/fw_info/fw_info.ld +++ b/subsys/fw_info/fw_info.ld @@ -1,4 +1,4 @@ -. = CONFIG_FW_INFO_OFFSET; +. = (CONFIG_ROM_START_OFFSET+CONFIG_FW_INFO_OFFSET); _fw_info_start = .; KEEP(*(SORT_BY_NAME(.firmware_info*))) _fw_info_size = ABSOLUTE(. - _fw_info_start); diff --git a/sysbuild/CMakeLists.txt b/sysbuild/CMakeLists.txt index 615508c7a42a..159331943c7b 100644 --- a/sysbuild/CMakeLists.txt +++ b/sysbuild/CMakeLists.txt @@ -51,6 +51,11 @@ function(restore_ncs_vars) endforeach() endfunction() +function(verify_bootloader_dts) + include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/bootloader_dts_utils.cmake) + verify_bootloader_dts_configuration() +endfunction() + function(include_provision_hex) include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/provision_hex.cmake) endfunction() @@ -148,7 +153,7 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake) set(target_length) if(SB_CONFIG_BOOTLOADER_MCUBOOT) - if(SB_CONFIG_PARTITION_MANAGER) + if(SB_CONFIG_PARTITION_MANAGER OR SB_CONFIG_SECURE_BOOT) # Make mcuboot a build only target as the main application will flash this from the # merged hex file set_target_properties(mcuboot PROPERTIES BUILD_ONLY true) @@ -287,7 +292,7 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_pre_cmake) set_config_bool(mcuboot CONFIG_BOOT_FIH_PROFILE_DEFAULT_LOW y) endif() - if(SB_CONFIG_PARTITION_MANAGER) + if(SB_CONFIG_PARTITION_MANAGER OR SB_CONFIG_SECURE_BOOT) # Use NCS signing script with support for PM if(SB_CONFIG_QSPI_XIP_SPLIT_IMAGE) set(${DEFAULT_IMAGE}_SIGNING_SCRIPT "${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/image_signing_split.cmake" CACHE INTERNAL "MCUboot signing script" FORCE) @@ -731,6 +736,10 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake) nrfconnect_generate_factory_data() endif() + if(SB_CONFIG_SECURE_BOOT AND NOT SB_CONFIG_PARTITION_MANAGER) + verify_bootloader_dts() + endif() + include_packaging() if(NOT SB_CONFIG_SOC_NRF54H20_IRON) include_suit_provisioning() @@ -829,6 +838,8 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake) -------------------------------------------------------------------------------------------- ") endif() + elseif(SB_CONFIG_SECURE_BOOT) + include(${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/secureboot_merge.cmake OPTIONAL) endif() foreach(image ${IMAGES}) configure_cache(IMAGE ${image}) @@ -840,24 +851,18 @@ function(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake) ExternalProject_Get_Property(${DEFAULT_IMAGE} BINARY_DIR) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${BINARY_DIR}/zephyr/.config) - if(NCS_SYSBUILD_PARTITION_MANAGER) - if(SB_CONFIG_SECURE_BOOT AND SB_CONFIG_SECURE_BOOT_APPCORE AND SB_CONFIG_BOOTLOADER_MCUBOOT) - ExternalProject_Get_Property(mcuboot BINARY_DIR) - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${BINARY_DIR}/zephyr/.config) - endif() + if(SB_CONFIG_SECURE_BOOT AND SB_CONFIG_SECURE_BOOT_APPCORE AND SB_CONFIG_BOOTLOADER_MCUBOOT) + ExternalProject_Get_Property(mcuboot BINARY_DIR) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${BINARY_DIR}/zephyr/.config) + endif() - if(SB_CONFIG_SECURE_BOOT_NETCORE) - get_property(main_app GLOBAL PROPERTY DOMAIN_APP_CPUNET) - ExternalProject_Get_Property(${main_app} BINARY_DIR) - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${BINARY_DIR}/zephyr/.config) - endif() + if(SB_CONFIG_SECURE_BOOT_NETCORE) + get_property(main_app GLOBAL PROPERTY DOMAIN_APP_CPUNET) + ExternalProject_Get_Property(${main_app} BINARY_DIR) + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${BINARY_DIR}/zephyr/.config) endif() endfunction(${SYSBUILD_CURRENT_MODULE_NAME}_post_cmake) -# Enable use of partition manager with sysbuild. -# Consider if this shoulc come through Sysbuild Kconfig flag. -set(NCS_SYSBUILD_PARTITION_MANAGER TRUE) - list(APPEND CMAKE_MODULE_PATH ${ZEPHYR_NRF_MODULE_DIR}/cmake/sysbuild/modules) include(ncs_sysbuild_extensions) include(${CMAKE_CURRENT_LIST_DIR}/extensions.cmake) diff --git a/sysbuild/secureboot.cmake b/sysbuild/secureboot.cmake index 78cec33b835b..0259cfe35f41 100644 --- a/sysbuild/secureboot.cmake +++ b/sysbuild/secureboot.cmake @@ -62,10 +62,31 @@ if(SB_CONFIG_SECURE_BOOT) if(SB_CONFIG_SECURE_BOOT_BUILD_S1_VARIANT_IMAGE) set(image s1_image) - if(SB_CONFIG_BOOTLOADER_MCUBOOT) - ExternalNcsVariantProject_Add(APPLICATION mcuboot VARIANT ${image}) + if(SB_CONFIG_PARTITION_MANAGER) + if(SB_CONFIG_BOOTLOADER_MCUBOOT) + ExternalNcsVariantProject_Add(APPLICATION mcuboot VARIANT ${image}) + else() + ExternalNcsVariantProject_Add(APPLICATION ${DEFAULT_IMAGE} VARIANT ${image}) + endif() else() - ExternalNcsVariantProject_Add(APPLICATION ${DEFAULT_IMAGE} VARIANT ${image}) + if(SB_CONFIG_BOOTLOADER_MCUBOOT) + ExternalNcsVariantProject_Add(APPLICATION mcuboot VARIANT ${image} SPLIT_KCONFIG true) + # TODO: NCSDK-33774 - add a robust way of passing all the required Kconfig options from MCUBOOT to s1 image + set_target_properties(${image} PROPERTIES + IMAGE_CONF_SCRIPT ${ZEPHYR_BASE}/share/sysbuild/image_configurations/BOOTLOADER_image_default.cmake + ) + set_config_int(${image} CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER ${SB_CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER}) + set_config_int(${image} CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER ${SB_CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER}) + math(EXPR mcuboot_total_images "${SB_CONFIG_MCUBOOT_UPDATEABLE_IMAGES} + ${SB_CONFIG_MCUBOOT_ADDITIONAL_UPDATEABLE_IMAGES}") + set_config_int(${image} CONFIG_UPDATEABLE_IMAGE_NUMBER ${mcuboot_total_images}) + else() + ExternalNcsVariantProject_Add(APPLICATION ${DEFAULT_IMAGE} VARIANT ${image} SPLIT_KCONFIG true) + endif() + set(slot_overlay_dir ${ZEPHYR_NRF_MODULE_DIR}/samples/bootloader/sysbuild) + cmake_path(APPEND slot_overlay_dir "s1_image.overlay" OUTPUT_VARIABLE s1_overlay) + add_overlay_dts(${image} "${s1_overlay}") + set_config_bool(${image} CONFIG_SECURE_BOOT y) + set_config_bool(${image} CONFIG_FW_INFO y) endif() set_property(GLOBAL APPEND PROPERTY diff --git a/west.yml b/west.yml index 7c4c4bed45db..1da2b6f35a0e 100644 --- a/west.yml +++ b/west.yml @@ -127,7 +127,7 @@ manifest: compare-by-default: true - name: mcuboot repo-path: sdk-mcuboot - revision: 766081bd6dfe26057fdbe3dca5d8eb5f64681beb + revision: pull/432/head path: bootloader/mcuboot - name: qcbor url: https://github.com/laurencelundblade/QCBOR