From 48420888f4e3013caf79bbdf31a930a4c9901ca7 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 10 Sep 2024 13:41:30 +0100 Subject: [PATCH 1/4] [nrf noup] treewide: Add support for sysbuild assigned images Adds support for image IDs that are assigned by sysbuild, which allows for dynamically supporting different configurations without needing dummy images to support different modes. Also fixes multiple deficiencies with the previous code where things were not properly accounted for e.g. using the swap algorithm including all swap status parts when updating s0/s1 MCUboot image which could overwrite and corrupt the image data in the other slot Signed-off-by: Jamie McCrae --- boot/bootutil/src/loader.c | 129 ++++++++++++++------- boot/bootutil/src/swap_nsib.c | 70 +++++++++++ boot/bootutil/src/swap_priv.h | 8 ++ boot/zephyr/CMakeLists.txt | 6 + boot/zephyr/include/sysflash/pm_sysflash.h | 70 +++++------ 5 files changed, 199 insertions(+), 84 deletions(-) create mode 100644 boot/bootutil/src/swap_nsib.c diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 53f40c33a..293baf4ac 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -153,15 +153,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all, * * Failure to read any headers is a fatal error. */ -#ifdef PM_S1_ADDRESS +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 /* Patch needed for NCS. The primary slot of the second image * (image 1) will not contain a valid image header until an upgrade * of mcuboot has happened (filling S1 with the new version). */ - if (BOOT_CURR_IMG(state) == 1 && i == 0) { + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER && i == 0) { continue; } -#endif /* PM_S1_ADDRESS */ +#endif /* CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 */ if (i > 0 && !require_all) { return 0; } else { @@ -1160,7 +1160,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) \ && defined(CONFIG_PCD_APP) && defined(CONFIG_PCD_READ_NETCORE_APP_VERSION) - if (BOOT_CURR_IMG(state) == 1) { + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { rc = pcd_version_cmp_net(fap, boot_img_hdr(state, BOOT_SECONDARY_SLOT)); } else { rc = boot_version_cmp( @@ -1229,6 +1229,8 @@ boot_validate_slot(struct boot_loader_state *state, int slot, struct image_header *secondary_hdr = boot_img_hdr(state, slot); uint32_t reset_value = 0; uint32_t reset_addr = secondary_hdr->ih_hdr_size + sizeof(reset_value); + uint32_t min_addr, max_addr; + bool check_addresses = false; rc = flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value)); if (rc != 0) { @@ -1236,29 +1238,46 @@ boot_validate_slot(struct boot_loader_state *state, int slot, goto out; } - uint32_t min_addr, max_addr; - #ifdef PM_CPUNET_APP_ADDRESS /* The primary slot for the network core is emulated in RAM. * Its flash_area hasn't got relevant boundaries. * Therfore need to override its boundaries for the check. */ - if (BOOT_CURR_IMG(state) == 1) { + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { min_addr = PM_CPUNET_APP_ADDRESS; max_addr = PM_CPUNET_APP_ADDRESS + PM_CPUNET_APP_SIZE; -#ifdef PM_S1_ADDRESS - } else if (BOOT_CURR_IMG(state) == 0) { + check_addresses = true; + } else +#endif +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { +#if (CONFIG_NCS_IS_VARIANT_IMAGE) min_addr = PM_S0_ADDRESS; - max_addr = pri_fa->fa_off + pri_fa->fa_size; + max_addr = (PM_S0_ADDRESS + PM_S0_SIZE); +#else + min_addr = PM_S1_ADDRESS; + max_addr = (PM_S1_ADDRESS + PM_S1_SIZE); #endif + check_addresses = true; } else #endif - { + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + min_addr = MIN(pri_fa->fa_off, PM_S0_ADDRESS); + max_addr = MAX((pri_fa->fa_off + pri_fa->fa_size), (PM_S0_ADDRESS + PM_S0_SIZE)); +#else + min_addr = MIN(pri_fa->fa_off, PM_S1_ADDRESS); + max_addr = MAX((pri_fa->fa_off + pri_fa->fa_size), (PM_S1_ADDRESS + PM_S1_SIZE)); +#endif +#else min_addr = pri_fa->fa_off; max_addr = pri_fa->fa_off + pri_fa->fa_size; +#endif + check_addresses = true; } - if (reset_value < min_addr || reset_value> (max_addr)) { + if (check_addresses == true && (reset_value < min_addr || reset_value > max_addr)) { BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot"); BOOT_LOG_ERR("Erasing image from secondary slot"); @@ -1364,7 +1383,7 @@ static inline void sec_slot_mark_assigned(struct boot_loader_state *state) } /** - * Cleanu up all secondary slot which couldn't be assigned to any primary slot. + * Cleanup up all secondary slot which couldn't be assigned to any primary slot. * * This function erases content of each secondary slot which contains valid * header but couldn't be assigned to any of supported primary images. @@ -1428,7 +1447,7 @@ boot_validated_swap_type(struct boot_loader_state *state, owner_nsib[BOOT_CURR_IMG(state)] = false; #endif -#if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) +#if defined(PM_S1_ADDRESS) || defined(PM_CPUNET_B0N_ADDRESS) const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); struct image_header *hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); @@ -1466,31 +1485,45 @@ boot_validated_swap_type(struct boot_loader_state *state, } /* Check start and end of primary slot for current image */ - if (reset_addr < primary_fa->fa_off) { -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) - const struct flash_area *nsib_fa; +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + if (reset_addr >= PM_S0_ADDRESS && reset_addr <= (PM_S0_ADDRESS + PM_S0_SIZE)) { +#else + if (reset_addr >= PM_S1_ADDRESS && reset_addr <= (PM_S1_ADDRESS + PM_S1_SIZE)) { +#endif + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { + /* This is not the s0/s1 upgrade image but the application image, pretend + * there is no image so the NSIB update can be loaded + */ + return BOOT_SWAP_TYPE_NONE; + } +#if 0 && defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) + const struct flash_area *nsib_fa; - /* NSIB upgrade slot */ - rc = flash_area_open((uint32_t)_image_1_primary_slot_id, - &nsib_fa); + /* NSIB upgrade slot */ +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + rc = flash_area_open(PM_S0_ID, &nsib_fa); +#else + rc = flash_area_open(PM_S1_ID, &nsib_fa); +#endif - if (rc != 0) { - return BOOT_SWAP_TYPE_FAIL; - } + if (rc != 0) { + return BOOT_SWAP_TYPE_FAIL; + } - /* Image is placed before Primary and within the NSIB slot */ - if (reset_addr > nsib_fa->fa_off - && reset_addr < (nsib_fa->fa_off + nsib_fa->fa_size)) { - /* Set primary to be NSIB upgrade slot */ - BOOT_IMG_AREA(state, 0) = nsib_fa; - owner_nsib[BOOT_CURR_IMG(state)] = true; - } + /* Set primary to be NSIB upgrade slot */ + BOOT_IMG_AREA(state, 0) = nsib_fa; +#endif + owner_nsib[BOOT_CURR_IMG(state)] = true; +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + } else if (reset_addr >= PM_S1_ADDRESS && reset_addr <= (PM_S1_ADDRESS + PM_S1_SIZE)) { #else - return BOOT_SWAP_TYPE_NONE; - + } else if (reset_addr >= PM_S0_ADDRESS && reset_addr <= (PM_S0_ADDRESS + PM_S0_SIZE)) { #endif - - } else if (reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { + /* NSIB upgrade but for the wrong slot, must be erased */ + LOG_ERR("Image in slot is for wrong s0/s1 image"); + flash_area_erase(secondary_fa, 0, secondary_fa->fa_size); + return BOOT_SWAP_TYPE_FAIL; + } else if (reset_addr < primary_fa->fa_off || reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { /* The image in the secondary slot is not intended for any */ return BOOT_SWAP_TYPE_NONE; } @@ -1503,7 +1536,7 @@ boot_validated_swap_type(struct boot_loader_state *state, sec_slot_mark_assigned(state); } -#endif /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ +#endif /* PM_S1_ADDRESS || PM_CPUNET_B0N_ADDRESS */ swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -2035,7 +2068,22 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) flash_area_close(fap); } - swap_run(state, bs, copy_size); +#if defined(PM_S1_ADDRESS) && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (owner_nsib[BOOT_CURR_IMG(state)]) { + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + /* For NSIB, move the image instead of swapping it */ + nsib_swap_run(state, bs); + +#if defined(CONFIG_REBOOT) + /* Should also reboot at this point so the new S0/S1 update is applied */ + sys_reboot(SYS_REBOOT_COLD); +#endif + } + } else +#endif + { + swap_run(state, bs, copy_size); + } #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT extern int boot_status_fails; @@ -2701,12 +2749,6 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) rc = boot_perform_update(state, &bs); } assert(rc == 0); -#if defined(PM_S1_ADDRESS) && defined(CONFIG_REBOOT) - if (owner_nsib[BOOT_CURR_IMG(state)]) { - sys_reboot(SYS_REBOOT_COLD); - - } -#endif break; case BOOT_SWAP_TYPE_FAIL: @@ -2780,7 +2822,8 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) * executing MCUBoot image, and is therefore already validated by NSIB and * does not need to also be validated by MCUBoot. */ - bool image_validated_by_nsib = BOOT_CURR_IMG(state) == 1; + bool image_validated_by_nsib = BOOT_CURR_IMG(state) == + CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER; if (!image_validated_by_nsib) #endif { diff --git a/boot/bootutil/src/swap_nsib.c b/boot/bootutil/src/swap_nsib.c new file mode 100644 index 000000000..39ed4c652 --- /dev/null +++ b/boot/bootutil/src/swap_nsib.c @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "bootutil/bootutil.h" +#include "bootutil_priv.h" +#include "swap_priv.h" +#include "bootutil/bootutil_log.h" + +#include "mcuboot_config/mcuboot_config.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs) +{ + uint32_t sector_sz; + uint8_t image_index; + const struct flash_area *fap_pri; + const struct flash_area *fap_sec; + int rc; + + BOOT_LOG_INF("Starting swap using nsib algorithm."); + + sector_sz = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0); + +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + rc = flash_area_open(PM_S0_ID, &fap_pri); +#else + rc = flash_area_open(PM_S1_ID, &fap_pri); +#endif + assert (rc == 0); + image_index = BOOT_CURR_IMG(state); + + rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap_sec); + assert (rc == 0); + + rc = boot_erase_region(fap_pri, 0, fap_pri->fa_size); + assert(rc == 0); + + rc = boot_copy_region(state, fap_sec, fap_pri, 0, 0, fap_pri->fa_size); + assert(rc == 0); + + rc = swap_erase_trailer_sectors(state, fap_sec); + assert(rc == 0); + + rc = boot_erase_region(fap_sec, 0, MIN((fap_pri->fa_size + sector_sz), fap_sec->fa_size)); + assert(rc == 0); + + flash_area_close(fap_pri); + flash_area_close(fap_sec); +} diff --git a/boot/bootutil/src/swap_priv.h b/boot/bootutil/src/swap_priv.h index 960c72250..2734d6262 100644 --- a/boot/bootutil/src/swap_priv.h +++ b/boot/bootutil/src/swap_priv.h @@ -106,4 +106,12 @@ static inline size_t boot_scratch_area_size(const struct boot_loader_state *stat */ int app_max_size(struct boot_loader_state *state); +#if defined(PM_S1_ADDRESS) && !defined(MCUBOOT_OVERWRITE_ONLY) && \ +(CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED)) +/** + * Performs an NSIB update + */ +void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs); +#endif + #endif /* H_SWAP_PRIV_ */ diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 20d38b49b..4587681e5 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -152,6 +152,12 @@ zephyr_library_sources( ${BOOT_DIR}/bootutil/src/swap_move.c ${BOOT_DIR}/bootutil/src/caps.c ) + + if(NOT CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER EQUAL "-1" AND NOT CONFIG_BOOT_UPGRADE_ONLY) + zephyr_library_sources( + ${BOOT_DIR}/bootutil/src/swap_nsib.c + ) + endif() endif() if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h index db60ddd03..67aca2fc1 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -15,48 +15,37 @@ #ifndef CONFIG_SINGLE_APPLICATION_SLOT -#if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) -/* If B0 is present then two bootloaders are present, and we must use - * a single secondary slot for both primary slots. - */ -extern uint32_t _image_1_primary_slot_id[]; -#endif /* (MCUBOOT_IMAGE_NUMBER == 2 && defined(PM_B0_ADDRESS) */ - -#if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ - !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) - -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - (uint32_t)_image_1_primary_slot_id : \ - 255 ) - -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - 255 ) - -#else /* MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ - * !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) - */ - /* Each pair of slots is separated by , and there is no terminating character */ -#define FLASH_AREA_IMAGE_0_SLOTS PM_MCUBOOT_PRIMARY_ID, PM_MCUBOOT_SECONDARY_ID -#define FLASH_AREA_IMAGE_1_SLOTS PM_MCUBOOT_PRIMARY_1_ID, PM_MCUBOOT_SECONDARY_1_ID -#define FLASH_AREA_IMAGE_2_SLOTS PM_MCUBOOT_PRIMARY_2_ID, PM_MCUBOOT_SECONDARY_2_ID +#define FLASH_AREA_IMAGE_0_SLOTS PM_MCUBOOT_PRIMARY_ID, PM_MCUBOOT_SECONDARY_ID, +#define FLASH_AREA_IMAGE_1_SLOTS PM_MCUBOOT_PRIMARY_1_ID, PM_MCUBOOT_SECONDARY_1_ID, +#define FLASH_AREA_IMAGE_2_SLOTS PM_MCUBOOT_PRIMARY_2_ID, PM_MCUBOOT_SECONDARY_2_ID, +#define FLASH_AREA_IMAGE_3_SLOTS PM_MCUBOOT_PRIMARY_3_ID, PM_MCUBOOT_SECONDARY_3_ID, + +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 +#ifdef CONFIG_NCS_IS_VARIANT_IMAGE +#define MCUBOOT_S0_S1_SLOTS PM_S0_ID, PM_MCUBOOT_SECONDARY_ID, +#else +#define MCUBOOT_S0_S1_SLOTS PM_S1_ID, PM_MCUBOOT_SECONDARY_ID, +#endif +#define MCUBOOT_IMAGE_NUMBER_WITHOUT_MCUBOOT_S0_S1 (MCUBOOT_IMAGE_NUMBER - 1) +#else +#define MCUBOOT_IMAGE_NUMBER_WITHOUT_MCUBOOT_S0_S1 MCUBOOT_IMAGE_NUMBER +#endif -#if (MCUBOOT_IMAGE_NUMBER == 1) +#if (MCUBOOT_IMAGE_NUMBER == 1) || (MCUBOOT_IMAGE_NUMBER == 2 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1) #define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS -#elif (MCUBOOT_IMAGE_NUMBER == 2) -#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS, \ +#elif (MCUBOOT_IMAGE_NUMBER == 2) || (MCUBOOT_IMAGE_NUMBER == 3 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1) +#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS \ FLASH_AREA_IMAGE_1_SLOTS -#elif (MCUBOOT_IMAGE_NUMBER == 3) -#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS, \ - FLASH_AREA_IMAGE_1_SLOTS, \ +#elif (MCUBOOT_IMAGE_NUMBER == 3) || (MCUBOOT_IMAGE_NUMBER == 4 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1) +#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS \ + FLASH_AREA_IMAGE_1_SLOTS \ FLASH_AREA_IMAGE_2_SLOTS +#elif (MCUBOOT_IMAGE_NUMBER == 4) +#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS \ + FLASH_AREA_IMAGE_1_SLOTS \ + FLASH_AREA_IMAGE_2_SLOTS \ + FLASH_AREA_IMAGE_3_SLOTS #else #error Unsupported number of images #endif @@ -65,6 +54,7 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) { static const int all_slots[] = { ALL_AVAILABLE_SLOTS + MCUBOOT_S0_S1_SLOTS }; return all_slots[img * 2 + slot]; }; @@ -72,6 +62,8 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #undef FLASH_AREA_IMAGE_0_SLOTS #undef FLASH_AREA_IMAGE_1_SLOTS #undef FLASH_AREA_IMAGE_2_SLOTS +#undef FLASH_AREA_IMAGE_3_SLOTS +#undef MCUBOOT_S0_S1_SLOTS #undef ALL_AVAILABLE_SLOTS #define FLASH_AREA_IMAGE_PRIMARY(x) __flash_area_ids_for_slot(x, 0) @@ -81,10 +73,6 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID #endif -#endif /* MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ - * !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) - */ - #else /* CONFIG_SINGLE_APPLICATION_SLOT */ #define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID From 00d17d7cc063d1272251ee174ef63c9241be0acb Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 17 Sep 2024 12:17:13 +0100 Subject: [PATCH 2/4] [nrf noup] treewide: Add child/parent support back for image numbers Adds support for child/parent images into the new dynamic image number system, without supporting any of the new features. This commit is scheduled to be removed from the tree when child/parent support is dropped so is purposely kept separate Signed-off-by: Jamie McCrae --- boot/bootutil/src/loader.c | 66 +++++++++++++++++++++- boot/bootutil/src/swap_nsib.c | 4 ++ boot/zephyr/CMakeLists.txt | 19 +++++++ boot/zephyr/include/sysflash/pm_sysflash.h | 29 ++++++++-- 4 files changed, 110 insertions(+), 8 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 293baf4ac..5c9bb1069 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -161,6 +161,14 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all, if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER && i == 0) { continue; } +#elif defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED) + /* Patch needed for NCS. The primary slot of the second image + * (image 1) will not contain a valid image header until an upgrade + * of mcuboot has happened (filling S1 with the new version). + */ + if (BOOT_CURR_IMG(state) == LEGACY_CHILD_PARENT_S0_S1_UPDATE_IMAGE_ID && i == 0) { + continue; + } #endif /* CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 */ if (i > 0 && !require_all) { return 0; @@ -1157,10 +1165,13 @@ boot_validate_slot(struct boot_loader_state *state, int slot, #if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION) if (slot != BOOT_PRIMARY_SLOT) { /* Check if version of secondary slot is sufficient */ - #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) \ && defined(CONFIG_PCD_APP) && defined(CONFIG_PCD_READ_NETCORE_APP_VERSION) +#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { +#elif defined(LEGACY_CHILD_PARENT_NETWORK_CORE_UPDATE_ENABLED) + if (BOOT_CURR_IMG(state) == LEGACY_CHILD_PARENT_NETWORK_CORE_UPDATE_IMAGE_ID) { +#endif rc = pcd_version_cmp_net(fap, boot_img_hdr(state, BOOT_SECONDARY_SLOT)); } else { rc = boot_version_cmp( @@ -1243,12 +1254,18 @@ boot_validate_slot(struct boot_loader_state *state, int slot, * Its flash_area hasn't got relevant boundaries. * Therfore need to override its boundaries for the check. */ +#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { +#elif defined(LEGACY_CHILD_PARENT_NETWORK_CORE_UPDATE_ENABLED) + if (BOOT_CURR_IMG(state) == LEGACY_CHILD_PARENT_NETWORK_CORE_UPDATE_IMAGE_ID) { +#endif min_addr = PM_CPUNET_APP_ADDRESS; max_addr = PM_CPUNET_APP_ADDRESS + PM_CPUNET_APP_SIZE; check_addresses = true; } else #endif +#ifndef LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED + /* Sysbuild */ #if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { #if (CONFIG_NCS_IS_VARIANT_IMAGE) @@ -1276,6 +1293,23 @@ boot_validate_slot(struct boot_loader_state *state, int slot, #endif check_addresses = true; } +#else + /* Legacy child/parent support */ + if (BOOT_CURR_IMG(state) == LEGACY_CHILD_PARENT_S0_S1_UPDATE_IMAGE_ID) { +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + min_addr = MIN(pri_fa->fa_off, PM_S0_ADDRESS); + max_addr = MAX((pri_fa->fa_off + pri_fa->fa_size), (PM_S0_ADDRESS + PM_S0_SIZE)); +#else + min_addr = MIN(pri_fa->fa_off, PM_S1_ADDRESS); + max_addr = MAX((pri_fa->fa_off + pri_fa->fa_size), (PM_S1_ADDRESS + PM_S1_SIZE)); +#endif + check_addresses = true; + } else { + min_addr = pri_fa->fa_off; + max_addr = pri_fa->fa_off + pri_fa->fa_size; + check_addresses = true; + } +#endif /* !LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED */ if (check_addresses == true && (reset_value < min_addr || reset_value > max_addr)) { BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot"); @@ -1490,13 +1524,18 @@ boot_validated_swap_type(struct boot_loader_state *state, #else if (reset_addr >= PM_S1_ADDRESS && reset_addr <= (PM_S1_ADDRESS + PM_S1_SIZE)) { #endif +#if !defined(LEGACY_CHILD_PARENT_BUILD) + /* Sysbuild */ if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { /* This is not the s0/s1 upgrade image but the application image, pretend * there is no image so the NSIB update can be loaded */ return BOOT_SWAP_TYPE_NONE; } -#if 0 && defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#else +#if defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED) && defined(CONFIG_SOC_NRF5340_CPUAPP) && \ +defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) + /* Legacy parent/child image */ const struct flash_area *nsib_fa; /* NSIB upgrade slot */ @@ -1512,6 +1551,7 @@ boot_validated_swap_type(struct boot_loader_state *state, /* Set primary to be NSIB upgrade slot */ BOOT_IMG_AREA(state, 0) = nsib_fa; +#endif #endif owner_nsib[BOOT_CURR_IMG(state)] = true; #if (CONFIG_NCS_IS_VARIANT_IMAGE) @@ -2068,9 +2108,15 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) flash_area_close(fap); } -#if defined(PM_S1_ADDRESS) && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 +#if defined(PM_S1_ADDRESS) && (CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED)) if (owner_nsib[BOOT_CURR_IMG(state)]) { +#ifndef LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED + /* Sysbuild */ if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { +#else + /* Legacy child/parent support */ + if (BOOT_CURR_IMG(state) == LEGACY_CHILD_PARENT_S0_S1_UPDATE_IMAGE_ID) { +#endif /* For NSIB, move the image instead of swapping it */ nsib_swap_run(state, bs); @@ -2749,6 +2795,15 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) rc = boot_perform_update(state, &bs); } assert(rc == 0); + +#if defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED) && defined(PM_S1_ADDRESS) && \ +defined(CONFIG_REBOOT) + /* Legacy child/parent support */ + if (owner_nsib[BOOT_CURR_IMG(state)]) { + sys_reboot(SYS_REBOOT_COLD); + } +#endif + break; case BOOT_SWAP_TYPE_FAIL: @@ -2823,7 +2878,12 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) * does not need to also be validated by MCUBoot. */ bool image_validated_by_nsib = BOOT_CURR_IMG(state) == +#ifndef LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER; +#else + LEGACY_CHILD_PARENT_S0_S1_UPDATE_IMAGE_ID; +#endif + if (!image_validated_by_nsib) #endif { diff --git a/boot/bootutil/src/swap_nsib.c b/boot/bootutil/src/swap_nsib.c index 39ed4c652..695733a25 100644 --- a/boot/bootutil/src/swap_nsib.c +++ b/boot/bootutil/src/swap_nsib.c @@ -28,6 +28,8 @@ #include "mcuboot_config/mcuboot_config.h" +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED + BOOT_LOG_MODULE_DECLARE(mcuboot); void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs) @@ -68,3 +70,5 @@ void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs) flash_area_close(fap_pri); flash_area_close(fap_sec); } + +#endif diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 4587681e5..9be69af9e 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -134,6 +134,19 @@ zephyr_library_sources( ) endif() +if(NOT SYSBUILD) + # Check if this is a legacy child/parent image build + cmake_path(GET CMAKE_BINARY_DIR PARENT_PATH parent_build_dir) + string(LENGTH ${parent_build_dir} parent_build_dir_len) + math(EXPR parent_build_dir_len "${parent_build_dir_len} + 1") + string(SUBSTRING ${CMAKE_BINARY_DIR} ${parent_build_dir_len} -1 current_dir_name) + + if(("${current_dir_name}" STREQUAL "mcuboot" OR "${current_dir_name}" STREQUAL "s1_image") AND EXISTS ${parent_build_dir}/image_preload.cmake) + zephyr_compile_definitions(LEGACY_CHILD_PARENT_BUILD=1) + set(LEGACY_CHILD_PARENT_BUILD y) + endif() +endif() + if(CONFIG_SINGLE_APPLICATION_SLOT) zephyr_library_sources( ${BOOT_DIR}/zephyr/single_loader.c @@ -154,6 +167,12 @@ zephyr_library_sources( ) if(NOT CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER EQUAL "-1" AND NOT CONFIG_BOOT_UPGRADE_ONLY) + # Sysbuild + zephyr_library_sources( + ${BOOT_DIR}/bootutil/src/swap_nsib.c + ) + elseif(LEGACY_CHILD_PARENT_BUILD AND NOT CONFIG_BOOT_UPGRADE_ONLY) + # Legacy child/parent image support zephyr_library_sources( ${BOOT_DIR}/bootutil/src/swap_nsib.c ) diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h index 67aca2fc1..e5b818083 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -21,23 +21,42 @@ #define FLASH_AREA_IMAGE_2_SLOTS PM_MCUBOOT_PRIMARY_2_ID, PM_MCUBOOT_SECONDARY_2_ID, #define FLASH_AREA_IMAGE_3_SLOTS PM_MCUBOOT_PRIMARY_3_ID, PM_MCUBOOT_SECONDARY_3_ID, +#ifndef LEGACY_CHILD_PARENT_BUILD +/* Sysbuild */ #if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 #ifdef CONFIG_NCS_IS_VARIANT_IMAGE #define MCUBOOT_S0_S1_SLOTS PM_S0_ID, PM_MCUBOOT_SECONDARY_ID, #else #define MCUBOOT_S0_S1_SLOTS PM_S1_ID, PM_MCUBOOT_SECONDARY_ID, #endif -#define MCUBOOT_IMAGE_NUMBER_WITHOUT_MCUBOOT_S0_S1 (MCUBOOT_IMAGE_NUMBER - 1) #else -#define MCUBOOT_IMAGE_NUMBER_WITHOUT_MCUBOOT_S0_S1 MCUBOOT_IMAGE_NUMBER +#define MCUBOOT_S0_S1_SLOTS +#endif +#else +/* Legacy child/parent image */ +#if defined(PM_B0_ADDRESS) +/* If B0 is present then two bootloaders are present, and we must use + * a single secondary slot for both primary slots. + */ +extern uint32_t _image_1_primary_slot_id[]; +#define MCUBOOT_S0_S1_SLOTS (uint32_t)_image_1_primary_slot_id, PM_MCUBOOT_SECONDARY_ID, +#define LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED 1 +#define LEGACY_CHILD_PARENT_S0_S1_UPDATE_IMAGE_ID 1 +#else +#define MCUBOOT_S0_S1_SLOTS +#endif /* defined(PM_B0_ADDRESS) */ +#if defined(PM_CPUNET_APP_ADDRESS) +#define LEGACY_CHILD_PARENT_NETWORK_CORE_UPDATE_ENABLED 1 +#define LEGACY_CHILD_PARENT_NETWORK_CORE_UPDATE_IMAGE_ID 1 +#endif /* defined(PM_CPUNET_APP_ADDRESS) */ #endif -#if (MCUBOOT_IMAGE_NUMBER == 1) || (MCUBOOT_IMAGE_NUMBER == 2 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1) +#if ((MCUBOOT_IMAGE_NUMBER == 1) || (MCUBOOT_IMAGE_NUMBER == 2 && (CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || (defined(LEGACY_CHILD_PARENT_BUILD) && defined(PM_B0_ADDRESS))))) #define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS -#elif (MCUBOOT_IMAGE_NUMBER == 2) || (MCUBOOT_IMAGE_NUMBER == 3 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1) +#elif ((MCUBOOT_IMAGE_NUMBER == 2) || (MCUBOOT_IMAGE_NUMBER == 3 && (CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || (defined(LEGACY_CHILD_PARENT_BUILD) && defined(PM_B0_ADDRESS))))) #define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS \ FLASH_AREA_IMAGE_1_SLOTS -#elif (MCUBOOT_IMAGE_NUMBER == 3) || (MCUBOOT_IMAGE_NUMBER == 4 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1) +#elif ((MCUBOOT_IMAGE_NUMBER == 3) || (MCUBOOT_IMAGE_NUMBER == 4 && (CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || (defined(LEGACY_CHILD_PARENT_BUILD) && defined(PM_B0_ADDRESS))))) #define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS \ FLASH_AREA_IMAGE_1_SLOTS \ FLASH_AREA_IMAGE_2_SLOTS From 30525e9a759fc0a8235dcdecd05a72c0e982ad1c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 8 Oct 2024 11:59:51 +0100 Subject: [PATCH 3/4] [nrf noup] boot: zephyr: Fix partition manager config fixup! [nrf noup] treewide: add NCS partition manager support Fixes an issue whereby the end address of MCUboot had no alignment requirements what-so-ever and would produce completely invalid configurations for NSIB that prevented it from being upgradeable Signed-off-by: Jamie McCrae --- boot/zephyr/pm.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml index eabe3d08e..13ffc44aa 100644 --- a/boot/zephyr/pm.yml +++ b/boot/zephyr/pm.yml @@ -4,6 +4,9 @@ mcuboot: size: CONFIG_PM_PARTITION_SIZE_MCUBOOT placement: before: [mcuboot_primary] +#if defined(CONFIG_HIDE_CHILD_PARENT_CONFIG) + align: {end: 0x1000} +#endif mcuboot_primary_app: # All images to be placed in MCUboot's slot 0 should be placed in this From 652fa0a1d4a72d30e738dff6715b01cb99b23040 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 8 Oct 2024 14:01:58 +0100 Subject: [PATCH 4/4] [nrf noup] boot: bootutil: loader: Fix image clean-up for sysbuild Fixes the implementation so that it works with sysbuild. This will need to be reworked separately when support for parent/child images is removed Signed-off-by: Jamie McCrae --- boot/bootutil/src/loader.c | 50 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 5c9bb1069..caf953108 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1388,6 +1388,11 @@ boot_update_security_counter(uint8_t image_index, int slot, #define SEC_SLOT_TOUCHED 1 #define SEC_SLOT_ASSIGNED 2 +#if !defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED) +/* Sysbuild */ +static uint8_t sec_slot_assignmnet[MCUBOOT_IMAGE_NUMBER] = {0}; +#else +/* Legacy child/parent image */ #if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) /* This configuration is peculiar - the one physical secondary slot is @@ -1399,21 +1404,56 @@ boot_update_security_counter(uint8_t image_index, int slot, #endif static uint8_t sec_slot_assignmnet[SEC_SLOT_PHYSICAL_CNT] = {0}; +#endif static inline void sec_slot_touch(struct boot_loader_state *state) { +#if !defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED) + /* Sysbuild */ +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + if (sec_slot_assignmnet[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] == SEC_SLOT_VIRGIN) { + sec_slot_assignmnet[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] = SEC_SLOT_TOUCHED; + } + } else if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { + if (sec_slot_assignmnet[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] == SEC_SLOT_VIRGIN) { + sec_slot_assignmnet[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] = SEC_SLOT_TOUCHED; + } + } +#endif + + if (sec_slot_assignmnet[BOOT_CURR_IMG(state)] == SEC_SLOT_VIRGIN) { + sec_slot_assignmnet[BOOT_CURR_IMG(state)] = SEC_SLOT_TOUCHED; + } +#else + /* Legacy child/parent image */ uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); if (SEC_SLOT_VIRGIN == sec_slot_assignmnet[idx]) { sec_slot_assignmnet[idx] = SEC_SLOT_TOUCHED; } +#endif } static inline void sec_slot_mark_assigned(struct boot_loader_state *state) { +#if !defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED) + /* Sysbuild */ +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + sec_slot_assignmnet[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] = SEC_SLOT_ASSIGNED; + } else if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { + sec_slot_assignmnet[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] = SEC_SLOT_ASSIGNED; + } +#endif + + sec_slot_assignmnet[BOOT_CURR_IMG(state)] = SEC_SLOT_ASSIGNED; +#else + /* Legacy child/parent image */ uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); sec_slot_assignmnet[idx] = SEC_SLOT_ASSIGNED; +#endif } /** @@ -1429,7 +1469,13 @@ static void sec_slot_cleanup_if_unusable(void) { uint8_t idx; +#if !defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED) + /* Sysbuild */ + for (idx = 0; idx < MCUBOOT_IMAGE_NUMBER; idx++) { +#else + /* Legacy child/parent image */ for (idx = 0; idx < SEC_SLOT_PHYSICAL_CNT; idx++) { +#endif if (SEC_SLOT_TOUCHED == sec_slot_assignmnet[idx]) { const struct flash_area *secondary_fa; int rc; @@ -1439,12 +1485,12 @@ static void sec_slot_cleanup_if_unusable(void) if (!rc) { rc = flash_area_erase(secondary_fa, 0, secondary_fa->fa_size); if (!rc) { - BOOT_LOG_ERR("Cleaned-up secondary slot of %d. image.", idx); + BOOT_LOG_ERR("Cleaned-up secondary slot of image %d", idx); } } if (rc) { - BOOT_LOG_ERR("Can not cleanup secondary slot of %d. image.", idx); + BOOT_LOG_ERR("Failed to clean-up secondary slot of image %d: %d", idx, rc); } } }