From 646f116cca6ef6c145e42907797ae80b4f851684 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 24 Jul 2024 13:21:33 +0100 Subject: [PATCH] mcuboot: Add support for RAM load mode Adds supporting code that allows the RAM load mode of MCUboot to be used and for applications to build successfully with it. Sysbuild can be used to build images for this mode Signed-off-by: Jamie McCrae --- cmake/mcuboot.cmake | 57 ++++++++++++++++++- modules/Kconfig.mcuboot | 12 ++++ .../MAIN_image_default.cmake | 5 +- subsys/dfu/Kconfig | 1 + subsys/dfu/boot/mcuboot.c | 35 ++++++++++++ .../mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c | 30 +++++++++- .../mcumgr/grp/img_mgmt/src/img_mgmt_state.c | 3 +- .../mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c | 2 + 8 files changed, 139 insertions(+), 6 deletions(-) diff --git a/cmake/mcuboot.cmake b/cmake/mcuboot.cmake index 25fa1827f33..b6ab9dd5034 100644 --- a/cmake/mcuboot.cmake +++ b/cmake/mcuboot.cmake @@ -114,9 +114,21 @@ function(zephyr_mcuboot_tasks) set(imgtool_args --key "${keyfile}" ${imgtool_args}) endif() - # Use overwrite-only instead of swap upgrades. if(CONFIG_MCUBOOT_IMGTOOL_OVERWRITE_ONLY) + # Use overwrite-only instead of swap upgrades. set(imgtool_args --overwrite-only --align 1 ${imgtool_args}) + elseif(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) + # RAM load requires setting the location of where to load the image to + dt_chosen(chosen_ram PROPERTY "zephyr,sram") + dt_reg_addr(chosen_ram_address PATH ${chosen_ram}) + dt_nodelabel(slot0_partition NODELABEL "slot0_partition" REQUIRED) + dt_reg_addr(slot0_partition_address PATH ${slot0_partition}) + dt_nodelabel(slot1_partition NODELABEL "slot1_partition" REQUIRED) + dt_reg_addr(slot1_partition_address PATH ${slot1_partition}) + + set(imgtool_args --align 1 --load-addr ${chosen_ram_address} ${imgtool_args}) + set(imgtool_args_alt_slot ${imgtool_args} --hex-addr ${slot1_partition_address}) + set(imgtool_args ${imgtool_args} --hex-addr ${slot0_partition_address}) else() set(imgtool_args --align ${write_block_size} ${imgtool_args}) endif() @@ -156,6 +168,27 @@ function(zephyr_mcuboot_tasks) ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" ${output}.bin ${output}.signed.encrypted.bin) endif() + + if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) + list(APPEND byproducts ${output}.slot1.signed.encrypted.bin) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND + ${imgtool_sign} ${imgtool_args_alt_slot} ${output}.bin + ${output}.slot1.signed.bin) + + if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) + list(APPEND byproducts ${output}.slot1.signed.confirmed.bin) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND + ${imgtool_sign} ${imgtool_args_alt_slot} --pad --confirm ${output}.bin + ${output}.slot1.signed.confirmed.bin) + endif() + + if(NOT "${keyfile_enc}" STREQUAL "") + list(APPEND byproducts ${output}.slot1.signed.encrypted.bin) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND + ${imgtool_sign} ${imgtool_args_alt_slot} --encrypt "${keyfile_enc}" + ${output}.bin ${output}.slot1.signed.encrypted.bin) + endif() + endif() endif() # Set up .hex outputs. @@ -187,8 +220,28 @@ function(zephyr_mcuboot_tasks) ${imgtool_sign} ${imgtool_args} --encrypt "${keyfile_enc}" ${output}.hex ${output}.signed.encrypted.hex) endif() - endif() + if(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) + list(APPEND byproducts ${output}.slot1.signed.hex) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND + ${imgtool_sign} ${imgtool_args_alt_slot} ${output}.hex + ${output}.slot1.signed.hex) + + if(CONFIG_MCUBOOT_GENERATE_CONFIRMED_IMAGE) + list(APPEND byproducts ${output}.slot1.signed.confirmed.hex) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND + ${imgtool_sign} ${imgtool_args_alt_slot} --pad --confirm ${output}.hex + ${output}.slot1.signed.confirmed.hex) + endif() + + if(NOT "${keyfile_enc}" STREQUAL "") + list(APPEND byproducts ${output}.slot1.signed.encrypted.hex) + set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND + ${imgtool_sign} ${imgtool_args_alt_slot} --encrypt "${keyfile_enc}" + ${output}.hex ${output}.slot1.signed.encrypted.hex) + endif() + endif() + endif() set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts ${byproducts}) endfunction() diff --git a/modules/Kconfig.mcuboot b/modules/Kconfig.mcuboot index a914ff1d5a8..2706ad6583c 100644 --- a/modules/Kconfig.mcuboot +++ b/modules/Kconfig.mcuboot @@ -183,6 +183,18 @@ config MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY that the overwrite will not happen unless the version of secondary slot is higher than the version in primary slot. +config MCUBOOT_BOOTLOADER_MODE_RAM_LOAD + bool "MCUboot has been configured for RAM LOAD operation" + select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE + select MCUBOOT_BOOTLOADER_NO_DOWNGRADE + help + MCUboot expects slot0_partition and slot1_partition to exist in DT. In this mode, MCUboot + will select the image with the higher version number, copy it to RAM and begin execution + from there. The image must be linked to execute from RAM, the address that it is copied + to is specified using the load-addr argument when running imgtool. + This option automatically selectes MCUBOOT_BOOTLOADER_NO_DOWNGRADE as it is not possible + to swap back to older version of the application. + config MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP bool "MCUboot has been configured for DirectXIP operation" select MCUBOOT_BOOTLOADER_MODE_HAS_NO_DOWNGRADE diff --git a/share/sysbuild/image_configurations/MAIN_image_default.cmake b/share/sysbuild/image_configurations/MAIN_image_default.cmake index 601d8b616ec..cd447a29d0c 100644 --- a/share/sysbuild/image_configurations/MAIN_image_default.cmake +++ b/share/sysbuild/image_configurations/MAIN_image_default.cmake @@ -33,7 +33,10 @@ if(SB_CONFIG_BOOTLOADER_MCUBOOT) elseif(SB_CONFIG_MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT) set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT y) elseif(SB_CONFIG_MCUBOOT_MODE_RAM_LOAD) - # Not yet supported in zephyr code + # RAM load mode requires XIP be disabled and flash size be set to 0 + set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD y) + set_config_bool(${ZCMAKE_APPLICATION} CONFIG_XIP n) + set_config_int(${ZCMAKE_APPLICATION} CONFIG_FLASH_SIZE 0) elseif(SB_CONFIG_MCUBOOT_MODE_FIRMWARE_UPDATER) set_config_bool(${ZCMAKE_APPLICATION} CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER y) endif() diff --git a/subsys/dfu/Kconfig b/subsys/dfu/Kconfig index 5977764016d..f621457a1e7 100644 --- a/subsys/dfu/Kconfig +++ b/subsys/dfu/Kconfig @@ -10,6 +10,7 @@ menuconfig IMG_MANAGER bool "DFU image manager" depends on STREAM_FLASH + depends on !MCUBOOT_BOOTLOADER_MODE_RAM_LOAD || RETENTION_BOOTLOADER_INFO_OUTPUT_FUNCTION help Enable support for managing DFU image. diff --git a/subsys/dfu/boot/mcuboot.c b/subsys/dfu/boot/mcuboot.c index 20015349dbc..dde9f8af579 100644 --- a/subsys/dfu/boot/mcuboot.c +++ b/subsys/dfu/boot/mcuboot.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -19,8 +20,15 @@ #include "bootutil/bootutil_public.h" #include +#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) +#include +#include +#endif + #include "mcuboot_priv.h" +LOG_MODULE_REGISTER(mcuboot_dfu, LOG_LEVEL_DBG); + /* * Helpers for image headers and trailers, as defined by mcuboot. */ @@ -34,8 +42,15 @@ #define BOOT_HEADER_MAGIC_V1 0x96f3b83d #define BOOT_HEADER_SIZE_V1 32 +#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) +/* For RAM LOAD mode, the active image must be fetched from the bootloader */ +static uint8_t boot_fetch_active_slot(void); +#define ACTIVE_SLOT_FLASH_AREA_ID boot_fetch_active_slot() +#define INVALID_SLOT_ID 255 +#else /* Get active partition. zephyr,code-partition chosen node must be defined */ #define ACTIVE_SLOT_FLASH_AREA_ID DT_FIXED_PARTITION_ID(DT_CHOSEN(zephyr_code_partition)) +#endif /* * Raw (on-flash) representation of the v1 image header. @@ -60,6 +75,26 @@ struct mcuboot_v1_raw_header { * End of strict defines */ +#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) +static uint8_t boot_fetch_active_slot(void) +{ + int rc; + uint8_t slot; + + rc = blinfo_lookup(BLINFO_RUNNING_SLOT, &slot, sizeof(slot)); + + if (rc <= 0) { + LOG_ERR("Failed to fetch active slot: %d", rc); + + return INVALID_SLOT_ID; + } + + LOG_DBG("Active slot: %d", slot); + + return slot; +} +#endif + static int boot_read_v1_header(uint8_t area_id, struct mcuboot_v1_raw_header *v1_raw) { diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c index 913aec15c88..63083c96fb9 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt.c @@ -35,6 +35,13 @@ #include #endif +#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) +#include +#include +#endif + +#if !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) + #ifndef CONFIG_FLASH_LOAD_OFFSET #error MCUmgr requires application to be built with CONFIG_FLASH_LOAD_OFFSET set \ to be able to figure out application running slot. @@ -75,6 +82,10 @@ BUILD_ASSERT(sizeof(struct image_header) == IMAGE_HEADER_SIZE, #define ACTIVE_IMAGE_IS 0 #endif +#else +#define ACTIVE_IMAGE_IS 0 +#endif + #define SLOTS_PER_IMAGE 2 LOG_MODULE_REGISTER(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL); @@ -198,9 +209,23 @@ int img_mgmt_active_slot(int image) { int slot = 0; - /* Multi image does not support DirectXIP currently */ + /* Multi image does not support DirectXIP or RAM load currently */ #if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER > 1 slot = (image << 1); +#elif defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) + /* RAM load requires querying bootloader */ + int rc; + uint8_t temp_slot; + + rc = blinfo_lookup(BLINFO_RUNNING_SLOT, &temp_slot, sizeof(temp_slot)); + + if (rc <= 0) { + LOG_ERR("Failed to fetch active slot: %d", rc); + + return 255; + } + + slot = (int)temp_slot; #else /* This covers single image, including DirectXiP */ if (FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot1_partition)) { @@ -1056,7 +1081,8 @@ static int img_mgmt_translate_error_code(uint16_t err) static const struct mgmt_handler img_mgmt_handlers[] = { [IMG_MGMT_ID_STATE] = { .mh_read = img_mgmt_state_read, -#ifdef CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP +#if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) .mh_write = NULL #else .mh_write = img_mgmt_state_write, diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c index a580d7af6c3..52b2ed76f67 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/img_mgmt_state.c @@ -324,7 +324,8 @@ img_mgmt_slot_in_use(int slot) int image = img_mgmt_slot_to_image(slot); int active_slot = img_mgmt_active_slot(image); -#if !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) +#if !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) && \ + !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) enum img_mgmt_next_boot_type type = NEXT_BOOT_TYPE_NORMAL; int nbs = img_mgmt_get_next_boot_slot(image, &type); diff --git a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c index 131f7a698b2..8d58a3b8634 100644 --- a/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/img_mgmt/src/zephyr_img_mgmt.c @@ -570,6 +570,7 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, (defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \ defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \ defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) || \ defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \ defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) && \ CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0 @@ -645,6 +646,7 @@ int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req, (defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) || \ defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) || \ defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) || \ + defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) || \ defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \ defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) && \ CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0