From 95cf231747707958e361236fde8d7193aa7a35f9 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 6 Nov 2025 17:31:40 +0100 Subject: [PATCH 001/149] Revert "[nrf noup] bootutil: ed25519_psa: multi verification revocation" This reverts commit 0d263faf6e55a697ee336f2fbef0af095802f979. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/ed25519_psa.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 87097f36c..541fc0155 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -45,8 +45,7 @@ static psa_key_id_t key_ids[] = { #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) #include -#define VALIDATED_WITH_UNINITIALIZED INT32_MAX -static int32_t validated_with = VALIDATED_WITH_UNINITIALIZED; +static psa_key_id_t *validated_with = NULL; #endif BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(key_ids), @@ -143,9 +142,7 @@ int ED25519_verify(const uint8_t *message, size_t message_len, EDDSA_SIGNAGURE_LENGTH); if (status == PSA_SUCCESS) { #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) - if(i < validated_with) { - validated_with = i; - } + validated_with = key_ids + i; #endif return 1; } @@ -162,7 +159,7 @@ int exec_revoke(void) int ret = BOOT_KEY_REVOKE_OK; psa_status_t status = psa_crypto_init(); - if (validated_with == VALIDATED_WITH_UNINITIALIZED) { + if (!validated_with) { ret = BOOT_KEY_REVOKE_INVALID; goto out; } @@ -173,7 +170,7 @@ int exec_revoke(void) goto out; } for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; i++) { - if ( i == validated_with) { + if ((key_ids + i) == validated_with) { break; } BOOT_LOG_DBG("Invalidating key ID %d", i); @@ -182,7 +179,7 @@ int exec_revoke(void) if (status == PSA_SUCCESS) { BOOT_LOG_DBG("Success on key ID %d", i); } else { - BOOT_LOG_DBG("Key invalidation failed with: %d", status); + BOOT_LOG_ERR("Key invalidation failed with: %d", status); } } out: From 4637f808483b18f04fa11fd1b90c8b89d42f693f Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 4 Nov 2025 16:33:24 +0100 Subject: [PATCH 002/149] Revert "[nrf noup] bootutil: Fix ITS key locking compile error" This reverts commit 459288d6a13cede9fa09e314b21a979a6cc6e3f2. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/ed25519_psa.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 541fc0155..c7e3910b1 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -187,7 +187,6 @@ int exec_revoke(void) } #endif /* CONFIG_BOOT_KMU_KEYS_REVOCATION */ -#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) void nrf_crypto_keys_housekeeping(void) { psa_status_t status; @@ -213,6 +212,5 @@ void nrf_crypto_keys_housekeeping(void) key_ids[i], i, status); } } -#endif #endif From 066f15dfe79e040dfe01f3e298f23d4ef3b8ee35 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 4 Nov 2025 16:33:49 +0100 Subject: [PATCH 003/149] Revert "[nrf noup] Handle pending confirm requests" This reverts commit 484a6f30394abbc2b9f404e715e99271fcf926aa. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/bootutil_public.c | 91 +++++++++---------- .../zephyr/src/boot_request_retention.c | 2 + boot/zephyr/Kconfig | 11 +++ 3 files changed, 54 insertions(+), 50 deletions(-) diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index 7365eac5b..f54dd6151 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -398,59 +398,9 @@ boot_write_image_ok(const struct flash_area *fap) return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET); } -#if defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) -static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) -{ - int id = flash_area_get_id(fa); -#if BOOT_IMAGE_NUMBER > 1 - uint8_t i = 0; - - for (i = 0; i < BOOT_IMAGE_NUMBER; i++) { - if (FLASH_AREA_IMAGE_PRIMARY(i) == id) { - if (slot != NULL) { - *slot = 0; - } - return i; - } else if (FLASH_AREA_IMAGE_SECONDARY(i) == id) { - if (slot != NULL) { - *slot = 1; - } - return i; - } - } - - /* Image not found */ - *slot = UINT32_MAX; -#else - (void)fa; - if (slot != NULL) { - if (FLASH_AREA_IMAGE_PRIMARY(0) == id) { - *slot = 0; - } else if (FLASH_AREA_IMAGE_SECONDARY(0) == id) { - *slot = 1; - } else { - *slot = UINT32_MAX; - } - } -#endif - return 0; -} -#endif /* SEND_BOOT_REQUEST || !MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP */ - int boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok) { -#ifdef SEND_BOOT_REQUEST - enum boot_slot slot_id = BOOT_SLOT_NONE; - int image_id = flash_area_to_image_slot(fap, &slot_id); - bool confirm_pending = boot_request_check_confirmed_slot(image_id, slot_id); - - if (confirm_pending) { - BOOT_LOG_DBG("Image confirmation pending for image %d slot %d", image_id, slot_id); - *image_ok = BOOT_FLAG_SET; - return 0; - } -#endif /* SEND_BOOT_REQUEST */ return boot_read_flag(fap, image_ok, boot_image_ok_off(fap)); } @@ -591,6 +541,47 @@ send_boot_request(uint8_t magic, uint8_t image_ok, bool confirm, int image_id, } #endif /* SEND_BOOT_REQUEST */ +#if defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) +static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) +{ + int id = flash_area_get_id(fa); +#if BOOT_IMAGE_NUMBER > 1 + uint8_t i = 0; + + while (i < BOOT_IMAGE_NUMBER) { + if (FLASH_AREA_IMAGE_PRIMARY(i) == id) { + if (slot != NULL) { + *slot = 0; + } + return i; + } else if (FLASH_AREA_IMAGE_SECONDARY(i) == id) { + if (slot != NULL) { + *slot = 1; + } + return i; + } + + ++i; + } + + /* Image not found */ + *slot = UINT32_MAX; +#else + (void)fa; + if (slot != NULL) { + if (FLASH_AREA_IMAGE_PRIMARY(0) == id) { + *slot = 0; + } else if (FLASH_AREA_IMAGE_SECONDARY(0) == id) { + *slot = 1; + } else { + *slot = UINT32_MAX; + } + } +#endif + return 0; +} +#endif /* defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) */ + #ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP int boot_set_next(const struct flash_area *fa, bool active, bool confirm) diff --git a/boot/bootutil/zephyr/src/boot_request_retention.c b/boot/bootutil/zephyr/src/boot_request_retention.c index 9cde6da04..e7fc393a0 100644 --- a/boot/bootutil/zephyr/src/boot_request_retention.c +++ b/boot/bootutil/zephyr/src/boot_request_retention.c @@ -236,6 +236,7 @@ int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot) sizeof(value)); } +#ifdef CONFIG_FIND_NEXT_SLOT_HOOKS enum boot_slot boot_request_get_preferred_slot(uint8_t image) { uint8_t value = BOOT_REQUEST_SLOT_INVALID; @@ -264,6 +265,7 @@ enum boot_slot boot_request_get_preferred_slot(uint8_t image) return BOOT_SLOT_NONE; } +#endif /* CONFIG_FIND_NEXT_SLOT_HOOKS */ int boot_request_enter_recovery(void) { diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 222a724a5..49b458e8e 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1441,4 +1441,15 @@ config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS Time between image validation attempts, in milliseconds. Allows for recovery from transient bit flips or similar situations. +config NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE + bool "Set boot preference if a slot is marked for test" + help + This option allows to verify boot preference requests through issuing + the image test. + Using this option is not recommended in production systems, because + it will boot any newly transferred image, even if it has a lower + version than the current one. + The rollback protection (using security counters) will still be + effective. + source "Kconfig.zephyr" From ffa4a652694212dee8197d0096b36d8cecbc5308 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:12:06 +0200 Subject: [PATCH 004/149] Revert "[nrf noup] boot: zephyr: remove nonsecure ram cleanup" This reverts commit 4adc4f628cdbf0a65e09737d7c297f7080f6922e. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/CMakeLists.txt | 2 +- boot/zephyr/main.c | 5 ++++- boot/zephyr/nrf_cleanup.c | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index b34824def..36416b61c 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -773,7 +773,7 @@ if(SYSBUILD) set(mcuboot_image_upgrade_footer_size ${required_upgrade_size} CACHE INTERNAL "Estimated MCUboot update image trailer size" FORCE) endif() -if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL) +if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL OR CONFIG_MCUBOOT_CLEANUP_NONSECURE_RAM) zephyr_library_sources( ${BOOT_DIR}/zephyr/nrf_cleanup.c ) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index ad36a60a2..8418eabe9 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -158,7 +158,7 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #include #endif -#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL +#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL || CONFIG_MCUBOOT_NRF_CLEANUP_NONSECURE_RAM #include #endif @@ -398,6 +398,9 @@ static void do_boot(struct boot_rsp *rsp) #if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL nrf_cleanup_peripheral(); #endif +#if CONFIG_MCUBOOT_NRF_CLEANUP_NONSECURE_RAM && defined(PM_SRAM_NONSECURE_NAME) + nrf_cleanup_ns_ram(); +#endif #if CONFIG_MCUBOOT_CLEANUP_ARM_CORE cleanup_arm_interrupts(); /* Disable and acknowledge all interrupts */ diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index c1e5a178e..b5b4d16e1 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -184,3 +184,12 @@ void nrf_cleanup_peripheral(void) nrf_cleanup_clock(); #endif } + +#if USE_PARTITION_MANAGER \ + && defined(CONFIG_ARM_TRUSTZONE_M) \ + && defined(PM_SRAM_NONSECURE_NAME) +void nrf_cleanup_ns_ram(void) +{ + memset((void *) PM_SRAM_NONSECURE_ADDRESS, 0, PM_SRAM_NONSECURE_SIZE); +} +#endif From 6a3baddfe1bc6340501dc0fb85ccbb84a3eadc3c Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:53 +0200 Subject: [PATCH 005/149] Revert "[nrf noup] boot: zephyr: Region protection adjustments for nRF54L" This reverts commit 697ca33a67777cf55045d1b33ababc9511eaa227. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/Kconfig | 8 +---- boot/zephyr/main.c | 73 ++++++--------------------------------------- 2 files changed, 10 insertions(+), 71 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 49b458e8e..fb8d7e2fd 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -496,15 +496,9 @@ config MCUBOOT_CLEANUP_RAM help Sets contents of memory to 0 before jumping to application. -config NCS_MCUBOOT_DISABLE_SELF_RWX_SUPPORTED - bool - default y if SOC_NRF54L15_CPUAPP || SOC_NRF54L10_CPUAPP || SOC_NRF54L05_CPUAPP - default y if SOC_NRF54LV10A_ENGA_CPUAPP - default y if SOC_NRF54LM20A_ENGA_CPUAPP - config NCS_MCUBOOT_DISABLE_SELF_RWX bool "Disable read and execution on self NVM" - depends on NCS_MCUBOOT_DISABLE_SELF_RWX_SUPPORTED && !FPROTECT + depends on (SOC_NRF54L15_CPUAPP || SOC_NRF54L10_CPUAPP || SOC_NRF54L05_CPUAPP) && !FPROTECT help Sets RRAMC's region no.4 protection before jumping to application. It disables reads writes and execution memory area which holds MCUBOOT. diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 8418eabe9..fe8e743e7 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -150,12 +150,9 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); * !defined(CONFIG_LOG_MODE_MINIMAL) */ -#if USE_PARTITION_MANAGER -#include -#endif - #if USE_PARTITION_MANAGER && CONFIG_FPROTECT #include +#include #endif #if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL || CONFIG_MCUBOOT_NRF_CLEANUP_NONSECURE_RAM @@ -176,48 +173,9 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #define RRAMC_REGION_RWX_LSB 0 #define RRAMC_REGION_RWX_WIDTH 3 - -#define RRAMC_REGION_NUMBER 4 -#define NRF_RRAM_REGION_SIZE_UNIT 0x400 -#define NRF_RRAM_REGION_ADDRESS_RESOLUTION 0x400 - -#if defined(CONFIG_SOC_NRF54L15_CPUAPP) || defined(CONFIG_SOC_NRF54L05_CPUAPP) || \ - defined(CONFIG_SOC_NRF54L10_CPUAPP) -#define MAX_PROTECTED_REGION_SIZE (31 * 1024) -#elif defined(CONFIG_SOC_NRF54LV10A_ENGA_CPUAPP) || defined(CONFIG_SOC_NRF54LM20A_ENGA_CPUAPP) -#define MAX_PROTECTED_REGION_SIZE (127 * 1024) -#elif defined(CONFIG_SOC_NRF54LS05B_ENGA_CPUAPP) -#define MAX_PROTECTED_REGION_SIZE (1023 * 1024) -#endif - -#define RRAMC_REGION_CONFIG NRF_RRAMC->REGION[RRAMC_REGION_NUMBER].CONFIG -#define RRAMC_REGION_CONFIG_H (((uint32_t)(&(RRAMC_REGION_CONFIG))) >> 16) -#define RRAMC_REGION_CONFIG_L (((uint32_t)(&(RRAMC_REGION_CONFIG))) & 0x0000fffful) - -#define RRAMC_REGION_ADDRESS NRF_RRAMC->REGION[RRAMC_REGION_NUMBER].ADDRESS -#define RRAMC_REGION_ADDRESS_H (((uint32_t)(&(RRAMC_REGION_ADDRESS))) >> 16) -#define RRAMC_REGION_ADDRESS_L (((uint32_t)(&(RRAMC_REGION_ADDRESS))) & 0x0000fffful) - -#if (CONFIG_NCS_IS_VARIANT_IMAGE) -#define PROTECTED_REGION_START PM_S1_IMAGE_ADDRESS -#define PROTECTED_REGION_SIZE PM_S1_IMAGE_SIZE -#else -#define PROTECTED_REGION_START PM_MCUBOOT_ADDRESS -#define PROTECTED_REGION_SIZE PM_MCUBOOT_SIZE -#endif - -BUILD_ASSERT((PROTECTED_REGION_START % NRF_RRAM_REGION_ADDRESS_RESOLUTION) == 0, - "Start of protected region is not aligned - not possible to protect"); - -BUILD_ASSERT((PROTECTED_REGION_SIZE % NRF_RRAM_REGION_SIZE_UNIT) == 0, - "Size of protected region is not aligned - not possible to protect"); - -BUILD_ASSERT(PROTECTED_REGION_SIZE <= MAX_PROTECTED_REGION_SIZE, - "Size of protected region is too big for protection"); - -#define PROTECTED_REGION_START_H ((PROTECTED_REGION_START) >> 16) -#define PROTECTED_REGION_START_L ((PROTECTED_REGION_START) & 0x0000fffful) - +#define RRAMC_REGION_TO_LOCK_ADDR NRF_RRAMC->REGION[4].CONFIG +#define RRAMC_REGION_TO_LOCK_ADDR_H (((uint32_t)(&(RRAMC_REGION_TO_LOCK_ADDR))) >> 16) +#define RRAMC_REGION_TO_LOCK_ADDR_L (((uint32_t)(&(RRAMC_REGION_TO_LOCK_ADDR))) & 0x0000fffful) #endif /* CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX */ BOOT_LOG_MODULE_REGISTER(mcuboot); @@ -287,20 +245,11 @@ static void __ramfunc jump_in(uint32_t reset) " ldr r2, [r1]\n" /* Size of the region should be set at this point * by NSIB's DISABLE_NEXT_W. - * If not, the region has not been configured yet. - * Set the size and address to the partition size and address. + * If not, set it according partition size. */ " ands r4, r2, %12\n" " cbnz r4, clear_rwx\n" - /* Set the size of the protected region */ " movt r2, %8\n" - /* Set the address of the protected region */ - " movw r5, %13\n" - " movt r5, %14\n" - " movw r6, %15\n" - " movt r6, %16\n" - " str r6, [r5]\n" - " dsb\n" "clear_rwx:\n" " bfc r2, %9, %10\n" /* Disallow further modifications */ @@ -321,17 +270,13 @@ static void __ramfunc jump_in(uint32_t reset) "r" (CLEANUP_RAM_GAP_SIZE), "i" (0) #ifdef CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX - , "i" (RRAMC_REGION_CONFIG_L), - "i" (RRAMC_REGION_CONFIG_H), - "i" ((PROTECTED_REGION_SIZE) / (NRF_RRAM_REGION_SIZE_UNIT)), + , "i" (RRAMC_REGION_TO_LOCK_ADDR_L), + "i" (RRAMC_REGION_TO_LOCK_ADDR_H), + "i" (CONFIG_PM_PARTITION_SIZE_B0_IMAGE / 1024), "i" (RRAMC_REGION_RWX_LSB), "i" (RRAMC_REGION_RWX_WIDTH), "i" (RRAMC_REGION_CONFIG_LOCK_Msk), - "i" (RRAMC_REGION_CONFIG_SIZE_Msk), - "i" (RRAMC_REGION_ADDRESS_L), - "i" (RRAMC_REGION_ADDRESS_H), - "i" (PROTECTED_REGION_START_L), - "i" (PROTECTED_REGION_START_H) + "i" (RRAMC_REGION_CONFIG_SIZE_Msk) #endif /* CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX */ : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory" ); From 9ea02631ac615d4b3f6cd6f51d239c076f82854b Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:53 +0200 Subject: [PATCH 006/149] Revert "[nrf noup] boards/thingy53_nrf5340_cpuapp: defaulat to LTO" This reverts commit 473f7d775201ad1f7276330f206cd1823eb9149c. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index 4c27c5da6..bbef18460 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -73,6 +73,3 @@ CONFIG_FLASH_SIMULATOR_STATS=n # Enable custom command to erase settings partition. CONFIG_ENABLE_MGMT_PERUSER=y CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE=y - -CONFIG_ISR_TABLES_LOCAL_DECLARATION=y -CONFIG_LTO=y From 7ba1005e7222c9763a132db33f29cfc322b2e812 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 007/149] Revert "[nrf noup] boot/zephyr: improve S2RAM resume support using dedicated API" This reverts commit dd353bcef4b90e0aa93cf12b7fec880e048f640e. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 4 +-- boot/zephyr/CMakeLists.txt | 3 +- boot/zephyr/nrf54h20_custom_s2ram.S | 43 ----------------------------- boot/zephyr/nrf54h20_custom_s2ram.c | 17 ++++++++++-- 4 files changed, 18 insertions(+), 49 deletions(-) delete mode 100644 boot/zephyr/nrf54h20_custom_s2ram.S diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index faffab03a..896b15894 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -84,7 +84,7 @@ int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); #include "bootutil/key_revocation.h" #endif -#ifdef CONFIG_SOC_EARLY_RESET_HOOK +#ifdef CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE void s2ram_designate_slot(uint8_t slot); #endif @@ -3434,7 +3434,7 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } } -#ifdef CONFIG_SOC_EARLY_RESET_HOOK +#ifdef CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE /* Designate the slot to be used by the PM_S2RAM resume module */ s2ram_designate_slot((uint8_t)state->slot_usage[0].active_slot); #endif diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 36416b61c..7d4648db7 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -496,8 +496,7 @@ if(CONFIG_MCUBOOT_CLEANUP_ARM_CORE) ) endif() -if(CONFIG_SOC_EARLY_RESET_HOOK) - zephyr_library_sources(${BOOT_DIR}/zephyr/nrf54h20_custom_s2ram.S) +if(CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE) zephyr_library_sources(${BOOT_DIR}/zephyr/nrf54h20_custom_s2ram.c) endif() diff --git a/boot/zephyr/nrf54h20_custom_s2ram.S b/boot/zephyr/nrf54h20_custom_s2ram.S deleted file mode 100644 index 1ffa17f42..000000000 --- a/boot/zephyr/nrf54h20_custom_s2ram.S +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2025, Nordic Semiconductor ASA - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * @brief ARM Cortex-M suspend-to-RAM resume intermediary code (S2RAM) - */ - - - -/* - * resume or - * reboot reboot==T - *[S2RAM sleep]---------->[ boot (reset.S) ]---->[soc_early_reset_hook]---------->[regular boot] - * | - * | resume==T - * \/ - * [jump to well-known] - * [ App reset vector ] - */ - - - -#include -#include - -GTEXT(pm_s2ram_mark_check_and_mediate) - -GTEXT(soc_early_reset_hook) -SECTION_FUNC(TEXT, soc_early_reset_hook) -#if DT_NODE_EXISTS(DT_NODELABEL(pm_s2ram_stack)) &&\ - DT_NODE_HAS_COMPAT(DT_NODELABEL(pm_s2ram_stack), zephyr_memory_region) - ldr r0, =DT_REG_ADDR(DT_NODELABEL(pm_s2ram_stack)) + DT_REG_SIZE(DT_NODELABEL(pm_s2ram_stack)) -#else -#error "The support of bridge for S2RAM resume requires dedicated small stack" -#endif - msr msp, r0 - push {r0, lr} - bl pm_s2ram_mark_check_and_mediate - pop {r0, pc} diff --git a/boot/zephyr/nrf54h20_custom_s2ram.c b/boot/zephyr/nrf54h20_custom_s2ram.c index faa8d9b46..51146e7b3 100644 --- a/boot/zephyr/nrf54h20_custom_s2ram.c +++ b/boot/zephyr/nrf54h20_custom_s2ram.c @@ -45,6 +45,17 @@ void s2ram_designate_slot(uint8_t slot) } #endif +int soc_s2ram_suspend(pm_s2ram_system_off_fn_t system_off) +{ + (void)(system_off); + return -1; +} + +void pm_s2ram_mark_set(void) +{ + /* empty */ +} + struct arm_vector_table { uint32_t msp; uint32_t reset; @@ -55,13 +66,13 @@ struct arm_vector_table { */ #define APP_EXE_START_OFFSET 0x800 /* nRF54H20 */ -void pm_s2ram_mark_check_and_mediate(void) +bool pm_s2ram_mark_check_and_clear(void) { uint32_t reset_reason = nrf_resetinfo_resetreas_local_get(NRF_RESETINFO); if (reset_reason != NRF_RESETINFO_RESETREAS_LOCAL_UNRETAINED_MASK) { /* Normal boot */ - return; + return false; } /* S2RAM resume expected, do doublecheck */ @@ -109,4 +120,6 @@ void pm_s2ram_mark_check_and_mediate(void) resume_failed: FIH_PANIC; + + return true; } From adcdc1198c80708f4b8e34436b75dabb90eb13dc Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 008/149] Revert "[nrf noup] bootutil: Use correct set of KMU key slots" This reverts commit 754f9586875dd72de367704e42c2121eb60696c3. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/ed25519_psa.c | 15 +++------------ boot/zephyr/Kconfig | 11 ----------- 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index c7e3910b1..3df1acbdd 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -25,20 +25,11 @@ BOOT_LOG_MODULE_REGISTER(ed25519_psa); #if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) /* List of KMU stored key ids available for MCUboot */ -#define PSA_KEY_INDEX_SIZE 2 - -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || \ - defined(CONFIG_NCS_BOOT_SIGNATURE_KMU_UROT_MAPPING) -#define PSA_KEY_STARTING_ID 226 -#else -#define PSA_KEY_STARTING_ID 242 -#endif - #define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id) static psa_key_id_t key_ids[] = { - MAKE_PSA_KMU_KEY_ID(PSA_KEY_STARTING_ID), - MAKE_PSA_KMU_KEY_ID(PSA_KEY_STARTING_ID + PSA_KEY_INDEX_SIZE), - MAKE_PSA_KMU_KEY_ID(PSA_KEY_STARTING_ID + (2 * PSA_KEY_INDEX_SIZE)) + MAKE_PSA_KMU_KEY_ID(226), + MAKE_PSA_KMU_KEY_ID(228), + MAKE_PSA_KMU_KEY_ID(230) }; #define KEY_SLOTS_COUNT CONFIG_BOOT_SIGNATURE_KMU_SLOTS diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index fb8d7e2fd..4815598ac 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -421,17 +421,6 @@ config BOOT_SIGNATURE_KMU_SLOTS Selects the number of KMU key slots (also known as generations) to use when verifying an image. -config NCS_BOOT_SIGNATURE_KMU_UROT_MAPPING - bool "Use original mapping [DEPRECATED]" - depends on SOC_SERIES_NRF54LX - depends on MCUBOOT_MCUBOOT_IMAGE_NUMBER = -1 - select DEPRECATED - help - When this option is enabled, it will use the UROT_PUBKEY key slot IDs for the MCUboot - image which are assigned for the non-immutable bootloader IDs, otherwise it will use - the key set for the mode that MCUboot is used in (non-immutable slots when b0 is - enabled, or immutable slots when b0 is not enabled). - endif config BOOT_KEYS_REVOCATION From 98a7dc774eeb9a851a5a6a91985793c05d477994 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 009/149] Revert "[nrf noup] bootutil/loader: integrate nRF54h S2RAM with diect-xip" This reverts commit 1c8a5953c5411bb1e453c3747a4d13ac0680ff14. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 896b15894..5ab1a75c7 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -84,10 +84,6 @@ int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); #include "bootutil/key_revocation.h" #endif -#ifdef CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE -void s2ram_designate_slot(uint8_t slot); -#endif - BOOT_LOG_MODULE_DECLARE(mcuboot); static struct boot_loader_state boot_data; @@ -3434,11 +3430,6 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } } -#ifdef CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE - /* Designate the slot to be used by the PM_S2RAM resume module */ - s2ram_designate_slot((uint8_t)state->slot_usage[0].active_slot); -#endif - /* All image loaded successfully. */ #ifdef MCUBOOT_HAVE_LOGGING print_loaded_images(state); From 760b114eea18697160b3109ab336b5465fd3906d Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 010/149] Revert "[nrf noup] mcuboot: Use dedicated type for slot numbers" This reverts commit 85349537b3bc4e8e9e7542abd0303adf28177dcb. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/include/bootutil/boot_request.h | 11 ++++--- boot/bootutil/src/bootutil_public.c | 2 +- .../zephyr/src/boot_request_retention.c | 30 +++++++++---------- boot/zephyr/main.c | 4 +-- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/boot/bootutil/include/bootutil/boot_request.h b/boot/bootutil/include/bootutil/boot_request.h index c92a91d4e..b1e8f891e 100644 --- a/boot/bootutil/include/bootutil/boot_request.h +++ b/boot/bootutil/include/bootutil/boot_request.h @@ -13,7 +13,6 @@ extern "C" { #include #include -#include /** Special value, indicating that there is no preferred slot. */ #define BOOT_REQUEST_NO_PREFERRED_SLOT UINT32_MAX @@ -26,7 +25,7 @@ extern "C" { * * @return 0 if requested, negative error code otherwise. */ -int boot_request_confirm_slot(uint8_t image, enum boot_slot slot); +int boot_request_confirm_slot(uint8_t image, uint32_t slot); /** * @brief Request a bootloader to boot the specified slot of an image. @@ -36,7 +35,7 @@ int boot_request_confirm_slot(uint8_t image, enum boot_slot slot); * * @return 0 if requested, negative error code otherwise. */ -int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot); +int boot_request_set_preferred_slot(uint8_t image, uint32_t slot); /** * @brief Request a bootloader to boot recovery image. @@ -60,16 +59,16 @@ int boot_request_enter_firmware_loader(void); * * @return true if requested, false otherwise. */ -bool boot_request_check_confirmed_slot(uint8_t image, enum boot_slot slot); +bool boot_request_check_confirmed_slot(uint8_t image, uint32_t slot); /** * @brief Find if there is a request to boot certain slot of the specified image. * * @param[in] image Image number. * - * @return slot number if requested, BOOT_SLOT_NONE otherwise. + * @return slot number if requested, BOOT_REQUEST_NO_PREFERRED_SLOT otherwise. */ -enum boot_slot boot_request_get_preferred_slot(uint8_t image); +uint32_t boot_request_get_preferred_slot(uint8_t image); /** * @brief Check if there is a request to boot recovery image. diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index f54dd6151..0f8857e4d 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -511,7 +511,7 @@ boot_write_copy_done(const struct flash_area *fap) #ifdef SEND_BOOT_REQUEST static int send_boot_request(uint8_t magic, uint8_t image_ok, bool confirm, int image_id, - enum boot_slot slot_id) + uint32_t slot_id) { int rc = BOOT_EBADIMAGE; diff --git a/boot/bootutil/zephyr/src/boot_request_retention.c b/boot/bootutil/zephyr/src/boot_request_retention.c index e7fc393a0..234dfb5cf 100644 --- a/boot/bootutil/zephyr/src/boot_request_retention.c +++ b/boot/bootutil/zephyr/src/boot_request_retention.c @@ -155,7 +155,7 @@ int boot_request_clear(void) return retention_clear(bootloader_request_dev); } -int boot_request_confirm_slot(uint8_t image, enum boot_slot slot) +int boot_request_confirm_slot(uint8_t image, uint32_t slot) { uint8_t value = BOOT_REQUEST_SLOT_INVALID; size_t req_entry; @@ -167,10 +167,10 @@ int boot_request_confirm_slot(uint8_t image, enum boot_slot slot) } switch (slot) { - case BOOT_SLOT_PRIMARY: + case 0: value = BOOT_REQUEST_SLOT_PRIMARY; break; - case BOOT_SLOT_SECONDARY: + case 1: value = BOOT_REQUEST_SLOT_SECONDARY; break; default: @@ -181,7 +181,7 @@ int boot_request_confirm_slot(uint8_t image, enum boot_slot slot) sizeof(value)); } -bool boot_request_check_confirmed_slot(uint8_t image, enum boot_slot slot) +bool boot_request_check_confirmed_slot(uint8_t image, uint32_t slot) { uint8_t value = BOOT_REQUEST_SLOT_INVALID; size_t req_entry; @@ -200,9 +200,9 @@ bool boot_request_check_confirmed_slot(uint8_t image, enum boot_slot slot) switch (value) { case BOOT_REQUEST_SLOT_PRIMARY: - return (slot == BOOT_SLOT_PRIMARY); + return (slot == 0); case BOOT_REQUEST_SLOT_SECONDARY: - return (slot == BOOT_SLOT_SECONDARY); + return (slot == 1); default: break; } @@ -210,7 +210,7 @@ bool boot_request_check_confirmed_slot(uint8_t image, enum boot_slot slot) return false; } -int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot) +int boot_request_set_preferred_slot(uint8_t image, uint32_t slot) { uint8_t value = BOOT_REQUEST_SLOT_INVALID; size_t req_entry; @@ -222,10 +222,10 @@ int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot) } switch (slot) { - case BOOT_SLOT_PRIMARY: + case 0: value = BOOT_REQUEST_SLOT_PRIMARY; break; - case BOOT_SLOT_SECONDARY: + case 1: value = BOOT_REQUEST_SLOT_SECONDARY; break; default: @@ -237,7 +237,7 @@ int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot) } #ifdef CONFIG_FIND_NEXT_SLOT_HOOKS -enum boot_slot boot_request_get_preferred_slot(uint8_t image) +uint32_t boot_request_get_preferred_slot(uint8_t image) { uint8_t value = BOOT_REQUEST_SLOT_INVALID; size_t req_entry; @@ -245,25 +245,25 @@ enum boot_slot boot_request_get_preferred_slot(uint8_t image) ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry); if (ret != 0) { - return BOOT_SLOT_NONE; + return BOOT_REQUEST_NO_PREFERRED_SLOT; } ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, sizeof(value)); if (ret != 0) { - return BOOT_SLOT_NONE; + return BOOT_REQUEST_NO_PREFERRED_SLOT; } switch (value) { case BOOT_REQUEST_SLOT_PRIMARY: - return BOOT_SLOT_PRIMARY; + return 0; case BOOT_REQUEST_SLOT_SECONDARY: - return BOOT_SLOT_SECONDARY; + return 1; default: break; } - return BOOT_SLOT_NONE; + return BOOT_REQUEST_NO_PREFERRED_SLOT; } #endif /* CONFIG_FIND_NEXT_SLOT_HOOKS */ diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index fe8e743e7..14410c66a 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -619,7 +619,7 @@ static int boot_prevalidate(void) { #ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST uint8_t image_index; - enum boot_slot slot; + uint32_t slot; uint32_t area_id; const struct flash_area *fap; int rc = boot_request_init(); @@ -629,7 +629,7 @@ static int boot_prevalidate(void) } for (image_index = 0; image_index < BOOT_IMAGE_NUMBER; ++image_index) { - for (slot = BOOT_SLOT_PRIMARY; slot < BOOT_SLOT_COUNT; slot++) { + for (slot = 0; slot < BOOT_REQUEST_NUM_SLOTS; slot++) { if (boot_request_check_confirmed_slot(image_index, slot)) { BOOT_LOG_DBG("Confirm image: %d slot: %d due to bootloader request.", image_index, slot); From 9cd9e799e7dccc22ee017db7414b71896c81aeca Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 011/149] Revert "[nrf noup] nrf_cleanup: temporary GRTC cleanup with no counter reset" This reverts commit 511e742327020ebe42df2e4b45a3ca8d0f3e6611. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/nrf_cleanup.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index b5b4d16e1..e261d1914 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -52,35 +52,9 @@ static inline void nrf_cleanup_rtc(NRF_RTC_Type * rtc_reg) #endif #if defined(CONFIG_NRF_GRTC_TIMER) - -/** - * This function is temporary and should be removed once nrfx_grtc_uninit - * no longer resets the counter - see NRFX-8487. - */ -static inline void nrfx_grtc_uninit_no_counter_reset(void) -{ - uint32_t ch_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; - -#if NRF_GRTC_HAS_RTCOUNTER - uint32_t grtc_all_int_mask = (NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK | - GRTC_NON_SYSCOMPARE_INT_MASK); -#else - uint32_t grtc_all_int_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; -#endif - - nrfy_grtc_int_disable(NRF_GRTC, grtc_all_int_mask); - - for (uint8_t chan = 0; ch_mask; chan++, ch_mask >>= 1) - { - nrfx_grtc_syscounter_cc_disable(chan); - nrfx_grtc_channel_free(chan); - } - nrfy_grtc_int_uninit(NRF_GRTC); -} - static inline void nrf_cleanup_grtc(void) { - nrfx_grtc_uninit_no_counter_reset(); + nrfx_grtc_uninit(); } #endif From 7ac4fe5f290cf3e811fd4297c356f60759d61b76 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 012/149] Revert "[nrf noup] boot: bootutil: Fix b0 checks" This reverts commit e8ddb173eee7dbfd4d2b7b0d16c2882c3e2174c9. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/swap_move.c | 23 +++++++---------------- boot/bootutil/src/swap_offset.c | 22 ---------------------- boot/bootutil/src/swap_scratch.c | 29 ++++++++++------------------- 3 files changed, 17 insertions(+), 57 deletions(-) diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index a183ce8b0..75dadfe91 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -230,12 +230,6 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz) int boot_slots_compatible(struct boot_loader_state *state) { - size_t num_sectors_pri; - size_t num_sectors_sec; - size_t sector_sz_pri = 0; - size_t sector_sz_sec = 0; - size_t i; - #ifdef PM_S1_ADDRESS /* Patch needed for NCS. In this case, image 1 primary points to the other * B1 slot (ie S0 or S1), and image 0 primary points to the app. @@ -246,17 +240,13 @@ boot_slots_compatible(struct boot_loader_state *state) * partition manager is in use, and since we have the same sector size * in all of our flash. */ -#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { - return 1; - } -#endif -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { return 1; - } -#endif -#endif +#else + size_t num_sectors_pri; + size_t num_sectors_sec; + size_t sector_sz_pri = 0; + size_t sector_sz_sec = 0; + size_t i; num_sectors_pri = boot_img_num_sectors(state, BOOT_SLOT_PRIMARY); num_sectors_sec = boot_img_num_sectors(state, BOOT_SLOT_SECONDARY); @@ -317,6 +307,7 @@ boot_slots_compatible(struct boot_loader_state *state) } return 1; +#endif /* PM_S1_ADDRESS */ } #define BOOT_LOG_SWAP_STATE(area, state) \ diff --git a/boot/bootutil/src/swap_offset.c b/boot/bootutil/src/swap_offset.c index 27862ea00..f0b2d0634 100644 --- a/boot/bootutil/src/swap_offset.c +++ b/boot/bootutil/src/swap_offset.c @@ -310,28 +310,6 @@ int boot_slots_compatible(struct boot_loader_state *state) size_t sector_sz_sec = 0; size_t i; -#ifdef PM_S1_ADDRESS - /* Patch needed for NCS. In this case, image 1 primary points to the other - * B1 slot (ie S0 or S1), and image 0 primary points to the app. - * With this configuration, image 0 and image 1 share the secondary slot. - * Hence, the primary slot of image 1 will be *smaller* than image 1's - * secondary slot. This is not allowed in upstream mcuboot, so we need - * this patch to allow it. Also, all of these checks are redundant when - * partition manager is in use, and since we have the same sector size - * in all of our flash. - */ -#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { - return 1; - } -#endif -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { - return 1; - } -#endif -#endif - num_sectors_pri = boot_img_num_sectors(state, BOOT_SLOT_PRIMARY); num_sectors_sec = boot_img_num_sectors(state, BOOT_SLOT_SECONDARY); diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c index 35fc8bf0c..f01f407b2 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -271,16 +271,6 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz) int boot_slots_compatible(struct boot_loader_state *state) { - size_t num_sectors_primary; - size_t num_sectors_secondary; - size_t sz0, sz1; - size_t primary_slot_sz, secondary_slot_sz; -#ifndef MCUBOOT_OVERWRITE_ONLY - size_t scratch_sz; -#endif - size_t i, j; - int8_t smaller; - #ifdef PM_S1_ADDRESS /* Patch needed for NCS. In this case, image 1 primary points to the other * B1 slot (ie S0 or S1), and image 0 primary points to the app. @@ -291,17 +281,17 @@ boot_slots_compatible(struct boot_loader_state *state) * partition manager is in use, and since we have the same sector size * in all of our flash. */ -#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { - return 1; - } -#endif -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { return 1; - } -#endif +#else + size_t num_sectors_primary; + size_t num_sectors_secondary; + size_t sz0, sz1; + size_t primary_slot_sz, secondary_slot_sz; +#ifndef MCUBOOT_OVERWRITE_ONLY + size_t scratch_sz; #endif + size_t i, j; + int8_t smaller; num_sectors_primary = boot_img_num_sectors(state, BOOT_SLOT_PRIMARY); num_sectors_secondary = boot_img_num_sectors(state, BOOT_SLOT_SECONDARY); @@ -390,6 +380,7 @@ boot_slots_compatible(struct boot_loader_state *state) #endif return 1; +#endif /* PM_S1_ADDRESS */ } #define BOOT_LOG_SWAP_STATE(area, state) \ From 97aa207a66b9fba006d2b261bc994be0c5edfbd4 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 013/149] Revert "[nrf noup] loader: Too many params when calling bootutil_img_validate" This reverts commit a9a760f896f2da81df41a118fde244974eb6b54b. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 5ab1a75c7..e3c637455 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -722,8 +722,13 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, BOOT_LOG_DBG("Image validation attempt %d/%d", i, CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT); #endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ +#if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_SERIAL_RECOVERY) + FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, + NULL, 0, NULL, 0); +#else FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, NULL); +#endif if (FIH_EQ(fih_rc, FIH_SUCCESS)) { #if CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 From da4e6e1c6df1891665e74f8a99163f823ac02bf1 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 014/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit a290437b3348209f18fe176d0b6d393062972d8e. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/swap_nsib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/swap_nsib.c b/boot/bootutil/src/swap_nsib.c index f8d6e8a88..079e193d5 100644 --- a/boot/bootutil/src/swap_nsib.c +++ b/boot/bootutil/src/swap_nsib.c @@ -40,7 +40,7 @@ void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs) BOOT_LOG_INF("Starting swap using nsib algorithm."); - sector_sz = boot_img_sector_size(state, BOOT_SLOT_SECONDARY, 0); + 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); From 750c041fa999f14e12bf53e5d0f008a4fd25f7f6 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 015/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit ea6bb5c467625b39fd3ad59775e08fe70889199d. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index e3c637455..e5744477e 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -2900,7 +2900,7 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) if (!image_validated_by_nsib) #endif { - FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SLOT_PRIMARY, NULL, 0); + FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL, 0); /* Check for all possible values is redundant in normal operation it * is meant to prevent FI attack. */ From a9dc12af58ac10b30df0b50f546837d325bcdf87 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 016/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit 2b997f2d434ce5c7e05ce087f896aea25592684a. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 2 +- boot/zephyr/decompression.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index e5744477e..8441f1d1a 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1781,7 +1781,7 @@ boot_copy_region(struct boot_loader_state *state, #endif #ifdef MCUBOOT_DECOMPRESS_IMAGES - hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY); + hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); if (MUST_DECOMPRESS(fap_src, BOOT_CURR_IMG(state), hdr)) { /* Use alternative function for compressed images */ diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c index c8b279a75..ce4fe0b2b 100644 --- a/boot/zephyr/decompression.c +++ b/boot/zephyr/decompression.c @@ -64,24 +64,24 @@ bool boot_is_compressed_header_valid(const struct image_header *hdr, const struc uint32_t protected_tlvs_size; uint32_t decompressed_size; - primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_SLOT_PRIMARY); + primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT); if (primary_fa_id == fap->fa_id) { BOOT_LOG_ERR("Primary slots cannot be compressed, image: %d", BOOT_CURR_IMG(state)); return false; } - if (BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY) == NULL) { + if (BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT) == NULL) { opened_flash_area = true; } - rc = flash_area_open(primary_fa_id, &BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); + rc = flash_area_open(primary_fa_id, &BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); assert(rc == 0); - size_check = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); + size_check = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); if (opened_flash_area) { - (void)flash_area_close(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); + (void)flash_area_close(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); } rc = bootutil_get_img_decomp_size(hdr, fap, &decompressed_size); @@ -1100,7 +1100,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl uint8_t decryption_block_size = 0; #endif - hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY); + hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); #ifdef MCUBOOT_ENC_IMAGES rc = bootutil_get_img_decrypted_comp_size(hdr, fap_src, &comp_size); From b6e04be3638f996b64525c72d9a0f269d65982a6 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 017/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit 98b6e78de31db132366252b89bc6b4001f9474d2. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 8441f1d1a..4b9f5e47d 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1439,7 +1439,7 @@ boot_validated_swap_type(struct boot_loader_state *state, { const struct flash_area *primary_fa; rc = flash_area_open(flash_area_id_from_multi_image_slot( - BOOT_CURR_IMG(state), BOOT_SLOT_PRIMARY), + BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT), &primary_fa); if (rc != 0) { return BOOT_SWAP_TYPE_FAIL; From e3d203b885fd3b44e0d3a97a21cd46d924476a21 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 018/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit 3b4341c427ddd921793b759a3be151bf8300dcc9. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 4b9f5e47d..aad1e84cc 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1411,7 +1411,7 @@ boot_validated_swap_type(struct boot_loader_state *state, #if defined(PM_S1_ADDRESS) || defined(PM_CPUNET_B0N_ADDRESS) const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); - struct image_header *hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY); + struct image_header *hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); uint32_t reset_addr = 0; int rc = 0; /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other From 344ac595ad5a7d9c468f76d0af00049faef0eb55 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 019/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit e72408e93097e42469cdc7a7bc7286b18a9d28f8. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index aad1e84cc..f73877f98 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1410,7 +1410,7 @@ boot_validated_swap_type(struct boot_loader_state *state, #if defined(PM_S1_ADDRESS) || defined(PM_CPUNET_B0N_ADDRESS) const struct flash_area *secondary_fa = - BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); + BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); struct image_header *hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); uint32_t reset_addr = 0; int rc = 0; From 7d9e0be9a9fb0a35673d65af05ae003036653c0f Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 020/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit a72f4f326ad71fdf87d4b8cf8d61eda0ad7b698d. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index f73877f98..e7f1f51cc 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1358,7 +1358,7 @@ static void sec_slot_cleanup_if_unusable(void) const struct flash_area *secondary_fa; int rc; - rc = flash_area_open(flash_area_id_from_multi_image_slot(idx, BOOT_SLOT_SECONDARY), + rc = flash_area_open(flash_area_id_from_multi_image_slot(idx, BOOT_SECONDARY_SLOT), &secondary_fa); if (!rc) { rc = flash_area_erase(secondary_fa, 0, secondary_fa->fa_size); From 959f460928cc16630e66561b0dd1a41e32b7c8cf Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 021/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit 61083522148044647811a53f418aee5b9ed6fb69. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index e7f1f51cc..4b075c00f 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1116,12 +1116,12 @@ boot_validate_slot(struct boot_loader_state *state, int slot, * 0. This part of image is not bootable, as the XIP setup is done by the app in * image 0 slot, and it does not carry the reset vector. */ - if (fap == state->imgs[2][BOOT_SLOT_SECONDARY].area) { + if (fap == state->imgs[2][BOOT_SECONDARY_SLOT].area) { goto out; } #endif - if (fap == BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY)) { - const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY); + if (fap == BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT)) { + const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_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); From 3426fc7930a19eba609d740a581723d8dc6d95b1 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 022/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit 72179c9d2d49766b5e896ebc7ad40f135ab49f7b. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 4b075c00f..0dabde195 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1033,7 +1033,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, */ int version_check; - version_check = boot_version_cmp(&boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, + version_check = boot_version_cmp(&boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, &mcuboot_s0_s1_image_version); /* Only update rc if the currently running version is newer */ @@ -1055,7 +1055,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, */ int version_check; - version_check = boot_version_cmp(&boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, + version_check = boot_version_cmp(&boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, &mcuboot_s0_s1_image_version); /* Only update rc if the currently running version is newer */ From 9e9958a858507facd874563bf5cf5345f519e9f1 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 023/149] Revert "[nrf noup] loader: Use BOOT_SLOT_PRIMARY and BOOT_SLOT_SECONDARY" This reverts commit 98b9e4b76abf89e5feb8df4b08a794d50c0cbaa8. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 0dabde195..e474db65f 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1020,11 +1020,11 @@ 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) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { - rc = pcd_version_cmp_net(fap, boot_img_hdr(state, BOOT_SLOT_SECONDARY)); + rc = pcd_version_cmp_net(fap, boot_img_hdr(state, BOOT_SECONDARY_SLOT)); } else { rc = boot_version_cmp( - &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, - &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); + &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, + &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); #if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 if (rc >= 0 && BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { @@ -1045,8 +1045,8 @@ boot_validate_slot(struct boot_loader_state *state, int slot, } #else rc = boot_version_cmp( - &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, - &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); + &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, + &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); #if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 if (rc >= 0 && BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { @@ -1065,7 +1065,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, } #endif #endif - if (rc < 0 && boot_check_header_erased(state, BOOT_SLOT_PRIMARY)) { + if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) { BOOT_LOG_ERR("insufficient version in secondary slot"); boot_scramble_slot(fap, slot); /* Image in the secondary slot does not satisfy version requirement. From b7ee0e03460213c9cae5dc2c5a6dbba13ba2021e Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 024/149] Revert "[nrf noup] bootutil: Remove bootutil_find_key from code" This reverts commit 0d5b49de2308449a4a9ba16f84887b7342b8701a. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/image_validate.c | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 16ff9c09c..efa1c1363 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -118,7 +118,76 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); # define KEY_BUF_SIZE (SIG_BUF_SIZE + 24) #endif /* !MCUBOOT_HW_KEY */ +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +#if !defined(MCUBOOT_HW_KEY) +static int +bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) +{ + bootutil_sha_context sha_ctx; + int i; + const struct bootutil_key *key; + uint8_t hash[IMAGE_HASH_SIZE]; + + BOOT_LOG_DBG("bootutil_find_key"); + + if (keyhash_len > IMAGE_HASH_SIZE) { + return -1; + } + + for (i = 0; i < bootutil_key_cnt; i++) { + key = &bootutil_keys[i]; + bootutil_sha_init(&sha_ctx); + bootutil_sha_update(&sha_ctx, key->key, *key->len); + bootutil_sha_finish(&sha_ctx, hash); + bootutil_sha_drop(&sha_ctx); + if (!memcmp(hash, keyhash, keyhash_len)) { + return i; + } + } + return -1; +} +#else /* !MCUBOOT_HW_KEY */ +extern unsigned int pub_key_len; +static int +bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) +{ + bootutil_sha_context sha_ctx; + uint8_t hash[IMAGE_HASH_SIZE]; + uint8_t key_hash[IMAGE_HASH_SIZE]; + size_t key_hash_size = sizeof(key_hash); + int rc; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + BOOT_LOG_DBG("bootutil_find_key: image_index %d", image_index); + + bootutil_sha_init(&sha_ctx); + bootutil_sha_update(&sha_ctx, key, key_len); + bootutil_sha_finish(&sha_ctx, hash); + bootutil_sha_drop(&sha_ctx); + + rc = boot_retrieve_public_key_hash(image_index, key_hash, &key_hash_size); + if (rc) { + return -1; + } + + /* Adding hardening to avoid this potential attack: + * - Image is signed with an arbitrary key and the corresponding public + * key is added as a TLV field. + * - During public key validation (comparing against key-hash read from + * HW) a fault is injected to accept the public key as valid one. + */ + FIH_CALL(boot_fih_memequal, fih_rc, hash, key_hash, key_hash_size); + if (FIH_EQ(fih_rc, FIH_SUCCESS)) { + bootutil_keys[0].key = key; + pub_key_len = key_len; + return 0; + } + + return -1; +} +#endif /* !MCUBOOT_HW_KEY */ #endif /* !MCUBOOT_BUILTIN_KEY */ +#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #endif /* EXPECTED_SIG_TLV */ #if defined(MCUBOOT_SIGN_PURE) From 7d50b7cc8fcde5824d43aac00883a8100d8dd595 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 025/149] Revert "[nrf noup] bootutil: Locking KMU keys" This reverts commit cb297debeee5a5878c3e3be1b2466ba63772253b. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/ed25519_psa.c | 27 --------------------------- boot/zephyr/include/nrf_cleanup.h | 11 ----------- boot/zephyr/main.c | 7 ------- 3 files changed, 45 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 3df1acbdd..8460da7c8 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -177,31 +177,4 @@ int exec_revoke(void) return ret; } #endif /* CONFIG_BOOT_KMU_KEYS_REVOCATION */ - -void nrf_crypto_keys_housekeeping(void) -{ - psa_status_t status; - - /* We will continue through all keys, even if we have error while - * processing any of it. Only doing BOOT_LOG_DBG, as we do not - * really want to inform on failures to lock. - */ - for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; ++i) { - psa_key_attributes_t attr; - - status = psa_get_key_attributes(key_ids[i], &attr); - BOOT_LOG_DBG("KMU key 0x%x(%d) attr query status == %d", - key_ids[i], i, status); - - if (status == PSA_SUCCESS) { - status = cracen_kmu_block(&attr); - BOOT_LOG_DBG("KMU key lock status == %d", status); - } - - status = psa_purge_key(key_ids[i]); - BOOT_LOG_DBG("KMU key 0x%x(%d) purge status == %d", - key_ids[i], i, status); - } -} - #endif diff --git a/boot/zephyr/include/nrf_cleanup.h b/boot/zephyr/include/nrf_cleanup.h index 8cd8fe377..9e87e13f5 100644 --- a/boot/zephyr/include/nrf_cleanup.h +++ b/boot/zephyr/include/nrf_cleanup.h @@ -21,15 +21,4 @@ void nrf_cleanup_peripheral(void); */ void nrf_cleanup_ns_ram(void); -/** - * Crypto key storage housekeeping. Intended to clean up key objects from - * crypto backend and apply key policies that should take effect after - * MCUboot no longer needs access to keys. - */ -#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) -extern void nrf_crypto_keys_housekeeping(void); -#else -#define nrf_crypto_keys_housekeeping() do {} while (0) -#endif - #endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 14410c66a..cad0ab75f 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -842,13 +842,6 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND); - /* From this point MCUboot does not need access to crypto keys. - * Clean up backend key objects and apply key access policies that - * will take effect from now through entire boot session and application - * run. - */ - nrf_crypto_keys_housekeeping(); - #if USE_PARTITION_MANAGER && CONFIG_FPROTECT #ifdef PM_S1_ADDRESS From e3c3f99df1375d98e5fbe7bd0bd323711fbd5c60 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 026/149] Revert "[nrf noup] bootloader: Fix logging in bootloader requests module" This reverts commit 4e25b7a914810c5583eab0327b842227bfc52940. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/zephyr/src/boot_request_retention.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/zephyr/src/boot_request_retention.c b/boot/bootutil/zephyr/src/boot_request_retention.c index 234dfb5cf..023f5af5e 100644 --- a/boot/bootutil/zephyr/src/boot_request_retention.c +++ b/boot/bootutil/zephyr/src/boot_request_retention.c @@ -14,7 +14,7 @@ /** Additional memory used by the retention subsystem (2B - prefix, 4B - CRC).*/ #define BOOT_REQUEST_ENTRY_METADATA_SIZE (2 + 4) -BOOT_LOG_MODULE_REGISTER(bootloader_request); +MCUBOOT_LOG_MODULE_REGISTER(bootloader_request); static const struct device *bootloader_request_dev = DEVICE_DT_GET(DT_CHOSEN(nrf_bootloader_request)); From 5cfd1c754052c13f8f5a366c54d6807c538ca06b Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 027/149] Revert "[nrf noup] boot: Fix test failing with bootloader requests" This reverts commit 3fc7ca5e12be700d42d552a6ee55078686dc4879. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/bootutil_public.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index 0f8857e4d..ea027f8bf 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -524,12 +524,10 @@ send_boot_request(uint8_t magic, uint8_t image_ok, bool confirm, int image_id, } else { rc = 0; } - } else { #ifdef CONFIG_NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE + } else { BOOT_LOG_DBG("Set image preference: %d, %d", image_id, slot_id); rc = boot_request_set_preferred_slot(image_id, slot_id); -#else - rc = 0; #endif /* CONFIG_NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE */ } if (rc != 0) { From fa735ff9138467a49697ddb57c538cb8817a857d Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 028/149] Revert "[nrf noup] Support for ed25519 signature verification using ITS" This reverts commit 335b6df85c2da36dd985b342456a7add5a35b564. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/ed25519_psa.c | 38 ++++++++++-------------------- boot/bootutil/src/image_ed25519.c | 6 ++--- boot/bootutil/src/image_validate.c | 6 ++--- 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 8460da7c8..6393d996e 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -26,35 +26,22 @@ BOOT_LOG_MODULE_REGISTER(ed25519_psa); #if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) /* List of KMU stored key ids available for MCUboot */ #define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id) -static psa_key_id_t key_ids[] = { +static psa_key_id_t kmu_key_ids[3] = { MAKE_PSA_KMU_KEY_ID(226), MAKE_PSA_KMU_KEY_ID(228), MAKE_PSA_KMU_KEY_ID(230) }; -#define KEY_SLOTS_COUNT CONFIG_BOOT_SIGNATURE_KMU_SLOTS - #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) #include static psa_key_id_t *validated_with = NULL; #endif -BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(key_ids), +BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(kmu_key_ids), "Invalid number of KMU slots, up to 3 are supported on nRF54L15"); #endif -#if defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) -static const psa_key_id_t key_ids[] = { - 0x40022100, - 0x40022101, - 0x40022102, - 0x40022103 -}; - -#define KEY_SLOTS_COUNT ARRAY_SIZE(key_ids) -#endif - -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], const uint8_t public_key[EDDSA_KEY_LENGTH]) @@ -115,6 +102,7 @@ int ED25519_verify(const uint8_t *message, size_t message_len, ARG_UNUSED(public_key); /* Set to any error */ psa_status_t status = PSA_ERROR_BAD_STATE; + int ret = 0; /* Fail by default */ /* Initialize PSA Crypto */ status = psa_crypto_init(); @@ -125,24 +113,24 @@ int ED25519_verify(const uint8_t *message, size_t message_len, status = PSA_ERROR_BAD_STATE; - for (int i = 0; i < KEY_SLOTS_COUNT; ++i) { - psa_key_id_t kid = key_ids[i]; + for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; ++i) { + psa_key_id_t kid = kmu_key_ids[i]; status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, message_len, signature, EDDSA_SIGNAGURE_LENGTH); if (status == PSA_SUCCESS) { + ret = 1; #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) - validated_with = key_ids + i; + validated_with = kmu_key_ids + i; #endif - return 1; + break; } + BOOT_LOG_ERR("ED25519 signature verification failed %d", status); } - BOOT_LOG_ERR("ED25519 signature verification failed %d", status); - - return 0; + return ret; } #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) int exec_revoke(void) @@ -161,12 +149,12 @@ int exec_revoke(void) goto out; } for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; i++) { - if ((key_ids + i) == validated_with) { + if ((kmu_key_ids + i) == validated_with) { break; } BOOT_LOG_DBG("Invalidating key ID %d", i); - status = psa_destroy_key(key_ids[i]); + status = psa_destroy_key(kmu_key_ids[i]); if (status == PSA_SUCCESS) { BOOT_LOG_DBG("Success on key ID %d", i); } else { diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 177550749..1a02811e3 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -36,7 +36,6 @@ extern int ED25519_verify(const uint8_t *message, size_t message_len, #if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #if !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) -#if !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) /* * Parse the public key used for signing. */ @@ -79,7 +78,6 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) } #endif /* !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) */ #endif -#endif /* Signature verification base function. * The function takes buffer of specified length and tries to verify @@ -95,7 +93,7 @@ bootutil_verify(uint8_t *buf, uint32_t blen, int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); uint8_t *pubkey = NULL; -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) uint8_t *end; #endif @@ -108,7 +106,7 @@ bootutil_verify(uint8_t *buf, uint32_t blen, goto out; } -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) pubkey = (uint8_t *)bootutil_keys[key_id].key; end = pubkey + *bootutil_keys[key_id].len; diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index efa1c1363..fd1a6a925 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -541,13 +541,13 @@ bootutil_img_validate(struct boot_loader_state *state, case EXPECTED_SIG_TLV: { BOOT_LOG_DBG("bootutil_img_validate: EXPECTED_SIG_TLV == %d", EXPECTED_SIG_TLV); -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } -#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) */ +#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; goto out; @@ -864,7 +864,7 @@ bootutil_img_validate(struct boot_loader_state *state, if (type == IMAGE_TLV_DECOMP_SIGNATURE) { /* Ignore this signature if it is out of bounds. */ -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; From 6afe632a0f91a999c25d0e22e096d215d003a124 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 029/149] Revert "[nrf noup] boot: Use NCS_ prefix for sdk-nrf specific Kconfigs" This reverts commit 7047d540c2d890d62513763dd963705bbea3e4b6. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 6 +++--- boot/zephyr/Kconfig | 4 ++-- boot/zephyr/include/mcuboot_config/mcuboot_config.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index 7fc5474e2..4fc7b7516 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -475,7 +475,7 @@ static int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, } #endif /* !MCUBOOT_BUILTIN_KEY */ -#if !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) +#if !defined(CONFIG_NRF_BOOT_SIGNATURE_USING_ITS) /* Verify the signature against the provided hash. The signature gets parsed from * the encoding first, then PSA Crypto has a dedicated API for ECDSA verification */ @@ -494,7 +494,7 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, return (int) psa_verify_hash(ctx->key_id, PSA_ALG_ECDSA(ctx->required_algorithm), hash, hlen, reformatted_signature, 2*ctx->curve_byte_count); } -#else /* !CONFIG_NCS_BOOT_SIGNATURE_USING_ITS */ +#else /* !CONFIG_NRF_BOOT_SIGNATURE_USING_ITS */ static const psa_key_id_t builtin_key_ids[] = { 0x40022100, @@ -541,7 +541,7 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, return status == PSA_SUCCESS ? 0 : 2; } -#endif /* !CONFIG_NCS_BOOT_SIGNATURE_USING_ITS */ +#endif /* !CONFIG_NRF_BOOT_SIGNATURE_USING_ITS */ #elif defined(MCUBOOT_USE_MBED_TLS) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 4815598ac..47c72c8ec 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -435,14 +435,14 @@ config BOOT_KMU_KEYS_REVOCATION help Enabling KMU key revocation backend. -config NCS_BOOT_SIGNATURE_USING_ITS +config NRF_BOOT_SIGNATURE_USING_ITS bool "Use ITS stored keys for signature verification" depends on NRF_SECURITY help MCUboot will use keys provisioned to the internal trusted storage for signature verification instead of compiling in key data from a file. -if !BOOT_SIGNATURE_USING_KMU && !NCS_BOOT_SIGNATURE_USING_ITS +if !BOOT_SIGNATURE_USING_KMU && !NRF_BOOT_SIGNATURE_USING_ITS config BOOT_SIGNATURE_KEY_FILE string "PEM key file" diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 2d759217b..9389c3a9f 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -68,7 +68,7 @@ #define MCUBOOT_HW_KEY #endif -#ifdef CONFIG_NCS_BOOT_SIGNATURE_USING_ITS +#ifdef CONFIG_NRF_BOOT_SIGNATURE_USING_ITS #define MCUBOOT_BUILTIN_KEY #endif From eae1d3fdb4a52cc5b9fbd1eafd9c725f3c4d11a5 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 030/149] Revert "[nrf noup] Added BOOT_SIGNATURE_USING_ITS for ecdsa configuration" This reverts commit e2bfd22d374aa91decc2d4d44b9dfde9bbb94213. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 50 ------------------- boot/bootutil/src/image_validate.c | 3 +- boot/zephyr/Kconfig | 9 +--- .../include/mcuboot_config/mcuboot_config.h | 4 -- 4 files changed, 2 insertions(+), 64 deletions(-) diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index 4fc7b7516..cbbff1783 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -475,7 +475,6 @@ static int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, } #endif /* !MCUBOOT_BUILTIN_KEY */ -#if !defined(CONFIG_NRF_BOOT_SIGNATURE_USING_ITS) /* Verify the signature against the provided hash. The signature gets parsed from * the encoding first, then PSA Crypto has a dedicated API for ECDSA verification */ @@ -494,55 +493,6 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, return (int) psa_verify_hash(ctx->key_id, PSA_ALG_ECDSA(ctx->required_algorithm), hash, hlen, reformatted_signature, 2*ctx->curve_byte_count); } -#else /* !CONFIG_NRF_BOOT_SIGNATURE_USING_ITS */ - -static const psa_key_id_t builtin_key_ids[] = { - 0x40022100, - 0x40022101, - 0x40022102, - 0x40022103 -}; - -#define BOOT_SIGNATURE_BUILTIN_KEY_SLOTS ARRAY_SIZE(builtin_key_ids) - -static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, - uint8_t *pk, size_t pk_len, - uint8_t *hash, size_t hlen, - uint8_t *sig, size_t slen) -{ - (void)pk; - (void)pk_len; - (void)slen; - psa_status_t status = PSA_ERROR_BAD_STATE; - - /* Initialize PSA Crypto */ - status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - BOOT_LOG_ERR("PSA crypto init failed %d", status); - return 1; - } - - uint8_t reformatted_signature[96] = {0}; /* Enough for P-384 signature sizes */ - parse_signature_from_rfc5480_encoding(sig, ctx->curve_byte_count, reformatted_signature); - - status = PSA_ERROR_BAD_STATE; - - for (int i = 0; i < BOOT_SIGNATURE_BUILTIN_KEY_SLOTS; ++i) { - psa_key_id_t kid = builtin_key_ids[i]; - - status = psa_verify_hash(kid, PSA_ALG_ECDSA(ctx->required_algorithm), - hash, hlen, reformatted_signature, 2*ctx->curve_byte_count); - if (status == PSA_SUCCESS) { - break; - } - BOOT_LOG_ERR("ECDSA signature verification failed %d", status); - } - - return status == PSA_SUCCESS ? 0 : 2; -} - -#endif /* !CONFIG_NRF_BOOT_SIGNATURE_USING_ITS */ - #elif defined(MCUBOOT_USE_MBED_TLS) typedef mbedtls_ecdsa_context bootutil_ecdsa_context; diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index fd1a6a925..3f235e048 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -280,8 +280,7 @@ bootutil_img_validate(struct boot_loader_state *state, ) { #if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) \ - || defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) || defined(MCUBOOT_DECOMPRESS_IMAGES) \ - || defined(MCUBOOT_BUILTIN_KEY) + || defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) || defined(MCUBOOT_DECOMPRESS_IMAGES) int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state)); #endif uint32_t off; diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 47c72c8ec..b7594f949 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -435,14 +435,7 @@ config BOOT_KMU_KEYS_REVOCATION help Enabling KMU key revocation backend. -config NRF_BOOT_SIGNATURE_USING_ITS - bool "Use ITS stored keys for signature verification" - depends on NRF_SECURITY - help - MCUboot will use keys provisioned to the internal trusted storage for signature - verification instead of compiling in key data from a file. - -if !BOOT_SIGNATURE_USING_KMU && !NRF_BOOT_SIGNATURE_USING_ITS +if !BOOT_SIGNATURE_USING_KMU config BOOT_SIGNATURE_KEY_FILE string "PEM key file" diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 9389c3a9f..5062d02fd 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -68,10 +68,6 @@ #define MCUBOOT_HW_KEY #endif -#ifdef CONFIG_NRF_BOOT_SIGNATURE_USING_ITS -#define MCUBOOT_BUILTIN_KEY -#endif - #ifdef CONFIG_BOOT_VALIDATE_SLOT0 #define MCUBOOT_VALIDATE_PRIMARY_SLOT #endif From 66a342cf28a22953ecab8667f11418bb896354ac Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 031/149] Revert "[nrf noup] bootutil: key revocation" This reverts commit 08e2009fbcdbcb8292cdb8bd62332f656443d170. Signed-off-by: Tomasz Chyrowicz --- .../include/bootutil/key_revocation.h | 30 -------------- boot/bootutil/src/ed25519_psa.c | 41 ------------------- boot/bootutil/src/key_revocation.c | 24 ----------- boot/bootutil/src/loader.c | 16 -------- boot/zephyr/CMakeLists.txt | 6 --- boot/zephyr/Kconfig | 12 ------ 6 files changed, 129 deletions(-) delete mode 100644 boot/bootutil/include/bootutil/key_revocation.h delete mode 100644 boot/bootutil/src/key_revocation.c diff --git a/boot/bootutil/include/bootutil/key_revocation.h b/boot/bootutil/include/bootutil/key_revocation.h deleted file mode 100644 index d184c9579..000000000 --- a/boot/bootutil/include/bootutil/key_revocation.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2025 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#ifndef H_KEY_REVOCATION_ -#define H_KEY_REVOCATION_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define BOOT_KEY_REVOKE_OK 0 -#define BOOT_KEY_REVOKE_NOT_READY 1 -#define BOOT_KEY_REVOKE_INVALID 2 -#define BOOT_KEY_REVOKE_FAILED 2 - - -void allow_revoke(void); - -int revoke(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 6393d996e..7665e4067 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -32,11 +32,6 @@ static psa_key_id_t kmu_key_ids[3] = { MAKE_PSA_KMU_KEY_ID(230) }; -#if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) -#include -static psa_key_id_t *validated_with = NULL; -#endif - BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(kmu_key_ids), "Invalid number of KMU slots, up to 3 are supported on nRF54L15"); #endif @@ -121,9 +116,6 @@ int ED25519_verify(const uint8_t *message, size_t message_len, EDDSA_SIGNAGURE_LENGTH); if (status == PSA_SUCCESS) { ret = 1; -#if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) - validated_with = kmu_key_ids + i; -#endif break; } @@ -132,37 +124,4 @@ int ED25519_verify(const uint8_t *message, size_t message_len, return ret; } -#if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) -int exec_revoke(void) -{ - int ret = BOOT_KEY_REVOKE_OK; - psa_status_t status = psa_crypto_init(); - - if (!validated_with) { - ret = BOOT_KEY_REVOKE_INVALID; - goto out; - } - - if (status != PSA_SUCCESS) { - BOOT_LOG_ERR("PSA crypto init failed with error %d", status); - ret = BOOT_KEY_REVOKE_FAILED; - goto out; - } - for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; i++) { - if ((kmu_key_ids + i) == validated_with) { - break; - } - BOOT_LOG_DBG("Invalidating key ID %d", i); - - status = psa_destroy_key(kmu_key_ids[i]); - if (status == PSA_SUCCESS) { - BOOT_LOG_DBG("Success on key ID %d", i); - } else { - BOOT_LOG_ERR("Key invalidation failed with: %d", status); - } - } -out: - return ret; -} -#endif /* CONFIG_BOOT_KMU_KEYS_REVOCATION */ #endif diff --git a/boot/bootutil/src/key_revocation.c b/boot/bootutil/src/key_revocation.c deleted file mode 100644 index 0768a3188..000000000 --- a/boot/bootutil/src/key_revocation.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2025 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#include - -extern int exec_revoke(void); - -static uint8_t ready_to_revoke; - -void allow_revoke(void) -{ - ready_to_revoke = 1; -} - -int revoke(void) -{ - if (ready_to_revoke) { - return exec_revoke(); - } - return BOOT_KEY_REVOKE_NOT_READY; -} diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index e474db65f..31aa7d87e 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -80,10 +80,6 @@ int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); #include "mcuboot_config/mcuboot_config.h" -#if defined(CONFIG_BOOT_KEYS_REVOCATION) -#include "bootutil/key_revocation.h" -#endif - BOOT_LOG_MODULE_DECLARE(mcuboot); static struct boot_loader_state boot_data; @@ -2843,11 +2839,6 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } } -#if defined(CONFIG_BOOT_KEYS_REVOCATION) - if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) { - allow_revoke(); - } -#endif /* Iterate over all the images. At this point all required update operations * have finished. By the end of the loop each image in the primary slot will * have been re-validated. @@ -2956,13 +2947,6 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) fill_rsp(state, rsp); fih_rc = FIH_SUCCESS; -#if defined(CONFIG_BOOT_KEYS_REVOCATION) - rc = revoke(); - if (rc != BOOT_KEY_REVOKE_OK && - rc != BOOT_KEY_REVOKE_NOT_READY) { - FIH_SET(fih_rc, FIH_FAILURE); - } -#endif /* CONFIG_BOOT_KEYS_REVOCATION */ out: /* * Since the boot_status struct stores plaintext encryption keys, reset diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 7d4648db7..43b325570 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -101,12 +101,6 @@ if(DEFINED CONFIG_BOOT_SHARE_BACKEND_RETENTION) ) endif() -if(DEFINED CONFIG_BOOT_KEYS_REVOCATION) - zephyr_library_sources( - ${BOOT_DIR}/bootutil/src/key_revocation.c -) -endif() - # Generic bootutil sources and includes. zephyr_library_include_directories(${BOOT_DIR}/bootutil/include) zephyr_library_sources( diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index b7594f949..e6b9f1927 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -423,18 +423,6 @@ config BOOT_SIGNATURE_KMU_SLOTS endif -config BOOT_KEYS_REVOCATION - bool "Auto revoke previous gen key" - help - Automatically revoke previous generation key upon new valid key usage. - -config BOOT_KMU_KEYS_REVOCATION - bool - depends on BOOT_KEYS_REVOCATION - default y if BOOT_SIGNATURE_USING_KMU - help - Enabling KMU key revocation backend. - if !BOOT_SIGNATURE_USING_KMU config BOOT_SIGNATURE_KEY_FILE From f047aad800a8de3e3db859ced84ce48b58d8bd76 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 032/149] Revert "[nrf noup] boot: bootutil: Allow configuring number of KMU keys" This reverts commit 37df88a122d6c12eaae322ba4ec9efca067741bf. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/ed25519_psa.c | 7 ++----- boot/zephyr/Kconfig | 12 ------------ 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 7665e4067..cd016158b 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -12,7 +12,6 @@ #include #include -#include #if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #include #endif @@ -31,9 +30,7 @@ static psa_key_id_t kmu_key_ids[3] = { MAKE_PSA_KMU_KEY_ID(228), MAKE_PSA_KMU_KEY_ID(230) }; - -BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(kmu_key_ids), - "Invalid number of KMU slots, up to 3 are supported on nRF54L15"); +#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0])) #endif #if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) @@ -108,7 +105,7 @@ int ED25519_verify(const uint8_t *message, size_t message_len, status = PSA_ERROR_BAD_STATE; - for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; ++i) { + for (int i = 0; i < KMU_KEY_COUNT; ++i) { psa_key_id_t kid = kmu_key_ids[i]; status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index e6b9f1927..3ed8dd2c6 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -411,18 +411,6 @@ config BOOT_SIGNATURE_USING_KMU MCUboot will use keys provisioned to the device key management unit for signature verification instead of compiling in key data from a file. -if BOOT_SIGNATURE_USING_KMU - -config BOOT_SIGNATURE_KMU_SLOTS - int "KMU key slots" - range 1 3 - default 1 - help - Selects the number of KMU key slots (also known as generations) to use when verifying - an image. - -endif - if !BOOT_SIGNATURE_USING_KMU config BOOT_SIGNATURE_KEY_FILE From aefceaf3b3d7366110f5cc920c947267325ba38f Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 033/149] Revert "[nrf noup] bootutil: Add support for KMU stored ED25519 signature key" This reverts commit d0cd58f1d7fceb6bbb7de0add810b652effb4b3b. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/ed25519_psa.c | 51 ------------------- boot/bootutil/src/image_ed25519.c | 9 +--- boot/bootutil/src/image_validate.c | 80 +----------------------------- boot/zephyr/CMakeLists.txt | 2 +- boot/zephyr/Kconfig | 26 ---------- 5 files changed, 4 insertions(+), 164 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index cd016158b..5b8a4ed7c 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -12,9 +12,6 @@ #include #include -#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) -#include -#endif BOOT_LOG_MODULE_REGISTER(ed25519_psa); @@ -22,18 +19,6 @@ BOOT_LOG_MODULE_REGISTER(ed25519_psa); #define EDDSA_KEY_LENGTH 32 #define EDDSA_SIGNAGURE_LENGTH 64 -#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) -/* List of KMU stored key ids available for MCUboot */ -#define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id) -static psa_key_id_t kmu_key_ids[3] = { - MAKE_PSA_KMU_KEY_ID(226), - MAKE_PSA_KMU_KEY_ID(228), - MAKE_PSA_KMU_KEY_ID(230) -}; -#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0])) -#endif - -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], const uint8_t public_key[EDDSA_KEY_LENGTH]) @@ -86,39 +71,3 @@ int ED25519_verify(const uint8_t *message, size_t message_len, return ret; } -#else -int ED25519_verify(const uint8_t *message, size_t message_len, - const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], - const uint8_t public_key[EDDSA_KEY_LENGTH]) -{ - ARG_UNUSED(public_key); - /* Set to any error */ - psa_status_t status = PSA_ERROR_BAD_STATE; - int ret = 0; /* Fail by default */ - - /* Initialize PSA Crypto */ - status = psa_crypto_init(); - if (status != PSA_SUCCESS) { - BOOT_LOG_ERR("PSA crypto init failed %d", status); - return 0; - } - - status = PSA_ERROR_BAD_STATE; - - for (int i = 0; i < KMU_KEY_COUNT; ++i) { - psa_key_id_t kid = kmu_key_ids[i]; - - status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, - message_len, signature, - EDDSA_SIGNAGURE_LENGTH); - if (status == PSA_SUCCESS) { - ret = 1; - break; - } - - BOOT_LOG_ERR("ED25519 signature verification failed %d", status); - } - - return ret; -} -#endif diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 1a02811e3..4d83bb3d7 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -34,7 +34,6 @@ extern int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNATURE_LENGTH], const uint8_t public_key[NUM_ED25519_BYTES]); -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #if !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) /* * Parse the public key used for signing. @@ -77,7 +76,6 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) return 0; } #endif /* !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) */ -#endif /* Signature verification base function. * The function takes buffer of specified length and tries to verify @@ -92,10 +90,8 @@ bootutil_verify(uint8_t *buf, uint32_t blen, { int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); - uint8_t *pubkey = NULL; -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) + uint8_t *pubkey; uint8_t *end; -#endif BOOT_LOG_DBG("bootutil_verify: ED25519 key_id %d", (int)key_id); @@ -106,7 +102,6 @@ bootutil_verify(uint8_t *buf, uint32_t blen, goto out; } -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) pubkey = (uint8_t *)bootutil_keys[key_id].key; end = pubkey + *bootutil_keys[key_id].len; @@ -130,8 +125,6 @@ bootutil_verify(uint8_t *buf, uint32_t blen, } pubkey = end - NUM_ED25519_BYTES; -#endif - #endif rc = ED25519_verify(buf, blen, sig, pubkey); diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 3f235e048..5d2efc98a 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -117,77 +117,7 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); # define EXPECTED_KEY_TLV IMAGE_TLV_PUBKEY # define KEY_BUF_SIZE (SIG_BUF_SIZE + 24) #endif /* !MCUBOOT_HW_KEY */ - -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) -#if !defined(MCUBOOT_HW_KEY) -static int -bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) -{ - bootutil_sha_context sha_ctx; - int i; - const struct bootutil_key *key; - uint8_t hash[IMAGE_HASH_SIZE]; - - BOOT_LOG_DBG("bootutil_find_key"); - - if (keyhash_len > IMAGE_HASH_SIZE) { - return -1; - } - - for (i = 0; i < bootutil_key_cnt; i++) { - key = &bootutil_keys[i]; - bootutil_sha_init(&sha_ctx); - bootutil_sha_update(&sha_ctx, key->key, *key->len); - bootutil_sha_finish(&sha_ctx, hash); - bootutil_sha_drop(&sha_ctx); - if (!memcmp(hash, keyhash, keyhash_len)) { - return i; - } - } - return -1; -} -#else /* !MCUBOOT_HW_KEY */ -extern unsigned int pub_key_len; -static int -bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) -{ - bootutil_sha_context sha_ctx; - uint8_t hash[IMAGE_HASH_SIZE]; - uint8_t key_hash[IMAGE_HASH_SIZE]; - size_t key_hash_size = sizeof(key_hash); - int rc; - FIH_DECLARE(fih_rc, FIH_FAILURE); - - BOOT_LOG_DBG("bootutil_find_key: image_index %d", image_index); - - bootutil_sha_init(&sha_ctx); - bootutil_sha_update(&sha_ctx, key, key_len); - bootutil_sha_finish(&sha_ctx, hash); - bootutil_sha_drop(&sha_ctx); - - rc = boot_retrieve_public_key_hash(image_index, key_hash, &key_hash_size); - if (rc) { - return -1; - } - - /* Adding hardening to avoid this potential attack: - * - Image is signed with an arbitrary key and the corresponding public - * key is added as a TLV field. - * - During public key validation (comparing against key-hash read from - * HW) a fault is injected to accept the public key as valid one. - */ - FIH_CALL(boot_fih_memequal, fih_rc, hash, key_hash, key_hash_size); - if (FIH_EQ(fih_rc, FIH_SUCCESS)) { - bootutil_keys[0].key = key; - pub_key_len = key_len; - return 0; - } - - return -1; -} -#endif /* !MCUBOOT_HW_KEY */ #endif /* !MCUBOOT_BUILTIN_KEY */ -#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #endif /* EXPECTED_SIG_TLV */ #if defined(MCUBOOT_SIGN_PURE) @@ -503,7 +433,6 @@ bootutil_img_validate(struct boot_loader_state *state, break; } #endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */ -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #ifdef EXPECTED_KEY_TLV case EXPECTED_KEY_TLV: { @@ -535,18 +464,15 @@ bootutil_img_validate(struct boot_loader_state *state, break; } #endif /* EXPECTED_KEY_TLV */ -#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #ifdef EXPECTED_SIG_TLV case EXPECTED_SIG_TLV: { BOOT_LOG_DBG("bootutil_img_validate: EXPECTED_SIG_TLV == %d", EXPECTED_SIG_TLV); -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } -#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; goto out; @@ -794,7 +720,7 @@ bootutil_img_validate(struct boot_loader_state *state, } #ifdef EXPECTED_SIG_TLV -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && defined(EXPECTED_KEY_TLV) +#ifdef EXPECTED_KEY_TLV rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false); if (rc) { goto out; @@ -840,7 +766,7 @@ bootutil_img_validate(struct boot_loader_state *state, */ } } -#endif /* !CONFIG_BOOT_SIGNATURE_USING_KMU && EXPECTED_KEY_TLV */ +#endif /* EXPECTED_KEY_TLV */ rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true); if (rc) { @@ -863,12 +789,10 @@ bootutil_img_validate(struct boot_loader_state *state, if (type == IMAGE_TLV_DECOMP_SIGNATURE) { /* Ignore this signature if it is out of bounds. */ -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } -#endif if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 43b325570..a1e9fa2de 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -361,7 +361,7 @@ if(CONFIG_MCUBOOT_SERIAL) endif() endif() -if(NOT CONFIG_BOOT_SIGNATURE_USING_KMU AND NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") +if(NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") # CONF_FILE points to the KConfig configuration files of the bootloader. foreach (filepath ${CONF_FILE}) file(READ ${filepath} temp_text) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 3ed8dd2c6..e11e7b320 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -397,22 +397,6 @@ config BOOT_BYPASS_KEY_MATCH Enabling this option turns off key matching, slightly reducing MCUboot code and boot time. -config BOOT_SIGNATURE_USING_KMU - bool "Use KMU stored keys for signature verification" - depends on NRF_SECURITY - depends on CRACEN_LIB_KMU - select PSA_WANT_ALG_GCM - select PSA_WANT_KEY_TYPE_AES - select PSA_WANT_AES_KEY_SIZE_256 - select PSA_WANT_ALG_SP800_108_COUNTER_CMAC - select PSA_WANT_ALG_CMAC - select PSA_WANT_ALG_ECB_NO_PADDING - help - MCUboot will use keys provisioned to the device key management unit for signature - verification instead of compiling in key data from a file. - -if !BOOT_SIGNATURE_USING_KMU - config BOOT_SIGNATURE_KEY_FILE string "PEM key file" default "root-ec-p256.pem" if BOOT_SIGNATURE_TYPE_ECDSA_P256 @@ -430,8 +414,6 @@ config BOOT_SIGNATURE_KEY_FILE with the public key information will be written in a format expected by MCUboot. -endif - config MCUBOOT_CLEANUP_ARM_CORE bool "Perform core cleanup before chain-load the application" depends on CPU_CORTEX_M || ARMV7_R @@ -468,14 +450,6 @@ config MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP Verification option that keeps execution in infinite loop after RAM cleanup has been performed. -# Disable MBEDTLS from being selected if NRF_SECURITY is enabled, and use default NRF_SECURITY -# configuration file for MBEDTLS -config MBEDTLS - depends on !NRF_SECURITY - -config NRF_SECURITY - select MBEDTLS_PROMPTLESS - config MBEDTLS_CFG_FILE # It might be awkward to define an Mbed TLS header file when TinyCrypt # is used, but the fact is that Mbed TLS' ASN1 parse module is used From 5c7e864ddd5a52cf0fa7759f7aab530e16304776 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 034/149] Revert "[nrf noup] boot: zephyr: Add experimental selection to compression" This reverts commit 4d4123bb5a508c8bfbb39301cab0c53e6ecfb84c. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index e11e7b320..f6b1d33d3 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1206,10 +1206,9 @@ config BOOT_DECOMPRESSION_SUPPORT if BOOT_DECOMPRESSION_SUPPORT menuconfig BOOT_DECOMPRESSION - bool "Decompression [EXPERIMENTAL]" + bool "Decompression" select NRF_COMPRESS_CLEANUP select PM_USE_CONFIG_SRAM_SIZE if SOC_NRF54L15_CPUAPP - select EXPERIMENTAL help If enabled, will include support for compressed images being loaded to the secondary slot which then get decompressed into the primary slot. This mode allows the secondary slot to From c629f4582638d00b406a8f9de6800f027a4b35f7 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 035/149] Revert "[nrf noup] decompression: Align to changes in nrfcompress API" This reverts commit 1efcec19d74e45296dc9a8c514c77873730d1a08. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/decompression.c | 65 +++++++++++++------------------------ 1 file changed, 23 insertions(+), 42 deletions(-) diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c index ce4fe0b2b..87e3d3763 100644 --- a/boot/zephyr/decompression.c +++ b/boot/zephyr/decompression.c @@ -256,6 +256,15 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h goto finish_without_clean; } + rc = compression_lzma->init(NULL); + rc = compression_arm_thumb->init(NULL); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish_without_clean; + } + /* We need a modified header which has the updated sizes, start with the original header */ memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); @@ -267,28 +276,12 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h if (rc) { BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); rc = BOOT_EBADIMAGE; - goto finish_without_clean; + goto finish; } modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; modified_hdr.ih_img_size = decompressed_image_size; - rc = compression_lzma->init(NULL, decompressed_image_size); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish_without_clean; - } - - rc = compression_arm_thumb->init(NULL, decompressed_image_size); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish; - } - /* Calculate the protected TLV size, these will not include the decompressed * sha/size/signature entries */ @@ -1108,7 +1101,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); rc = BOOT_EBADIMAGE; - goto finish_without_clean; + goto finish; } if (IS_ENCRYPTED(hdr)) { @@ -1131,7 +1124,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl */ BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); rc = BOOT_EBADIMAGE; - goto finish_without_clean; + goto finish; } compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); @@ -1142,7 +1135,16 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl /* Compression library missing or missing required function pointer */ BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; - goto finish_without_clean; + goto finish; + } + + rc = compression_lzma->init(NULL); + rc = compression_arm_thumb->init(NULL); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish; } write_alignment = flash_area_align(fap_dst); @@ -1156,28 +1158,12 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); rc = BOOT_EBADIMAGE; - goto finish_without_clean; + goto finish; } modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; modified_hdr.ih_img_size = decompressed_image_size; - rc = compression_lzma->init(NULL, decompressed_image_size); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish_without_clean; - } - - rc = compression_arm_thumb->init(NULL, decompressed_image_size); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish; - } - /* Calculate protected TLV size for target image once items are removed */ rc = boot_size_protected_tlvs(hdr, fap_src, &protected_tlv_size); @@ -1471,11 +1457,6 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl } finish: - /* Clean up decompression system */ - (void)compression_lzma->deinit(NULL); - (void)compression_arm_thumb->deinit(NULL); - -finish_without_clean: memset(decomp_buf, 0, sizeof(decomp_buf)); return rc; From 7cee68f1b0c1f22cbd22e3b5e8b6cd2cbb042797 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 036/149] Revert "[nrf noup] zephyr: Add support for compressed image updates" This reverts commit 90b22796b1a6f08705c79ddf5884f3a83a2563a0. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/bootutil_misc.c | 80 +- boot/bootutil/src/image_validate.c | 223 +-- boot/bootutil/src/loader.c | 27 +- boot/zephyr/CMakeLists.txt | 6 - boot/zephyr/Kconfig | 9 +- boot/zephyr/decompression.c | 1505 ----------------- .../include/compression/decompression.h | 103 -- 7 files changed, 26 insertions(+), 1927 deletions(-) delete mode 100644 boot/zephyr/decompression.c delete mode 100644 boot/zephyr/include/compression/decompression.h diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index ec61f6f9e..396381437 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -47,9 +47,8 @@ #include "swap_priv.h" #endif -#if defined(MCUBOOT_DECOMPRESS_IMAGES) -#include -#include +#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_SWAP_USING_SCRATCH) +#include "swap_priv.h" #endif BOOT_LOG_MODULE_DECLARE(mcuboot); @@ -488,76 +487,35 @@ boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size) fap = BOOT_IMG_AREA(state, slot); assert(fap != NULL); -#ifdef MCUBOOT_DECOMPRESS_IMAGES - if (MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), boot_img_hdr(state, slot))) { - uint32_t tmp_size = 0; - - rc = bootutil_get_img_decomp_size(boot_img_hdr(state, slot), fap, &tmp_size); + off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); - if (rc) { - rc = BOOT_EBADIMAGE; - goto done; - } - - off = boot_img_hdr(state, slot)->ih_hdr_size + tmp_size; - - rc = boot_size_protected_tlvs(boot_img_hdr(state, slot), fap, &tmp_size); + if (flash_area_read(fap, off, &info, sizeof(info))) { + rc = BOOT_EFLASH; + goto done; + } - if (rc) { + protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; + if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { + if (protect_tlv_size != info.it_tlv_tot) { rc = BOOT_EBADIMAGE; goto done; } - off += tmp_size; - - if (flash_area_read(fap, (BOOT_TLV_OFF(boot_img_hdr(state, slot)) + - boot_img_hdr(state, slot)->ih_protect_tlv_size), &info, - sizeof(info))) { + if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { rc = BOOT_EFLASH; goto done; } + } else if (protect_tlv_size != 0) { + rc = BOOT_EBADIMAGE; + goto done; + } - if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { - rc = BOOT_EBADIMAGE; - goto done; - } - - *size = off + info.it_tlv_tot; - } else { -#else - if (1) { -#endif - off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); - - if (flash_area_read(fap, off, &info, sizeof(info))) { - rc = BOOT_EFLASH; - goto done; - } - - protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; - if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { - if (protect_tlv_size != info.it_tlv_tot) { - rc = BOOT_EBADIMAGE; - goto done; - } - - if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { - rc = BOOT_EFLASH; - goto done; - } - } else if (protect_tlv_size != 0) { - rc = BOOT_EBADIMAGE; - goto done; - } - - if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { - rc = BOOT_EBADIMAGE; - goto done; - } - - *size = off + protect_tlv_size + info.it_tlv_tot; + if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { + rc = BOOT_EBADIMAGE; + goto done; } + *size = off + protect_tlv_size + info.it_tlv_tot; rc = 0; done: diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 5d2efc98a..cb9ce3466 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -50,11 +50,6 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); #include "bootutil/mcuboot_uuid.h" #endif /* MCUBOOT_UUID_VID || MCUBOOT_UUID_CID */ -#if defined(MCUBOOT_DECOMPRESS_IMAGES) -#include -#include -#endif - #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -210,7 +205,7 @@ bootutil_img_validate(struct boot_loader_state *state, ) { #if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) \ - || defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) || defined(MCUBOOT_DECOMPRESS_IMAGES) + || defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state)); #endif uint32_t off; @@ -266,67 +261,6 @@ bootutil_img_validate(struct boot_loader_state *state, #endif BOOT_LOG_DBG("bootutil_img_validate: flash area %p", fap); -#ifdef MCUBOOT_DECOMPRESS_IMAGES - /* If the image is compressed, the integrity of the image must also be validated */ - if (MUST_DECOMPRESS(fap, image_index, hdr)) { - bool found_decompressed_size = false; - bool found_decompressed_sha = false; - bool found_decompressed_signature = false; - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true); - if (rc) { - goto out; - } - - if (it.tlv_end > bootutil_max_image_size(state, fap)) { - rc = -1; - goto out; - } - - while (true) { - uint16_t expected_size = 0; - bool *found_flag = NULL; - - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - break; - } - - switch (type) { - case IMAGE_TLV_DECOMP_SIZE: - expected_size = sizeof(size_t); - found_flag = &found_decompressed_size; - break; - case IMAGE_TLV_DECOMP_SHA: - expected_size = IMAGE_HASH_SIZE; - found_flag = &found_decompressed_sha; - break; - case IMAGE_TLV_DECOMP_SIGNATURE: - found_flag = &found_decompressed_signature; - break; - default: - continue; - }; - - if (type == IMAGE_TLV_DECOMP_SIGNATURE && !EXPECTED_SIG_LEN(len)) { - rc = -1; - goto out; - } else if (type != IMAGE_TLV_DECOMP_SIGNATURE && len != expected_size) { - rc = -1; - goto out; - } - - *found_flag = true; - } - - rc = (!found_decompressed_size || !found_decompressed_sha || !found_decompressed_signature); - if (rc) { - goto out; - } - } -#endif #if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) rc = bootutil_img_hash(state, hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len); @@ -661,161 +595,6 @@ bootutil_img_validate(struct boot_loader_state *state, } #endif -#ifdef MCUBOOT_DECOMPRESS_IMAGES - /* Only after all previous verifications have passed, perform a dry-run of the decompression - * and ensure the image is valid - */ - if (!rc && MUST_DECOMPRESS(fap, image_index, hdr)) { - image_hash_valid = 0; - FIH_SET(valid_signature, FIH_FAILURE); - - rc = bootutil_img_hash_decompress(state, hdr, fap, tmp_buf, tmp_buf_sz, - hash, seed, seed_len); - if (rc) { - goto out; - } - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SHA, true); - if (rc) { - goto out; - } - - if (it.tlv_end > bootutil_max_image_size(state, fap)) { - rc = -1; - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - break; - } - - if (type == IMAGE_TLV_DECOMP_SHA) { - /* Verify the image hash. This must always be present. */ - if (len != sizeof(hash)) { - rc = -1; - goto out; - } - rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash)); - if (rc) { - goto out; - } - - FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash)); - if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { - FIH_SET(fih_rc, FIH_FAILURE); - goto out; - } - - image_hash_valid = 1; - } - } - - rc = !image_hash_valid; - if (rc) { - goto out; - } - -#ifdef EXPECTED_SIG_TLV -#ifdef EXPECTED_KEY_TLV - rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false); - if (rc) { - goto out; - } - - if (it.tlv_end > bootutil_max_image_size(state, fap)) { - rc = -1; - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - break; - } - - if (type == EXPECTED_KEY_TLV) { - /* - * Determine which key we should be checking. - */ - if (len > KEY_BUF_SIZE) { - rc = -1; - goto out; - } -#ifndef MCUBOOT_HW_KEY - rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); - if (rc) { - goto out; - } - key_id = bootutil_find_key(buf, len); -#else - rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len); - if (rc) { - goto out; - } - key_id = bootutil_find_key(image_index, key_buf, len); -#endif /* !MCUBOOT_HW_KEY */ - /* - * The key may not be found, which is acceptable. There - * can be multiple signatures, each preceded by a key. - */ - } - } -#endif /* EXPECTED_KEY_TLV */ - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true); - if (rc) { - goto out; - } - - if (it.tlv_end > bootutil_max_image_size(state, fap)) { - rc = -1; - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - - if (type == IMAGE_TLV_DECOMP_SIGNATURE) { - /* Ignore this signature if it is out of bounds. */ - if (key_id < 0 || key_id >= bootutil_key_cnt) { - key_id = -1; - continue; - } - - if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { - rc = -1; - goto out; - } - rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); - if (rc) { - goto out; - } - - FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash), - buf, len, key_id); - key_id = -1; - } - } -#endif /* EXPECTED_SIG_TLV */ - } -#endif - -#ifdef EXPECTED_SIG_TLV - FIH_SET(fih_rc, valid_signature); -#endif - out: if (rc) { FIH_SET(fih_rc, FIH_FAILURE); diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 31aa7d87e..6ed19951c 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -50,11 +50,6 @@ #include "bootutil/boot_hooks.h" #include "bootutil/mcuboot_status.h" -#if defined(MCUBOOT_DECOMPRESS_IMAGES) -#include -#include -#endif - #ifdef __ZEPHYR__ #include #if defined(CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) @@ -840,10 +835,10 @@ boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fa return false; } #else - if (MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), hdr)) { - if (!boot_is_compressed_header_valid(hdr, fap, state)) { - return false; - } + if ((hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1) && + (hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) + { + return false; } #endif @@ -1091,7 +1086,6 @@ boot_validate_slot(struct boot_loader_state *state, int slot, * attempts to validate and boot it. */ } - #if !defined(__BOOTSIM__) BOOT_LOG_ERR("Image in the %s slot is not valid!", (slot == BOOT_SLOT_PRIMARY) ? "primary" : "secondary"); @@ -1748,9 +1742,6 @@ boot_copy_region(struct boot_loader_state *state, #else (void)state; #endif -#if defined(MCUBOOT_DECOMPRESS_IMAGES) && !defined(MCUBOOT_ENC_IMAGES) - struct image_header *hdr; -#endif TARGET_STATIC uint8_t buf[BUF_SZ] __attribute__((aligned(4))); @@ -1776,16 +1767,6 @@ boot_copy_region(struct boot_loader_state *state, } #endif -#ifdef MCUBOOT_DECOMPRESS_IMAGES - hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); - - if (MUST_DECOMPRESS(fap_src, BOOT_CURR_IMG(state), hdr)) { - /* Use alternative function for compressed images */ - return boot_copy_region_decompress(state, fap_src, fap_dst, off_src, off_dst, sz, buf, - BUF_SZ); - } -#endif - bytes_copied = 0; while (bytes_copied < sz) { if (sz - bytes_copied > sizeof buf) { diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index a1e9fa2de..10593cdbf 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -334,12 +334,6 @@ if(CONFIG_BOOT_ENCRYPT_EC256 AND NOT CONFIG_BOOT_ECDSA_PSA) ) endif() -if(CONFIG_BOOT_DECOMPRESSION) - zephyr_library_sources( - decompression.c - ) -endif() - if(CONFIG_MCUBOOT_SERIAL) zephyr_sources(${BOOT_DIR}/zephyr/serial_adapter.c) zephyr_sources(${BOOT_DIR}/boot_serial/src/boot_serial.c) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index f6b1d33d3..1d74880fb 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1197,9 +1197,6 @@ config MCUBOOT_USE_TLV_ALLOW_LIST config BOOT_DECOMPRESSION_SUPPORT bool - depends on NRF_COMPRESS && NRF_COMPRESS_DECOMPRESSION && (NRF_COMPRESS_LZMA_VERSION_LZMA1 || NRF_COMPRESS_LZMA_VERSION_LZMA2) - depends on !SINGLE_APPLICATION_SLOT && BOOT_UPGRADE_ONLY - default y help Hidden symbol which should be selected if a system provided decompression support. @@ -1207,8 +1204,6 @@ if BOOT_DECOMPRESSION_SUPPORT menuconfig BOOT_DECOMPRESSION bool "Decompression" - select NRF_COMPRESS_CLEANUP - select PM_USE_CONFIG_SRAM_SIZE if SOC_NRF54L15_CPUAPP help If enabled, will include support for compressed images being loaded to the secondary slot which then get decompressed into the primary slot. This mode allows the secondary slot to @@ -1217,9 +1212,9 @@ menuconfig BOOT_DECOMPRESSION if BOOT_DECOMPRESSION config BOOT_DECOMPRESSION_BUFFER_SIZE - int + int "Write buffer size" range 16 16384 - default NRF_COMPRESS_CHUNK_SIZE + default 4096 help The size of a secondary buffer used for writing decompressed data to the storage device. diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c deleted file mode 100644 index 87e3d3763..000000000 --- a/boot/zephyr/decompression.c +++ /dev/null @@ -1,1505 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#include -#include "compression/decompression.h" -#include "bootutil/crypto/sha.h" -#include "bootutil/bootutil_log.h" - -#if !defined(__BOOTSIM__) -#define TARGET_STATIC static -#else -#define TARGET_STATIC -#endif - -#if defined(MCUBOOT_SIGN_RSA) -#if MCUBOOT_SIGN_RSA_LEN == 2048 -#define EXPECTED_SIG_TLV IMAGE_TLV_RSA2048_PSS -#elif MCUBOOT_SIGN_RSA_LEN == 3072 -#define EXPECTED_SIG_TLV IMAGE_TLV_RSA3072_PSS -#endif -#elif defined(MCUBOOT_SIGN_EC256) || \ - defined(MCUBOOT_SIGN_EC384) || \ - defined(MCUBOOT_SIGN_EC) -#define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA_SIG -#elif defined(MCUBOOT_SIGN_ED25519) -#define EXPECTED_SIG_TLV IMAGE_TLV_ED25519 -#endif - -#define DECOMP_BUF_SIZE CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) -/* Extra buffer space for being able to writeback ARM thumb decompression output, - * which may be of +2 bytes more size than its input. - */ -#define DECOMP_BUF_EXTRA_SIZE 2 -#else -#define DECOMP_BUF_EXTRA_SIZE 0 -#endif -#define DECOMP_BUF_ALLOC_SIZE (DECOMP_BUF_SIZE + DECOMP_BUF_EXTRA_SIZE) - -#define DECRYPTION_BLOCK_SIZE_AES128 16 -#define DECRYPTION_BLOCK_SIZE_AES256 32 - -/* Number of times that consumed data by decompression system can be 0 in a row before aborting */ -#define OFFSET_ZERO_CHECK_TIMES 3 - -BOOT_LOG_MODULE_DECLARE(mcuboot); - -static int boot_sha_protected_tlvs(const struct image_header *hdr, - const struct flash_area *fap_src, uint32_t protected_size, - uint8_t *buf, size_t buf_size, bootutil_sha_context *sha_ctx); - -bool boot_is_compressed_header_valid(const struct image_header *hdr, const struct flash_area *fap, - struct boot_loader_state *state) -{ - /* Image is compressed in secondary slot, need to check if fits into the primary slot */ - bool opened_flash_area = false; - int primary_fa_id; - int rc; - int size_check; - int size; - uint32_t protected_tlvs_size; - uint32_t decompressed_size; - - primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT); - - if (primary_fa_id == fap->fa_id) { - BOOT_LOG_ERR("Primary slots cannot be compressed, image: %d", BOOT_CURR_IMG(state)); - return false; - } - - if (BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT) == NULL) { - opened_flash_area = true; - } - - rc = flash_area_open(primary_fa_id, &BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); - assert(rc == 0); - - size_check = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); - - if (opened_flash_area) { - (void)flash_area_close(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)); - } - - rc = bootutil_get_img_decomp_size(hdr, fap, &decompressed_size); - - if (rc) { - return false; - } - - if (!boot_u32_safe_add(&size, decompressed_size, hdr->ih_hdr_size)) { - return false; - } - - rc = boot_size_protected_tlvs(hdr, fap, &protected_tlvs_size); - - if (rc) { - return false; - } - - if (!boot_u32_safe_add(&size, size, protected_tlvs_size)) { - return false; - } - - if (size >= size_check) { - BOOT_LOG_ERR("Compressed image too large, decompressed image size: 0x%x, slot size: 0x%x", - size, size_check); - return false; - } - - return true; -} - -static bool is_compression_object_valid(struct nrf_compress_implementation *compression) -{ - if (compression == NULL || compression->init == NULL || compression->deinit == NULL || - compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { - return false; - } - - return true; -} - -#ifdef MCUBOOT_ENC_IMAGES -int bootutil_get_img_decrypted_comp_size(const struct image_header *hdr, - const struct flash_area *fap, uint32_t *img_comp_size) -{ - if (hdr == NULL || fap == NULL || img_comp_size == NULL) { - return BOOT_EBADARGS; - } else if (hdr->ih_protect_tlv_size == 0) { - return BOOT_EBADIMAGE; - } - - if (!IS_ENCRYPTED(hdr)) { - /* Update is not encrypted so use size from header */ - *img_comp_size = hdr->ih_img_size; - } else { - struct image_tlv_iter it; - uint32_t off; - uint16_t len; - int32_t rc; - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_COMP_DEC_SIZE, true); - - if (rc) { - return rc; - } - - rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); - - if (rc != 0) { - return -1; - } - - if (len != sizeof(*img_comp_size)) { - BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); - return BOOT_EBADIMAGE; - } - - rc = LOAD_IMAGE_DATA(hdr, fap, off, img_comp_size, len); - - if (rc) { - BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - off, len, fap->fa_id, rc); - return BOOT_EFLASH; - } - } - - return 0; -} -#endif - -int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_header *hdr, - const struct flash_area *fap, uint8_t *tmp_buf, - uint32_t tmp_buf_sz, uint8_t *hash_result, - uint8_t *seed, int seed_len) -{ - int rc; - uint32_t read_pos = 0; - uint32_t write_pos = 0; - uint32_t protected_tlv_size = 0; - uint32_t decompressed_image_size; - uint32_t output_size_total = 0; - struct nrf_compress_implementation *compression_lzma = NULL; - struct nrf_compress_implementation *compression_arm_thumb = NULL; - TARGET_STATIC struct image_header modified_hdr; - bootutil_sha_context sha_ctx; - -#ifdef MCUBOOT_ENC_IMAGES - struct enc_key_data *enc_state; - int image_index; - uint32_t comp_size = 0; - uint8_t decryption_block_size = 0; - - rc = bootutil_get_img_decrypted_comp_size(hdr, fap, &comp_size); - - if (rc) { - BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); - rc = BOOT_EBADIMAGE; - goto finish_end; - } - - if (state == NULL) { - enc_state = NULL; - image_index = 0; - } else { - enc_state = BOOT_CURR_ENC(state); - image_index = BOOT_CURR_IMG(state); - } - - /* Encrypted images only exist in the secondary slot */ - if (MUST_DECRYPT(fap, image_index, hdr) && - !boot_enc_valid(enc_state, 1)) { - return -1; - } - - if (MUST_DECRYPT(fap, image_index, hdr)) { - if (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES128) { - decryption_block_size = DECRYPTION_BLOCK_SIZE_AES128; - } else if (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES256) { - decryption_block_size = DECRYPTION_BLOCK_SIZE_AES256; - } else { - LOG_ERR("Unknown decryption block size"); - rc = BOOT_EBADIMAGE; - goto finish_end; - } - } -#endif - - bootutil_sha_init(&sha_ctx); - - /* Setup decompression system */ -#if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 - if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { -#elif CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2 - if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) { -#endif - /* Compressed image does not use the correct compression type which is supported by this - * build - */ - BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); - rc = BOOT_EBADIMAGE; - goto finish_without_clean; - } - - compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); - compression_arm_thumb = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_ARM_THUMB); - - if (!is_compression_object_valid(compression_lzma) || - !is_compression_object_valid(compression_arm_thumb)) { - /* Compression library missing or missing required function pointer */ - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish_without_clean; - } - - rc = compression_lzma->init(NULL); - rc = compression_arm_thumb->init(NULL); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish_without_clean; - } - - /* We need a modified header which has the updated sizes, start with the original header */ - memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); - - /* Extract the decompressed image size from the protected TLV, set it and remove the - * compressed image flags - */ - rc = bootutil_get_img_decomp_size(hdr, fap, &decompressed_image_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); - rc = BOOT_EBADIMAGE; - goto finish; - } - - modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; - modified_hdr.ih_img_size = decompressed_image_size; - - /* Calculate the protected TLV size, these will not include the decompressed - * sha/size/signature entries - */ - rc = boot_size_protected_tlvs(hdr, fap, &protected_tlv_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); - rc = BOOT_EBADIMAGE; - goto finish; - } - - modified_hdr.ih_protect_tlv_size = protected_tlv_size; - bootutil_sha_update(&sha_ctx, &modified_hdr, sizeof(modified_hdr)); - read_pos = sizeof(modified_hdr); - - while (read_pos < modified_hdr.ih_hdr_size) { - uint32_t copy_size = tmp_buf_sz; - - if ((read_pos + copy_size) > modified_hdr.ih_hdr_size) { - copy_size = modified_hdr.ih_hdr_size - read_pos; - } - - rc = flash_area_read(fap, read_pos, tmp_buf, copy_size); - - if (rc != 0) { - BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (hdr->ih_hdr_size + read_pos), copy_size, fap->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - - bootutil_sha_update(&sha_ctx, tmp_buf, copy_size); - read_pos += copy_size; - } - - /* Read in compressed data, decompress and add to hash calculation */ - read_pos = 0; - -#ifdef MCUBOOT_ENC_IMAGES - while (read_pos < comp_size) { - uint32_t copy_size = comp_size - read_pos; -#else - while (read_pos < hdr->ih_img_size) { - uint32_t copy_size = hdr->ih_img_size - read_pos; -#endif - uint32_t tmp_off = 0; - uint8_t offset_zero_check = 0; - - if (copy_size > tmp_buf_sz) { - copy_size = tmp_buf_sz; - } - - rc = flash_area_read(fap, (hdr->ih_hdr_size + read_pos), tmp_buf, copy_size); - - if (rc != 0) { - BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (hdr->ih_hdr_size + read_pos), copy_size, fap->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - -#ifdef MCUBOOT_ENC_IMAGES - if (MUST_DECRYPT(fap, image_index, hdr)) { - uint8_t dummy_bytes = 0; - - if ((copy_size % decryption_block_size)) { - dummy_bytes = decryption_block_size - (copy_size % decryption_block_size); - memset(&tmp_buf[copy_size], 0x00, dummy_bytes); - } - - boot_enc_decrypt(enc_state, 1, read_pos, (copy_size + dummy_bytes), (read_pos & 0xf), - tmp_buf); - } -#endif - - /* Decompress data in chunks, writing it back with a larger write offset of the primary - * slot than read size of the secondary slot - */ - while (tmp_off < copy_size) { - uint32_t offset = 0; - uint8_t *output = NULL; - uint32_t output_size = 0; - uint32_t chunk_size; - bool last_packet = false; - - chunk_size = compression_lzma->decompress_bytes_needed(NULL); - - if (chunk_size > (copy_size - tmp_off)) { - chunk_size = (copy_size - tmp_off); - } - -#ifdef MCUBOOT_ENC_IMAGES - if ((read_pos + tmp_off + chunk_size) >= comp_size) { -#else - if ((read_pos + tmp_off + chunk_size) >= hdr->ih_img_size) { -#endif - last_packet = true; - } - - rc = compression_lzma->decompress(NULL, &tmp_buf[tmp_off], chunk_size, last_packet, - &offset, &output, &output_size); - - if (rc) { - BOOT_LOG_ERR("Decompression error: %d", rc); - rc = BOOT_EBADSTATUS; - goto finish; - } - - write_pos += output_size; - - if (write_pos > decompressed_image_size) { - BOOT_LOG_ERR("Decompressed image larger than claimed TLV size, at least: %d", - write_pos); - rc = BOOT_EBADIMAGE; - goto finish; - } - - /* Additional dry-run validity checks */ - if (last_packet == true && write_pos == 0) { - /* Last packet and we still have no output, this is a faulty update */ - BOOT_LOG_ERR("All compressed data consumed without any output, image not valid"); - rc = BOOT_EBADIMAGE; - goto finish; - } - - if (offset == 0) { - /* If the decompression system continually consumes 0 bytes, then there is a - * problem with this update image, abort and mark image as bad - */ - if (offset_zero_check >= OFFSET_ZERO_CHECK_TIMES) { - BOOT_LOG_ERR("Decompression system returning no output data, image not valid"); - rc = BOOT_EBADIMAGE; - goto finish; - } - - ++offset_zero_check; - - break; - } else { - offset_zero_check = 0; - } - - /* Copy data to secondary buffer for calculating hash */ - if (output_size > 0) { - if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { - /* Run this through the ARM thumb filter */ - uint32_t offset_arm_thumb = 0; - uint8_t *output_arm_thumb = NULL; - uint32_t processed_size = 0; - uint32_t output_size_arm_thumb = 0; - - while (processed_size < output_size) { - uint32_t current_size = output_size - processed_size; - bool arm_thumb_last_packet = false; - - if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) { - current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE; - } - - if (last_packet && (processed_size + current_size) == - output_size) { - arm_thumb_last_packet = true; - } - - rc = compression_arm_thumb->decompress(NULL, &output[processed_size], - current_size, arm_thumb_last_packet, - &offset_arm_thumb, - &output_arm_thumb, - &output_size_arm_thumb); - - if (rc) { - BOOT_LOG_ERR("Decompression error: %d", rc); - rc = BOOT_EBADSTATUS; - goto finish; - } - - bootutil_sha_update(&sha_ctx, output_arm_thumb, output_size_arm_thumb); - output_size_total += output_size_arm_thumb; - processed_size += current_size; - } - } else { - bootutil_sha_update(&sha_ctx, output, output_size); - output_size_total += output_size; - } - } - - tmp_off += offset; - } - - read_pos += copy_size; - } - - if (modified_hdr.ih_img_size != output_size_total) { - BOOT_LOG_ERR("Decompression expected output_size mismatch: %d vs %d", - modified_hdr.ih_img_size, output_size_total); - rc = BOOT_EBADSTATUS; - goto finish; - } - - /* If there are any protected TLVs present, add them after the main decompressed image */ - if (modified_hdr.ih_protect_tlv_size > 0) { - rc = boot_sha_protected_tlvs(hdr, fap, modified_hdr.ih_protect_tlv_size, tmp_buf, - tmp_buf_sz, &sha_ctx); - } - - bootutil_sha_finish(&sha_ctx, hash_result); - -finish: - /* Clean up decompression system */ - (void)compression_lzma->deinit(NULL); - (void)compression_arm_thumb->deinit(NULL); - -finish_without_clean: - bootutil_sha_drop(&sha_ctx); - -#ifdef MCUBOOT_ENC_IMAGES -finish_end: -#endif - return rc; -} - -static int boot_copy_protected_tlvs(const struct image_header *hdr, - const struct flash_area *fap_src, - const struct flash_area *fap_dst, uint32_t off_dst, - uint32_t protected_size, uint8_t *buf, size_t buf_size, - uint16_t *buf_pos, uint32_t *written) -{ - int rc; - uint32_t off; - uint32_t write_pos = 0; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - struct image_tlv tlv_header; - struct image_tlv_info tlv_info_header = { - .it_magic = IMAGE_TLV_PROT_INFO_MAGIC, - .it_tlv_tot = protected_size, - }; - uint16_t info_size_left = sizeof(tlv_info_header); - - while (info_size_left > 0) { - uint16_t copy_size = buf_size - *buf_pos; - - if (info_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - uint8_t *tlv_info_header_address = (uint8_t *)&tlv_info_header; - - if (single_copy_size > info_size_left) { - single_copy_size = info_size_left; - } - - memcpy(&buf[*buf_pos], &tlv_info_header_address[sizeof(tlv_info_header) - - info_size_left], single_copy_size); - *buf_pos += single_copy_size; - info_size_left -= single_copy_size; - } - - if (*buf_pos == buf_size) { - rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); - - if (rc != 0) { - BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto out; - } - - write_pos += *buf_pos; - *buf_pos = 0; - } - } - - rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, true); - - if (rc) { - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - - if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { - /* Skip these TLVs as they are not needed */ - continue; - } else { - uint16_t header_size_left = sizeof(tlv_header); - uint16_t data_size_left = len; - - tlv_header.it_type = type; - tlv_header.it_len = len; - - while (header_size_left > 0 || data_size_left > 0) { - uint16_t copy_size = buf_size - *buf_pos; - uint8_t *tlv_header_address = (uint8_t *)&tlv_header; - - if (header_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - - if (single_copy_size > header_size_left) { - single_copy_size = header_size_left; - } - - memcpy(&buf[*buf_pos], &tlv_header_address[sizeof(tlv_header) - - header_size_left], - single_copy_size); - *buf_pos += single_copy_size; - copy_size -= single_copy_size; - header_size_left -= single_copy_size; - } - - if (data_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - - if (single_copy_size > data_size_left) { - single_copy_size = data_size_left; - } - - rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + (len - data_size_left)), - &buf[*buf_pos], single_copy_size); - - if (rc) { - BOOT_LOG_ERR( - "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); - goto out; - } - - *buf_pos += single_copy_size; - data_size_left -= single_copy_size; - } - - if (*buf_pos == buf_size) { - rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto out; - } - - write_pos += *buf_pos; - *buf_pos = 0; - } - } - } - } - - *written = write_pos; - -out: - return rc; -} - -static int boot_sha_protected_tlvs(const struct image_header *hdr, - const struct flash_area *fap_src, uint32_t protected_size, - uint8_t *buf, size_t buf_size, bootutil_sha_context *sha_ctx) -{ - int rc; - uint32_t off; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - struct image_tlv tlv_header; - struct image_tlv_info tlv_info_header = { - .it_magic = IMAGE_TLV_PROT_INFO_MAGIC, - .it_tlv_tot = protected_size, - }; - - bootutil_sha_update(sha_ctx, &tlv_info_header, sizeof(tlv_info_header)); - - rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, true); - if (rc) { - goto out; - } - - while (true) { - uint32_t read_off = 0; - - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - - if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { - /* Skip these TLVs as they are not needed */ - continue; - } - - tlv_header.it_type = type; - tlv_header.it_len = len; - - bootutil_sha_update(sha_ctx, &tlv_header, sizeof(tlv_header)); - - while (read_off < len) { - uint32_t copy_size = buf_size; - - if (copy_size > (len - read_off)) { - copy_size = len - read_off; - } - - rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + read_off), buf, copy_size); - - if (rc) { - BOOT_LOG_ERR( - "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off + read_off), copy_size, fap_src->fa_id, rc); - goto out; - } - - bootutil_sha_update(sha_ctx, buf, copy_size); - read_off += copy_size; - } - } - -out: - return rc; -} - -int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_area *fap, - uint32_t *sz) -{ - int rc = 0; - uint32_t tlv_size; - uint32_t off; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - - *sz = 0; - tlv_size = hdr->ih_protect_tlv_size; - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true); - - if (rc) { - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - - if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || - type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { - /* Exclude these TLVs as they will be copied to the unprotected area */ - tlv_size -= len + sizeof(struct image_tlv); - } - } - - if (!rc) { - if (tlv_size == sizeof(struct image_tlv_info)) { - /* If there are no entries then omit protected TLV section entirely */ - tlv_size = 0; - } - - *sz = tlv_size; - } - -out: - return rc; -} - -int boot_size_unprotected_tlvs(const struct image_header *hdr, const struct flash_area *fap, - uint32_t *sz) -{ - int rc = 0; - uint32_t tlv_size; - uint32_t off; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - - *sz = 0; - tlv_size = sizeof(struct image_tlv_info); - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false); - - if (rc) { - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } else if (bootutil_tlv_iter_is_prot(&it, off) && type != IMAGE_TLV_DECOMP_SHA && - type != IMAGE_TLV_DECOMP_SIGNATURE) { - /* Include size of protected hash and signature as these will be replacing the - * original ones - */ - continue; - } else if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV || type == IMAGE_TLV_COMP_DEC_SIZE) { - /* Exclude the original unprotected TLVs for signature and hash, the length of the - * signature of the compressed data might not be the same size as the signaute of the - * decompressed data, as is the case when using ECDSA-P256 - */ - continue; - } - - tlv_size += len + sizeof(struct image_tlv); - } - - if (!rc) { - if (tlv_size == sizeof(struct image_tlv_info)) { - /* If there are no entries in the unprotected TLV section then there is something wrong - * with this image - */ - BOOT_LOG_ERR("No unprotected TLVs in post-decompressed image output, image is invalid"); - rc = BOOT_EBADIMAGE; - goto out; - } - - *sz = tlv_size; - } - -out: - return rc; -} - -static int boot_copy_unprotected_tlvs(const struct image_header *hdr, - const struct flash_area *fap_src, - const struct flash_area *fap_dst, uint32_t off_dst, - uint32_t unprotected_size, uint8_t *buf, size_t buf_size, - uint16_t *buf_pos, uint32_t *written) -{ - int rc; - uint32_t write_pos = 0; - uint32_t off; - uint16_t len; - uint16_t type; - struct image_tlv_iter it; - struct image_tlv_iter it_protected; - struct image_tlv tlv_header; - struct image_tlv_info tlv_info_header = { - .it_magic = IMAGE_TLV_INFO_MAGIC, - .it_tlv_tot = unprotected_size, - }; - uint16_t info_size_left = sizeof(tlv_info_header); - - while (info_size_left > 0) { - uint16_t copy_size = buf_size - *buf_pos; - - if (info_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - uint8_t *tlv_info_header_address = (uint8_t *)&tlv_info_header; - - if (single_copy_size > info_size_left) { - single_copy_size = info_size_left; - } - - memcpy(&buf[*buf_pos], &tlv_info_header_address[sizeof(tlv_info_header) - - info_size_left], single_copy_size); - *buf_pos += single_copy_size; - info_size_left -= single_copy_size; - } - - if (*buf_pos == buf_size) { - rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); - - if (rc != 0) { - BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto out; - } - - write_pos += *buf_pos; - *buf_pos = 0; - } - } - - rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, false); - if (rc) { - goto out; - } - - while (true) { - uint16_t header_size_left = sizeof(tlv_header); - uint16_t data_size_left; - - rc = bootutil_tlv_iter_next(&it, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } else if (bootutil_tlv_iter_is_prot(&it, off)) { - /* Skip protected TLVs */ - continue; - } - - /* Change the values of these fields from having the data in the compressed image - * unprotected TLV (which is valid only for the compressed image data) to having the - * fields in the protected TLV section (which is valid for the decompressed image data). - * The compressed data is no longer needed - */ - if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV) { - rc = bootutil_tlv_iter_begin(&it_protected, hdr, fap_src, (type == EXPECTED_HASH_TLV ? - IMAGE_TLV_DECOMP_SHA : - IMAGE_TLV_DECOMP_SIGNATURE), - true); - - if (rc) { - goto out; - } - - while (true) { - rc = bootutil_tlv_iter_next(&it_protected, &off, &len, &type); - if (rc < 0) { - goto out; - } else if (rc > 0) { - rc = 0; - break; - } - } - - if (type == IMAGE_TLV_DECOMP_SHA) { - type = EXPECTED_HASH_TLV; - } else { - type = EXPECTED_SIG_TLV; - } - } - - data_size_left = len; - tlv_header.it_type = type; - tlv_header.it_len = len; - - while (header_size_left > 0 || data_size_left > 0) { - uint16_t copy_size = buf_size - *buf_pos; - - if (header_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - uint8_t *tlv_header_address = (uint8_t *)&tlv_header; - - if (single_copy_size > header_size_left) { - single_copy_size = header_size_left; - } - - memcpy(&buf[*buf_pos], &tlv_header_address[sizeof(tlv_header) - header_size_left], - single_copy_size); - *buf_pos += single_copy_size; - copy_size -= single_copy_size; - header_size_left -= single_copy_size; - } - - if (data_size_left > 0 && copy_size > 0) { - uint16_t single_copy_size = copy_size; - - if (single_copy_size > data_size_left) { - single_copy_size = data_size_left; - } - - rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + len - data_size_left), - &buf[*buf_pos], single_copy_size); - - if (rc) { - BOOT_LOG_ERR( - "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); - goto out; - } - - *buf_pos += single_copy_size; - data_size_left -= single_copy_size; - } - - if (*buf_pos == buf_size) { - rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto out; - } - - write_pos += *buf_pos; - *buf_pos = 0; - } - } - } - - *written = write_pos; - -out: - return rc; -} - -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) -/** - * @brief Helper function for in-place ARM Thumb filtering. - * This function places the decompressed data back into the same buffer - * at the beginning, overwriting the compressed data. WARNING: because - * ARM Thumb filtering can return +-2 more/less bytes than the input, - * the buffer provided needs to have free DECOMP_BUF_EXTRA_SIZE bytes at - * the beginning and provide valid data for filtering after these. - * - * @param[in] arm_thumb_impl Pointer to the ARM Thumb decompression implementation. - * @param[in,out] buf Pointer to the buffer containing the compressed data / filtered data. - * @param[in] buf_size Size of the buffer (including DECOMP_BUF_EXTRA_SIZE bytes at the beginning). - * @param[out] out_size Pointer to a variable where the size of the filtered data will be stored. - * @param[in] last_part Indicates if this is the last part of the data to be filtered. - * - * @return 0 on success, BOOT_EBADSTATUS on error. - */ -static int boot_arm_thumb_filter(struct nrf_compress_implementation * const arm_thumb_impl, - uint8_t *buf, size_t buf_size, size_t *out_size, bool last_part) { - - uint32_t filter_writeback_pos = 0; - uint32_t processed_size = 0; - int rc; - - while (processed_size < (buf_size - DECOMP_BUF_EXTRA_SIZE)) { - uint32_t offset_arm_thumb = 0; - uint32_t output_size_arm_thumb = 0; - uint8_t *output_arm_thumb = NULL; - uint32_t current_size = (buf_size - DECOMP_BUF_EXTRA_SIZE - processed_size); - bool arm_thumb_last_packet = false; - - if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) { - current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE; - } - - if (last_part && (processed_size + current_size) == (buf_size - DECOMP_BUF_EXTRA_SIZE)) { - arm_thumb_last_packet = true; - } - - rc = arm_thumb_impl->decompress(NULL, - &buf[processed_size + - DECOMP_BUF_EXTRA_SIZE], - current_size, - arm_thumb_last_packet, - &offset_arm_thumb, - &output_arm_thumb, - &output_size_arm_thumb); - - if (rc) { - BOOT_LOG_ERR("Decompression error: %d", rc); - return BOOT_EBADSTATUS; - } - - if (output_size_arm_thumb > (buf_size - filter_writeback_pos)) { - BOOT_LOG_ERR("Filter writeback position exceeds buffer size"); - return BOOT_EBADSTATUS; - } - - memcpy(&buf[filter_writeback_pos], output_arm_thumb, - output_size_arm_thumb); - filter_writeback_pos += output_size_arm_thumb; - processed_size += offset_arm_thumb; - } - *out_size = filter_writeback_pos; - - return 0; -} -#endif /* CONFIG_NRF_COMPRESS_ARM_THUMB */ - -int boot_copy_region_decompress(struct boot_loader_state *state, const struct flash_area *fap_src, - const struct flash_area *fap_dst, uint32_t off_src, - uint32_t off_dst, uint32_t sz, uint8_t *buf, size_t buf_size) -{ - int rc; - uint32_t pos = 0; - uint16_t decomp_buf_size = 0; - uint16_t write_alignment; - uint32_t write_pos = 0; - uint32_t protected_tlv_size = 0; - uint32_t unprotected_tlv_size = 0; - uint32_t tlv_write_size = 0; - uint32_t decompressed_image_size; - struct nrf_compress_implementation *compression_lzma = NULL; - struct nrf_compress_implementation *compression_arm_thumb = NULL; - struct image_header *hdr; - TARGET_STATIC uint8_t decomp_buf[DECOMP_BUF_ALLOC_SIZE] __attribute__((aligned(4))); - TARGET_STATIC struct image_header modified_hdr; - uint16_t decomp_buf_max_size; - -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) - uint8_t unaligned_data_length = 0; -#endif - -#ifdef MCUBOOT_ENC_IMAGES - uint32_t comp_size = 0; - uint8_t decryption_block_size = 0; -#endif - - hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); - -#ifdef MCUBOOT_ENC_IMAGES - rc = bootutil_get_img_decrypted_comp_size(hdr, fap_src, &comp_size); - - if (rc) { - BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); - rc = BOOT_EBADIMAGE; - goto finish; - } - - if (IS_ENCRYPTED(hdr)) { - if (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES128) { - decryption_block_size = DECRYPTION_BLOCK_SIZE_AES128; - } else if (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES256) { - decryption_block_size = DECRYPTION_BLOCK_SIZE_AES256; - } - } -#endif - - /* Setup decompression system */ -#if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 - if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { -#elif CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2 - if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) { -#endif - /* Compressed image does not use the correct compression type which is supported by this - * build - */ - BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); - rc = BOOT_EBADIMAGE; - goto finish; - } - - compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); - compression_arm_thumb = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_ARM_THUMB); - - if (!is_compression_object_valid(compression_lzma) || - !is_compression_object_valid(compression_arm_thumb)) { - /* Compression library missing or missing required function pointer */ - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish; - } - - rc = compression_lzma->init(NULL); - rc = compression_arm_thumb->init(NULL); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish; - } - - write_alignment = flash_area_align(fap_dst); - - decomp_buf_max_size = DECOMP_BUF_SIZE - (DECOMP_BUF_SIZE % write_alignment); - - memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); - - rc = bootutil_get_img_decomp_size(hdr, fap_src, &decompressed_image_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); - rc = BOOT_EBADIMAGE; - goto finish; - } - - modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; - modified_hdr.ih_img_size = decompressed_image_size; - - /* Calculate protected TLV size for target image once items are removed */ - rc = boot_size_protected_tlvs(hdr, fap_src, &protected_tlv_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); - rc = BOOT_EBADIMAGE; - goto finish; - } - - modified_hdr.ih_protect_tlv_size = protected_tlv_size; - - rc = boot_size_unprotected_tlvs(hdr, fap_src, &unprotected_tlv_size); - - if (rc) { - BOOT_LOG_ERR("Unable to determine unprotected TLV size of compressed image"); - rc = BOOT_EBADIMAGE; - goto finish; - } - - /* Write out the image header first, this should be a multiple of the write size */ - rc = flash_area_write(fap_dst, off_dst, &modified_hdr, sizeof(modified_hdr)); - - if (rc != 0) { - BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - off_dst, sizeof(modified_hdr), fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - - /* Read in, decompress and write out data */ -#ifdef MCUBOOT_ENC_IMAGES - while (pos < comp_size) { - uint32_t copy_size = comp_size - pos; -#else - while (pos < hdr->ih_img_size) { - uint32_t copy_size = hdr->ih_img_size - pos; -#endif - uint32_t tmp_off = 0; - - if (copy_size > buf_size) { - copy_size = buf_size; - } - - rc = flash_area_read(fap_src, off_src + hdr->ih_hdr_size + pos, buf, copy_size); - - if (rc != 0) { - BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_src + hdr->ih_hdr_size + pos), copy_size, fap_src->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - -#ifdef MCUBOOT_ENC_IMAGES - if (IS_ENCRYPTED(hdr)) { - uint8_t dummy_bytes = 0; - - if ((copy_size % decryption_block_size)) { - dummy_bytes = decryption_block_size - (copy_size % decryption_block_size); - memset(&buf[copy_size], 0x00, dummy_bytes); - } - - boot_enc_decrypt(BOOT_CURR_ENC(state), 1, pos, (copy_size + dummy_bytes), (pos & 0xf), buf); - } -#endif - - /* Decompress data in chunks, writing it back with a larger write offset of the primary - * slot than read size of the secondary slot - */ - while (tmp_off < copy_size) { - uint32_t offset = 0; - uint32_t output_size = 0; - uint32_t chunk_size; - uint32_t compression_buffer_pos = 0; - uint8_t *output = NULL; - bool last_packet = false; - - chunk_size = compression_lzma->decompress_bytes_needed(NULL); - - if (chunk_size > (copy_size - tmp_off)) { - chunk_size = (copy_size - tmp_off); - } - -#ifdef MCUBOOT_ENC_IMAGES - if ((pos + tmp_off + chunk_size) >= comp_size) { -#else - if ((pos + tmp_off + chunk_size) >= hdr->ih_img_size) { -#endif - last_packet = true; - } - - rc = compression_lzma->decompress(NULL, &buf[tmp_off], chunk_size, last_packet, - &offset, &output, &output_size); - - if (rc) { - BOOT_LOG_ERR("Decompression error: %d", rc); - rc = BOOT_EBADSTATUS; - goto finish; - } - - /* Copy data to secondary buffer for writing out */ - while (output_size > 0) { - uint32_t data_size = (decomp_buf_max_size - decomp_buf_size); - - if (data_size > output_size) { - data_size = output_size; - } - -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) - if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { - memcpy(&decomp_buf[decomp_buf_size + DECOMP_BUF_EXTRA_SIZE], - &output[compression_buffer_pos], data_size); - } else -#endif - { - memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos], - data_size); - } - - compression_buffer_pos += data_size; - - decomp_buf_size += data_size; - output_size -= data_size; - - /* Write data out from secondary buffer when it is full */ - if (decomp_buf_size == decomp_buf_max_size) { -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) - if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { - - uint32_t filter_output_size; - - /* Run this through the ARM thumb filter */ - rc = boot_arm_thumb_filter(compression_arm_thumb, - &decomp_buf[unaligned_data_length], - decomp_buf_size - unaligned_data_length + DECOMP_BUF_EXTRA_SIZE, - &filter_output_size, - last_packet && output_size == 0); - - if (rc) { - goto finish; - } - - decomp_buf_size = filter_output_size + unaligned_data_length; - unaligned_data_length = decomp_buf_size % write_alignment; - - rc = flash_area_write(fap_dst, - (off_dst + hdr->ih_hdr_size + write_pos), - decomp_buf, - (decomp_buf_size - unaligned_data_length)); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + hdr->ih_hdr_size + write_pos), - (decomp_buf_size - unaligned_data_length), - fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - - memmove(decomp_buf, - &decomp_buf[decomp_buf_size - unaligned_data_length], - unaligned_data_length); - write_pos += decomp_buf_size - unaligned_data_length; - decomp_buf_size = unaligned_data_length; - } else -#endif - { - rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), - decomp_buf, decomp_buf_max_size); - - if (rc != 0) { - BOOT_LOG_ERR( - "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_max_size, - fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - - write_pos += decomp_buf_max_size; - decomp_buf_size = 0; - } - } - } - - tmp_off += offset; - } - - pos += copy_size; - } - -#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) - if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT && decomp_buf_size > 0) { - /* Extra data that has not been written out that needs ARM thumb filter applied */ - - uint32_t filter_output_size; - - rc = boot_arm_thumb_filter(compression_arm_thumb, - &decomp_buf[unaligned_data_length], - decomp_buf_size - unaligned_data_length + DECOMP_BUF_EXTRA_SIZE, - &filter_output_size, - true); - - if (rc) { - goto finish; - } - - decomp_buf_size = filter_output_size + unaligned_data_length; - - if (decomp_buf_size > decomp_buf_max_size) { - /* It can happen if ARM thumb decompression returned +2 bytes and we had near full - * decomp_buf. We still can hold these additional 2 bytes because of - * DECOMP_BUF_EXTRA_SIZE allocated. */ - - rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), - decomp_buf, decomp_buf_max_size); - - if (rc != 0) { - BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_max_size, - fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - memmove(decomp_buf, &decomp_buf[decomp_buf_max_size], - (decomp_buf_size - decomp_buf_max_size)); - - decomp_buf_size = decomp_buf_size - decomp_buf_max_size; - write_pos += decomp_buf_max_size; - } - } -#endif - - /* Clean up decompression system */ - (void)compression_lzma->deinit(NULL); - (void)compression_arm_thumb->deinit(NULL); - - if (protected_tlv_size > 0) { - rc = boot_copy_protected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + - write_pos), protected_tlv_size, - decomp_buf, decomp_buf_max_size, &decomp_buf_size, - &tlv_write_size); - - if (rc) { - BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); - goto finish; - } - - write_pos += tlv_write_size; - } - - tlv_write_size = 0; - rc = boot_copy_unprotected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + - write_pos), unprotected_tlv_size, - decomp_buf, decomp_buf_max_size, &decomp_buf_size, - &tlv_write_size); - - if (rc) { - BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); - goto finish; - } - - write_pos += tlv_write_size; - - /* Check if we have unwritten data buffered up and, if so, write it out */ - if (decomp_buf_size > 0) { - uint32_t write_padding_size = write_alignment - (decomp_buf_size % write_alignment); - - /* Check if additional write padding should be applied to meet the minimum write size */ - if (write_alignment > 1 && write_padding_size) { - uint8_t flash_erased_value; - - flash_erased_value = flash_area_erased_val(fap_dst); - memset(&decomp_buf[decomp_buf_size], flash_erased_value, write_padding_size); - decomp_buf_size += write_padding_size; - } - - rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf, - decomp_buf_size); - - if (rc != 0) { - BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_size, - fap_dst->fa_id, rc); - rc = BOOT_EFLASH; - goto finish; - } - - write_pos += decomp_buf_size; - decomp_buf_size = 0; - } - -finish: - memset(decomp_buf, 0, sizeof(decomp_buf)); - - return rc; -} - -int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct flash_area *fap, - uint32_t *img_decomp_size) -{ - struct image_tlv_iter it; - uint32_t off; - uint16_t len; - int32_t rc; - - if (hdr == NULL || fap == NULL || img_decomp_size == NULL) { - return BOOT_EBADARGS; - } else if (hdr->ih_protect_tlv_size == 0) { - return BOOT_EBADIMAGE; - } - - rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIZE, true); - - if (rc) { - return rc; - } - - rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); - - if (rc != 0) { - return -1; - } - - if (len != sizeof(*img_decomp_size)) { - BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); - return BOOT_EBADIMAGE; - } - - rc = LOAD_IMAGE_DATA(hdr, fap, off, img_decomp_size, len); - - if (rc) { - BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", - off, len, fap->fa_id, rc); - return BOOT_EFLASH; - } - - return 0; -} diff --git a/boot/zephyr/include/compression/decompression.h b/boot/zephyr/include/compression/decompression.h deleted file mode 100644 index 2104c4eb6..000000000 --- a/boot/zephyr/include/compression/decompression.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2024 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#ifndef H_DECOMPRESSION_ -#define H_DECOMPRESSION_ - -#include -#include -#include -#include "bootutil/bootutil.h" -#include "bootutil/bootutil_public.h" -#include "bootutil/image.h" -#include "../src/bootutil_priv.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Checks if a compressed image header is valid. - * - * @param hdr Image header. - * @param fap Flash area of the slot. - * @param state Bootloader state object. - * - * @return true if valid; false if invalid. - */ -bool boot_is_compressed_header_valid(const struct image_header *hdr, const struct flash_area *fap, - struct boot_loader_state *state); - -/** - * Reads in compressed image data from a slot, decompresses it and writes it out to a destination - * slot, including corresponding image headers and TLVs. - * - * @param state Bootloader state object. - * @param fap_src Flash area of the source slot. - * @param fap_dst Flash area of the destination slot. - * @param off_src Offset of the source slot to read from (should be 0). - * @param off_dst Offset of the destination slot to write to (should be 0). - * @param sz Size of the source slot data. - * @param buf Temporary buffer for reading data from. - * @param buf_size Size of temporary buffer. - * - * @return 0 on success; nonzero on failure. - */ -int boot_copy_region_decompress(struct boot_loader_state *state, const struct flash_area *fap_src, - const struct flash_area *fap_dst, uint32_t off_src, - uint32_t off_dst, uint32_t sz, uint8_t *buf, size_t buf_size); - -/** - * Gets the total data size (excluding headers and TLVs) of a compressed image when it is - * decompressed. - * - * @param hdr Image header. - * @param fap Flash area of the slot. - * @param img_decomp_size Pointer to variable that will be updated with the decompressed image - * size. - * - * @return 0 on success; nonzero on failure. - */ -int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct flash_area *fap, - uint32_t *img_decomp_size); - -/** - * Calculate MCUboot-compatible image hash of compressed image slot. - * - * @param state MCUboot state. - * @param hdr Image header. - * @param fap Flash area of the slot. - * @param tmp_buf Temporary buffer for reading data from. - * @param tmp_buf_sz Size of temporary buffer. - * @param hash_result Pointer to a variable that will be updated with the image hash. - * @param seed Not currently used, set to NULL. - * @param seed_len Not currently used, set to 0. - * - * @return 0 on success; nonzero on failure. - */ -int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_header *hdr, - const struct flash_area *fap, uint8_t *tmp_buf, - uint32_t tmp_buf_sz, uint8_t *hash_result, - uint8_t *seed, int seed_len); - -/** - * Calculates the size that the compressed image protected TLV section will occupy once the image - * has been decompressed. - * - * @param hdr Image header. - * @param fap Flash area of the slot. - * @param sz Pointer to variable that will be updated with the protected TLV size. - * - * @return 0 on success; nonzero on failure. - */ -int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_area *fap_src, - uint32_t *sz); - -#ifdef __cplusplus -} -#endif - -#endif /* H_DECOMPRESSION_ */ From e3265fea869f7580b7b5546470c2a475cc4ce31e Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 037/149] Revert "[nrf noup] boot: Improve bootloader request handling" This reverts commit bb72623b1dfbebf95443562fe16baa4c73cf2121. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/bootutil_public.c | 17 ++++------------- boot/zephyr/Kconfig | 11 ----------- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index ea027f8bf..c7f3c5125 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -510,8 +510,7 @@ boot_write_copy_done(const struct flash_area *fap) #ifdef SEND_BOOT_REQUEST static int -send_boot_request(uint8_t magic, uint8_t image_ok, bool confirm, int image_id, - uint32_t slot_id) +send_boot_request(uint8_t magic, bool confirm, int image_id, uint32_t slot_id) { int rc = BOOT_EBADIMAGE; @@ -519,16 +518,10 @@ send_boot_request(uint8_t magic, uint8_t image_ok, bool confirm, int image_id, if ((magic == BOOT_MAGIC_GOOD) || (magic == BOOT_MAGIC_UNSET)) { if (confirm) { BOOT_LOG_DBG("Confirm image: %d, %d", image_id, slot_id); - if ((image_ok != BOOT_FLAG_SET) || (magic != BOOT_MAGIC_GOOD)) { - rc = boot_request_confirm_slot(image_id, slot_id); - } else { - rc = 0; - } -#ifdef CONFIG_NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE + rc = boot_request_confirm_slot(image_id, slot_id); } else { BOOT_LOG_DBG("Set image preference: %d, %d", image_id, slot_id); rc = boot_request_set_preferred_slot(image_id, slot_id); -#endif /* CONFIG_NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE */ } if (rc != 0) { rc = BOOT_EBADIMAGE; @@ -604,8 +597,7 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) image_id = flash_area_to_image_slot(fa, &slot_id); #ifdef SEND_BOOT_REQUEST - rc = send_boot_request(slot_state.magic, slot_state.image_ok, confirm, - image_id, slot_id); + rc = send_boot_request(slot_state.magic, confirm, image_id, slot_id); if ((rc != 0) || active) { return rc; } @@ -694,8 +686,7 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) #ifdef SEND_BOOT_REQUEST image_id = flash_area_to_image_slot(fa, &slot_id); - rc = send_boot_request(slot_state.magic, slot_state.image_ok, confirm, - image_id, slot_id); + rc = send_boot_request(slot_state.magic, confirm, image_id, slot_id); if ((rc != 0) || active) { return rc; } diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 1d74880fb..2ceafc4ba 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1361,15 +1361,4 @@ config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS Time between image validation attempts, in milliseconds. Allows for recovery from transient bit flips or similar situations. -config NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE - bool "Set boot preference if a slot is marked for test" - help - This option allows to verify boot preference requests through issuing - the image test. - Using this option is not recommended in production systems, because - it will boot any newly transferred image, even if it has a lower - version than the current one. - The rollback protection (using security counters) will still be - effective. - source "Kconfig.zephyr" From 1eb02451cf9b9dc3144e43d0e112842fc77e5f67 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 038/149] Revert "[nrf noup] bootloader: Add bootloader requests" This reverts commit cc558efbb2e06ef1a195a3a0e3e83ecd182c8946. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/include/bootutil/boot_request.h | 105 ------ boot/bootutil/src/bootutil_public.c | 84 +---- boot/bootutil/zephyr/CMakeLists.txt | 5 - .../zephyr/src/boot_request_retention.c | 346 ------------------ boot/zephyr/Kconfig | 4 - boot/zephyr/Kconfig.firmware_loader | 6 - boot/zephyr/Kconfig.serial_recovery | 6 - boot/zephyr/firmware_loader.c | 9 - boot/zephyr/main.c | 53 --- 9 files changed, 5 insertions(+), 613 deletions(-) delete mode 100644 boot/bootutil/include/bootutil/boot_request.h delete mode 100644 boot/bootutil/zephyr/src/boot_request_retention.c diff --git a/boot/bootutil/include/bootutil/boot_request.h b/boot/bootutil/include/bootutil/boot_request.h deleted file mode 100644 index b1e8f891e..000000000 --- a/boot/bootutil/include/bootutil/boot_request.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * Copyright (c) 2025 Nordic Semiconductor ASA - */ - -#ifndef __BOOT_REQUEST_H__ -#define __BOOT_REQUEST_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -/** Special value, indicating that there is no preferred slot. */ -#define BOOT_REQUEST_NO_PREFERRED_SLOT UINT32_MAX - -/** - * @brief Request a bootloader to confirm the specified slot of an image. - * - * @param[in] image Image number. - * @param[in] slot Slot number. - * - * @return 0 if requested, negative error code otherwise. - */ -int boot_request_confirm_slot(uint8_t image, uint32_t slot); - -/** - * @brief Request a bootloader to boot the specified slot of an image. - * - * @param[in] image Image number. - * @param[in] slot Slot number. - * - * @return 0 if requested, negative error code otherwise. - */ -int boot_request_set_preferred_slot(uint8_t image, uint32_t slot); - -/** - * @brief Request a bootloader to boot recovery image. - * - * @return 0 if requested, negative error code otherwise. - */ -int boot_request_enter_recovery(void); - -/** - * @brief Request a bootloader to boot firmware loader image. - * - * @return 0 if requested, negative error code otherwise. - */ -int boot_request_enter_firmware_loader(void); - -/** - * @brief Check if there is a request to confirm the specified slot of an image. - * - * @param[in] image Image number. - * @param[in] slot Slot number. - * - * @return true if requested, false otherwise. - */ -bool boot_request_check_confirmed_slot(uint8_t image, uint32_t slot); - -/** - * @brief Find if there is a request to boot certain slot of the specified image. - * - * @param[in] image Image number. - * - * @return slot number if requested, BOOT_REQUEST_NO_PREFERRED_SLOT otherwise. - */ -uint32_t boot_request_get_preferred_slot(uint8_t image); - -/** - * @brief Check if there is a request to boot recovery image. - * - * @return true if requested, false otherwise. - */ -bool boot_request_detect_recovery(void); - -/** - * @brief Check if there is a request to boot firmware loader image. - * - * @return true if requested, false otherwise. - */ -bool boot_request_detect_firmware_loader(void); - -/** - * @brief Initialize boot requests module. - * - * @return 0 if successful, negative error code otherwise. - */ -int boot_request_init(void); - -/** - * @brief Clear/drop all requests. - * - * @return 0 if successful, negative error code otherwise. - */ -int boot_request_clear(void); - -#ifdef __cplusplus -} -#endif - -#endif /* __BOOT_REQUEST_H__ */ diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index c7f3c5125..5071b561a 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -51,11 +51,6 @@ #include "bootutil_priv.h" #include "bootutil_misc.h" -#if defined(CONFIG_NRF_MCUBOOT_BOOT_REQUEST) && !defined(CONFIG_MCUBOOT) -#include -#define SEND_BOOT_REQUEST -#endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST && !CONFIG_MCUBOOT */ - #ifdef CONFIG_MCUBOOT BOOT_LOG_MODULE_DECLARE(mcuboot); #else @@ -508,47 +503,16 @@ boot_write_copy_done(const struct flash_area *fap) return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET); } -#ifdef SEND_BOOT_REQUEST -static int -send_boot_request(uint8_t magic, bool confirm, int image_id, uint32_t slot_id) -{ - int rc = BOOT_EBADIMAGE; - - /* Handle write-protected active image. */ - if ((magic == BOOT_MAGIC_GOOD) || (magic == BOOT_MAGIC_UNSET)) { - if (confirm) { - BOOT_LOG_DBG("Confirm image: %d, %d", image_id, slot_id); - rc = boot_request_confirm_slot(image_id, slot_id); - } else { - BOOT_LOG_DBG("Set image preference: %d, %d", image_id, slot_id); - rc = boot_request_set_preferred_slot(image_id, slot_id); - } - if (rc != 0) { - rc = BOOT_EBADIMAGE; - } - } - - return rc; -} -#endif /* SEND_BOOT_REQUEST */ +#ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP -#if defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) -static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) +static int flash_area_to_image(const struct flash_area *fa) { - int id = flash_area_get_id(fa); #if BOOT_IMAGE_NUMBER > 1 uint8_t i = 0; + int id = flash_area_get_id(fa); while (i < BOOT_IMAGE_NUMBER) { - if (FLASH_AREA_IMAGE_PRIMARY(i) == id) { - if (slot != NULL) { - *slot = 0; - } - return i; - } else if (FLASH_AREA_IMAGE_SECONDARY(i) == id) { - if (slot != NULL) { - *slot = 1; - } + if (FLASH_AREA_IMAGE_PRIMARY(i) == id || (FLASH_AREA_IMAGE_SECONDARY(i) == id)) { return i; } @@ -559,31 +523,15 @@ static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) *slot = UINT32_MAX; #else (void)fa; - if (slot != NULL) { - if (FLASH_AREA_IMAGE_PRIMARY(0) == id) { - *slot = 0; - } else if (FLASH_AREA_IMAGE_SECONDARY(0) == id) { - *slot = 1; - } else { - *slot = UINT32_MAX; - } - } #endif return 0; } -#endif /* defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) */ -#ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP int boot_set_next(const struct flash_area *fa, bool active, bool confirm) { struct boot_swap_state slot_state; int rc; - int image_id; - uint32_t slot_id; - - BOOT_LOG_DBG("boot_set_next: fa %p active == %d, confirm == %d", - fa, (int)active, (int)confirm); if (active) { confirm = true; @@ -594,15 +542,6 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) return rc; } - image_id = flash_area_to_image_slot(fa, &slot_id); - -#ifdef SEND_BOOT_REQUEST - rc = send_boot_request(slot_state.magic, confirm, image_id, slot_id); - if ((rc != 0) || active) { - return rc; - } -#endif - switch (slot_state.magic) { case BOOT_MAGIC_GOOD: /* If non-active then swap already scheduled, else confirm needed.*/ @@ -633,7 +572,7 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) } else { swap_type = BOOT_SWAP_TYPE_TEST; } - rc = boot_write_swap_info(fa, swap_type, image_id); + rc = boot_write_swap_info(fa, swap_type, flash_area_to_image(fa)); } } break; @@ -661,10 +600,6 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) { struct boot_swap_state slot_state; int rc; -#ifdef SEND_BOOT_REQUEST - int image_id; - uint32_t slot_id; -#endif BOOT_LOG_DBG("boot_set_next: fa %p active == %d, confirm == %d", fa, (int)active, (int)confirm); @@ -683,15 +618,6 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) return rc; } -#ifdef SEND_BOOT_REQUEST - image_id = flash_area_to_image_slot(fa, &slot_id); - - rc = send_boot_request(slot_state.magic, confirm, image_id, slot_id); - if ((rc != 0) || active) { - return rc; - } -#endif - switch (slot_state.magic) { case BOOT_MAGIC_UNSET: /* Magic is needed for MCUboot to even consider booting an image */ diff --git a/boot/bootutil/zephyr/CMakeLists.txt b/boot/bootutil/zephyr/CMakeLists.txt index 111cf4f1d..44f78f395 100644 --- a/boot/bootutil/zephyr/CMakeLists.txt +++ b/boot/bootutil/zephyr/CMakeLists.txt @@ -16,11 +16,6 @@ zephyr_library_named(mcuboot_util) zephyr_library_sources( ../src/bootutil_public.c ) -if(CONFIG_NRF_MCUBOOT_BOOT_REQUEST) - zephyr_library_sources_ifdef(CONFIG_NRF_MCUBOOT_BOOT_REQUEST_IMPL_RETENTION - src/boot_request_retention.c - ) -endif() # Sensitivity to the TEST_BOOT_IMAGE_ACCESS_HOOKS define is implemented for # allowing the test-build with the hooks feature enabled. diff --git a/boot/bootutil/zephyr/src/boot_request_retention.c b/boot/bootutil/zephyr/src/boot_request_retention.c deleted file mode 100644 index 023f5af5e..000000000 --- a/boot/bootutil/zephyr/src/boot_request_retention.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * Copyright (c) 2025 Nordic Semiconductor ASA - */ -#include - -#include "bootutil/bootutil_log.h" -#include - -/** Special value of image number, indicating a request to the bootloader. */ -#define BOOT_REQUEST_IMG_BOOTLOADER 0xFF - -/** Additional memory used by the retention subsystem (2B - prefix, 4B - CRC).*/ -#define BOOT_REQUEST_ENTRY_METADATA_SIZE (2 + 4) - -MCUBOOT_LOG_MODULE_REGISTER(bootloader_request); - -static const struct device *bootloader_request_dev = - DEVICE_DT_GET(DT_CHOSEN(nrf_bootloader_request)); - -enum boot_request_type { - /** Invalid request. */ - BOOT_REQUEST_INVALID = 0, - - /** Request a change in the bootloader boot mode. - * - * @details Use @p boot_request_mode as argument. - * @p BOOT_REQUEST_IMG_BOOTLOADER as image number. - * - * @note Used to trigger recovery through i.e. retention sybsystem. - */ - BOOT_REQUEST_BOOT_MODE = 1, - - /** Select the preferred image to be selected during boot or update. - * - * @details Use @p boot_request_slot_t as argument. - * - * @note Used in the Direct XIP mode. - */ - BOOT_REQUEST_IMG_PREFERENCE = 2, - - /** Request a confirmation of an image. - * - * @details Use @p boot_request_slot_t as argument. - * - * @note Used if the code cannot modify the image trailer directly. - */ - BOOT_REQUEST_IMG_CONFIRM = 3, -}; - -/* Entries inside the boot request shared memory. */ -enum boot_request_entry { - BOOT_REQUEST_ENTRY_BOOT_MODE = 0, - BOOT_REQUEST_ENTRY_IMAGE_0_PREFERENCE = 1, - BOOT_REQUEST_ENTRY_IMAGE_0_CONFIRM = 2, - BOOT_REQUEST_ENTRY_IMAGE_1_PREFERENCE = 3, - BOOT_REQUEST_ENTRY_IMAGE_1_CONFIRM = 4, - BOOT_REQUEST_ENTRY_MAX = 5, -}; - -/* Assert that all requests will fit within the retention area. */ -BUILD_ASSERT((BOOT_REQUEST_ENTRY_METADATA_SIZE + BOOT_REQUEST_ENTRY_MAX * sizeof(uint8_t)) < - DT_REG_SIZE_BY_IDX(DT_CHOSEN(nrf_bootloader_request), 0), - "nrf,bootloader-request area is too small for bootloader request struct"); - -enum boot_request_slot { - /** Unsupported value. */ - BOOT_REQUEST_SLOT_INVALID = 0, - /** Primary slot. */ - BOOT_REQUEST_SLOT_PRIMARY = 1, - /** Secondary slot. */ - BOOT_REQUEST_SLOT_SECONDARY = 2, -}; - -/** Alias type for the image and number. */ -typedef uint8_t boot_request_slot_t; - -enum boot_request_mode { - /** Execute a regular boot logic. */ - BOOT_REQUEST_MODE_REGULAR = 0, - /** Execute the recovery boot logic. */ - BOOT_REQUEST_MODE_RECOVERY = 1, - /** Execute the firmware loader logic. */ - BOOT_REQUEST_MODE_FIRMWARE_LOADER = 2, - /** Unsupported value. */ - BOOT_REQUEST_MODE_INVALID = 0xFF, -}; - -/** Alias type for the image number. */ -typedef uint8_t boot_request_img_t; - -/** - * @brief Find an entry for a given request. - * - * @param[in] type Type of request. - * @param[in] image Image number. Use @p BOOT_REQUEST_IMG_BOOTLOADER for generic requests. - * @param[out] entry Entry to use. - * - * @return 0 on success; nonzero on failure. - */ -static int boot_request_entry_find(enum boot_request_type type, boot_request_img_t image, - size_t *entry) -{ - if (entry == NULL) { - return -EINVAL; - } - - switch (type) { - case BOOT_REQUEST_BOOT_MODE: - *entry = BOOT_REQUEST_ENTRY_BOOT_MODE; - break; - case BOOT_REQUEST_IMG_PREFERENCE: - switch (image) { - case 0: - *entry = BOOT_REQUEST_ENTRY_IMAGE_0_PREFERENCE; - break; - case 1: - *entry = BOOT_REQUEST_ENTRY_IMAGE_1_PREFERENCE; - break; - default: - return -EINVAL; - } - break; - case BOOT_REQUEST_IMG_CONFIRM: - switch (image) { - case 0: - *entry = BOOT_REQUEST_ENTRY_IMAGE_0_CONFIRM; - break; - case 1: - *entry = BOOT_REQUEST_ENTRY_IMAGE_1_CONFIRM; - break; - default: - return -EINVAL; - } - break; - default: - return -EINVAL; - } - - return 0; -} - -int boot_request_init(void) -{ - if (!device_is_ready(bootloader_request_dev)) { - return -EIO; - } - - return 0; -} - -int boot_request_clear(void) -{ - return retention_clear(bootloader_request_dev); -} - -int boot_request_confirm_slot(uint8_t image, uint32_t slot) -{ - uint8_t value = BOOT_REQUEST_SLOT_INVALID; - size_t req_entry; - int ret; - - ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry); - if (ret != 0) { - return ret; - } - - switch (slot) { - case 0: - value = BOOT_REQUEST_SLOT_PRIMARY; - break; - case 1: - value = BOOT_REQUEST_SLOT_SECONDARY; - break; - default: - return -EINVAL; - } - - return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, - sizeof(value)); -} - -bool boot_request_check_confirmed_slot(uint8_t image, uint32_t slot) -{ - uint8_t value = BOOT_REQUEST_SLOT_INVALID; - size_t req_entry; - int ret; - - ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry); - if (ret != 0) { - return false; - } - - ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, - sizeof(value)); - if (ret != 0) { - return false; - } - - switch (value) { - case BOOT_REQUEST_SLOT_PRIMARY: - return (slot == 0); - case BOOT_REQUEST_SLOT_SECONDARY: - return (slot == 1); - default: - break; - } - - return false; -} - -int boot_request_set_preferred_slot(uint8_t image, uint32_t slot) -{ - uint8_t value = BOOT_REQUEST_SLOT_INVALID; - size_t req_entry; - int ret; - - ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry); - if (ret != 0) { - return ret; - } - - switch (slot) { - case 0: - value = BOOT_REQUEST_SLOT_PRIMARY; - break; - case 1: - value = BOOT_REQUEST_SLOT_SECONDARY; - break; - default: - return -EINVAL; - } - - return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, - sizeof(value)); -} - -#ifdef CONFIG_FIND_NEXT_SLOT_HOOKS -uint32_t boot_request_get_preferred_slot(uint8_t image) -{ - uint8_t value = BOOT_REQUEST_SLOT_INVALID; - size_t req_entry; - int ret; - - ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry); - if (ret != 0) { - return BOOT_REQUEST_NO_PREFERRED_SLOT; - } - - ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, - sizeof(value)); - if (ret != 0) { - return BOOT_REQUEST_NO_PREFERRED_SLOT; - } - - switch (value) { - case BOOT_REQUEST_SLOT_PRIMARY: - return 0; - case BOOT_REQUEST_SLOT_SECONDARY: - return 1; - default: - break; - } - - return BOOT_REQUEST_NO_PREFERRED_SLOT; -} -#endif /* CONFIG_FIND_NEXT_SLOT_HOOKS */ - -int boot_request_enter_recovery(void) -{ - uint8_t value = BOOT_REQUEST_MODE_RECOVERY; - size_t req_entry; - int ret; - - ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, - &req_entry); - if (ret != 0) { - return ret; - } - - return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, - sizeof(value)); -} - -#ifdef CONFIG_NRF_BOOT_SERIAL_BOOT_REQ -bool boot_request_detect_recovery(void) -{ - uint8_t value = BOOT_REQUEST_MODE_INVALID; - size_t req_entry; - int ret; - - ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, - &req_entry); - if (ret != 0) { - return false; - } - - ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, - sizeof(value)); - if ((ret == 0) && (value == BOOT_REQUEST_MODE_RECOVERY)) { - return true; - } - - return false; -} -#endif /* CONFIG_NRF_BOOT_SERIAL_BOOT_REQ */ - -int boot_request_enter_firmware_loader(void) -{ - uint8_t value = BOOT_REQUEST_MODE_FIRMWARE_LOADER; - size_t req_entry; - int ret; - - ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, - &req_entry); - if (ret != 0) { - return ret; - } - - return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, - sizeof(value)); -} - -#ifdef CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ -bool boot_request_detect_firmware_loader(void) -{ - uint8_t value = BOOT_REQUEST_MODE_INVALID; - size_t req_entry; - int ret; - - ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, - &req_entry); - if (ret != 0) { - return false; - } - - ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, - sizeof(value)); - if ((ret == 0) && (value == BOOT_REQUEST_MODE_FIRMWARE_LOADER)) { - return true; - } - - return false; -} -#endif /* CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ */ diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 2ceafc4ba..03812562b 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1322,10 +1322,6 @@ config USB_DEVICE_PRODUCT config MCUBOOT_BOOTUTIL_LIB_OWN_LOG bool -config NRF_MCUBOOT_BOOT_REQUEST - bool - imply FIND_NEXT_SLOT_HOOKS if BOOT_DIRECT_XIP || BOOT_RAM_LOAD - config MCUBOOT_VERIFY_IMG_ADDRESS bool "Verify reset address of image in secondary slot" depends on UPDATEABLE_IMAGE_NUMBER > 1 diff --git a/boot/zephyr/Kconfig.firmware_loader b/boot/zephyr/Kconfig.firmware_loader index 376dc06f7..036da98eb 100644 --- a/boot/zephyr/Kconfig.firmware_loader +++ b/boot/zephyr/Kconfig.firmware_loader @@ -42,12 +42,6 @@ config BOOT_FIRMWARE_LOADER_PIN_RESET Checks if the module reset was caused by the reset pin and will remain in bootloader firmware loader mode if it was. -config NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ - bool "Check boot mode via bootloader request" - depends on NRF_MCUBOOT_BOOT_REQUEST - help - Allows for entering firmware loader mode by using bootloader rquests. - endmenu endif diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery index c57e48197..0bffe6131 100644 --- a/boot/zephyr/Kconfig.serial_recovery +++ b/boot/zephyr/Kconfig.serial_recovery @@ -192,12 +192,6 @@ config BOOT_SERIAL_PIN_RESET Checks if the module reset was caused by the reset pin and will remain in bootloader serial recovery mode if it was. -config NRF_BOOT_SERIAL_BOOT_REQ - bool "Check boot mode via bootloader request subsystem" - depends on NRF_MCUBOOT_BOOT_REQUEST - help - Allows for entering serial recovery mode by using bootloader requests. - endmenu config BOOT_SERIAL_IMG_GRP_HASH diff --git a/boot/zephyr/firmware_loader.c b/boot/zephyr/firmware_loader.c index 217336755..18070bc25 100644 --- a/boot/zephyr/firmware_loader.c +++ b/boot/zephyr/firmware_loader.c @@ -17,9 +17,6 @@ #include "io/io.h" #include "mcuboot_config/mcuboot_config.h" -#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST -#include -#endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST */ BOOT_LOG_MODULE_DECLARE(mcuboot); @@ -186,12 +183,6 @@ boot_go(struct boot_rsp *rsp) } #endif -#ifdef CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ - if (boot_request_detect_firmware_loader()) { - boot_firmware_loader = true; - } -#endif - /* Check if firmware loader button is pressed. TODO: check all entrance methods */ if (boot_firmware_loader == true) { FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp); diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index cad0ab75f..a0f9ffa4d 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -47,12 +47,6 @@ #include "bootutil/fault_injection_hardening.h" #include "bootutil/mcuboot_status.h" #include "flash_map_backend/flash_map_backend.h" -#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST -#include - -/** Number of image slots. */ -#define BOOT_REQUEST_NUM_SLOTS 2 -#endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST */ #if defined(CONFIG_MCUBOOT_UUID_VID) || defined(CONFIG_MCUBOOT_UUID_CID) #include "bootutil/mcuboot_uuid.h" @@ -615,37 +609,6 @@ static void boot_serial_enter() } #endif -static int boot_prevalidate(void) -{ -#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST - uint8_t image_index; - uint32_t slot; - uint32_t area_id; - const struct flash_area *fap; - int rc = boot_request_init(); - - if (rc != 0) { - return rc; - } - - for (image_index = 0; image_index < BOOT_IMAGE_NUMBER; ++image_index) { - for (slot = 0; slot < BOOT_REQUEST_NUM_SLOTS; slot++) { - if (boot_request_check_confirmed_slot(image_index, slot)) { - BOOT_LOG_DBG("Confirm image: %d slot: %d due to bootloader request.", - image_index, slot); - - area_id = flash_area_id_from_multi_image_slot(image_index, slot); - rc = flash_area_open(area_id, &fap); - if (rc == 0) { - rc = boot_set_next(fap, true, true); - } - } - } - } -#endif - return 0; -} - int main(void) { struct boot_rsp rsp; @@ -685,11 +648,6 @@ int main(void) } #endif /* CONFIG_MCUBOOT_UUID_VID || CONFIG_MCUBOOT_UUID_CID */ - rc = boot_prevalidate(); - if (rc) { - BOOT_LOG_ERR("Failed to prevalidate the state: %d", rc); - } - #ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO BOOT_LOG_DBG("Checking GPIO for serial recovery"); if (io_detect_pin() && @@ -705,13 +663,6 @@ int main(void) } #endif -#ifdef CONFIG_NRF_BOOT_SERIAL_BOOT_REQ - if (boot_request_detect_recovery()) { - BOOT_LOG_DBG("Staying in serial recovery"); - boot_serial_enter(); - } -#endif - #if defined(CONFIG_BOOT_USB_DFU_GPIO) BOOT_LOG_DBG("Checking GPIO for USB DFU request"); if (io_detect_pin()) { @@ -772,10 +723,6 @@ int main(void) } BOOT_LOG_DBG("Left boot_go with success == %d", FIH_EQ(fih_rc, FIH_SUCCESS) ? 1 : 0); -#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST - (void)boot_request_clear(); -#endif - #ifdef CONFIG_BOOT_SERIAL_BOOT_MODE if (io_detect_boot_mode()) { /* Boot mode to stay in bootloader, clear status and enter serial From 90f1cccfbf4e8649060386a9b4472d63feea92d1 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 039/149] Revert "[nrf noup] boot: zephyr: Disable self RWX" This reverts commit 211da1bf19b4dc5b8078ffbc143f02caca88bb9f. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/Kconfig | 7 --- boot/zephyr/main.c | 140 +++++++++++++------------------------------- 2 files changed, 42 insertions(+), 105 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 03812562b..0804c5c76 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -436,13 +436,6 @@ config MCUBOOT_CLEANUP_RAM help Sets contents of memory to 0 before jumping to application. -config NCS_MCUBOOT_DISABLE_SELF_RWX - bool "Disable read and execution on self NVM" - depends on (SOC_NRF54L15_CPUAPP || SOC_NRF54L10_CPUAPP || SOC_NRF54L05_CPUAPP) && !FPROTECT - help - Sets RRAMC's region no.4 protection before jumping to application. - It disables reads writes and execution memory area which holds MCUBOOT. - config MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP bool "Infinite loop after RAM cleanup" depends on MCUBOOT_CLEANUP_RAM diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index a0f9ffa4d..bdc264d94 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -153,25 +153,6 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #include #endif -#include -#define CLEANUP_RAM_GAP_START ((int)__ramfunc_region_start) -#define CLEANUP_RAM_GAP_SIZE ((int) (__ramfunc_end - __ramfunc_region_start)) - -#if defined(CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX) -/* Disabling R_X has to be done while running from RAM for obvious reasons. - * Moreover as a last step before jumping to application it must work even after - * RAM has been cleared, therefore these operations are performed while executing from RAM. - * RAM cleanup ommits portion of the memory where code lives. - */ -#include - -#define RRAMC_REGION_RWX_LSB 0 -#define RRAMC_REGION_RWX_WIDTH 3 -#define RRAMC_REGION_TO_LOCK_ADDR NRF_RRAMC->REGION[4].CONFIG -#define RRAMC_REGION_TO_LOCK_ADDR_H (((uint32_t)(&(RRAMC_REGION_TO_LOCK_ADDR))) >> 16) -#define RRAMC_REGION_TO_LOCK_ADDR_L (((uint32_t)(&(RRAMC_REGION_TO_LOCK_ADDR))) & 0x0000fffful) -#endif /* CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX */ - BOOT_LOG_MODULE_REGISTER(mcuboot); void os_heap_init(void); @@ -198,84 +179,6 @@ struct arm_vector_table { #endif }; -static void __ramfunc jump_in(uint32_t reset) -{ - __asm__ volatile ( - /* reset -> r0 */ - " mov r0, %0\n" -#ifdef CONFIG_MCUBOOT_CLEANUP_RAM - /* Base to write -> r1 */ - " mov r1, %1\n" - /* Size to write -> r2 */ - " mov r2, %2\n" - /* Value to write -> r3 */ - " movw r3, %5\n" - /* gap start */ - " mov r4, %3\n" - /* gap size */ - " mov r5, %4\n" - "clear:\n" - " subs r6, r4, r1\n" - " cbnz r6, skip_gap\n" - " add r1, r5\n" - "skip_gap:\n" - " str r3, [r1]\n" - " add r1, r1, #1\n" - " sub r2, r2, #1\n" - " cbz r2, clear_end\n" - " b clear\n" - "clear_end:\n" - " dsb\n" -#ifdef CONFIG_MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP - " b clear_end\n" -#endif /* CONFIG_MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP */ -#endif /* CONFIG_MCUBOOT_CLEANUP_RAM */ - -#ifdef CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX - ".thumb_func\n" - "region_disable_rwx:\n" - " movw r1, %6\n" - " movt r1, %7\n" - " ldr r2, [r1]\n" - /* Size of the region should be set at this point - * by NSIB's DISABLE_NEXT_W. - * If not, set it according partition size. - */ - " ands r4, r2, %12\n" - " cbnz r4, clear_rwx\n" - " movt r2, %8\n" - "clear_rwx:\n" - " bfc r2, %9, %10\n" - /* Disallow further modifications */ - " orr r2, %11\n" - " str r2, [r1]\n" - " dsb\n" - /* Next assembly line is important for current function */ - - #endif /* CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX */ - - /* Jump to reset vector of an app */ - " bx r0\n" - : - : "r" (reset), - "r" (CONFIG_SRAM_BASE_ADDRESS), - "i" (CONFIG_SRAM_SIZE * 1024), - "r" (CLEANUP_RAM_GAP_START), - "r" (CLEANUP_RAM_GAP_SIZE), - "i" (0) -#ifdef CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX - , "i" (RRAMC_REGION_TO_LOCK_ADDR_L), - "i" (RRAMC_REGION_TO_LOCK_ADDR_H), - "i" (CONFIG_PM_PARTITION_SIZE_B0_IMAGE / 1024), - "i" (RRAMC_REGION_RWX_LSB), - "i" (RRAMC_REGION_RWX_WIDTH), - "i" (RRAMC_REGION_CONFIG_LOCK_Msk), - "i" (RRAMC_REGION_CONFIG_SIZE_Msk) -#endif /* CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX */ - : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory" - ); -} - static void do_boot(struct boot_rsp *rsp) { /* vt is static as it shall not land on the stack, @@ -410,7 +313,48 @@ static void do_boot(struct boot_rsp *rsp) #endif /* CONFIG_CPU_CORTEX_M */ #endif - jump_in(vt->reset); +#if CONFIG_MCUBOOT_CLEANUP_RAM + __asm__ volatile ( + /* vt->reset -> r0 */ + " mov r0, %0\n" + /* base to write -> r1 */ + " mov r1, %1\n" + /* size to write -> r2 */ + " mov r2, %2\n" + /* value to write -> r3 */ + " mov r3, %3\n" + "clear:\n" + " str r3, [r1]\n" + " add r1, r1, #4\n" + " sub r2, r2, #4\n" + " cbz r2, out\n" + " b clear\n" + "out:\n" + " dsb\n" +#if CONFIG_MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP + " b out\n" +#endif /*CONFIG_MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP */ + /* jump to reset vector of an app */ + " bx r0\n" + : + : "r" (vt->reset), "i" (CONFIG_SRAM_BASE_ADDRESS), + "i" (CONFIG_SRAM_SIZE * 1024), "i" (0) + : "r0", "r1", "r2", "r3", "memory" + ); +#else + +#ifdef CONFIG_CPU_CORTEX_M + ((void (*)(void))vt->reset)(); +#else + /* Some ARM CPUs like the Cortex-R5 can run in thumb mode but reset into ARM + * mode (depending on a CPU signal configurations). To do the switch into ARM + * mode, if needed, an explicit branch with exchange instruction set + * instruction is needed + */ + __asm__("bx %0\n" : : "r" (&vt->reset)); +#endif + +#endif } #elif defined(CONFIG_XTENSA) || defined(CONFIG_RISCV) From d74a7c8b362156cf6dc178bf3cc5e3421876b743 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 040/149] Revert "[nrf noup] boot/zephyr/nrf_cleanup: fix index error" This reverts commit e2bd60731db5b7e07bebc0297c8bf71dfbd005f8. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/nrf_cleanup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index e261d1914..39dfcbc41 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -131,7 +131,7 @@ void nrf_cleanup_peripheral(void) for (int j = 0; j < 4; j++) { if (pin[j] != NRF_UARTE_PSEL_DISCONNECTED) { - nrfy_gpio_cfg_default(pin[j]); + nrfy_gpio_cfg_default(pin[i]); } } #endif From d4dac35b7396e59dc14771e82ae8f80070cdb3f1 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 041/149] Revert "[nrf noup] boot: Use NCS_ prefix for sdk-nrf specific Kconfigs" This reverts commit 9126c5a1865fc1dea050859bc111cc4731613846. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 38 +++++++++++++++++++------------------- boot/zephyr/Kconfig | 6 +++--- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 6ed19951c..d0ed55d7b 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -52,9 +52,9 @@ #ifdef __ZEPHYR__ #include -#if defined(CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) +#if defined(CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) #include -#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ +#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ #endif #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) @@ -708,10 +708,10 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, } #endif - for (int i = 1; i <= CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT; i++ ) { -#if CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 - BOOT_LOG_DBG("Image validation attempt %d/%d", i, CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT); -#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ + for (int i = 1; i <= CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT; i++ ) { +#if CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + BOOT_LOG_DBG("Image validation attempt %d/%d", i, CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT); +#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ #if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_SERIAL_RECOVERY) FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, @@ -722,25 +722,25 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, #endif if (FIH_EQ(fih_rc, FIH_SUCCESS)) { -#if CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 - BOOT_LOG_DBG("Image validation attempt %d/%d success", i, CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT); -#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ +#if CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + BOOT_LOG_DBG("Image validation attempt %d/%d success", i, CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT); +#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ break; } else { -#if CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 +#if CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 BOOT_LOG_WRN("Image validation attempt %d/%d failure: %d", i, - CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT, fih_rc); -#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ + CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT, fih_rc); +#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ - if (i < CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT) { -#if defined(CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) -#if CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + if (i < CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT) { +#if defined(CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) +#if CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 BOOT_LOG_DBG("Waiting %d ms before next attempt", - CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS); -#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ - k_busy_wait(CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS * 1000); -#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ + CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS); +#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ + k_busy_wait(CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS * 1000); +#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ } } } diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 0804c5c76..4bb54ac91 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1333,7 +1333,7 @@ config MCUBOOT_VERIFY_IMG_ADDRESS also be useful when BOOT_DIRECT_XIP is enabled, to ensure that the image linked at the correct address is loaded. -config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT +config NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT int "Number of image validation attempts" default 1 help @@ -1342,9 +1342,9 @@ config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT This can prevent erasing an image when initial validation fails. Wait time is controlled by MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS. -config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS +config NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS int "Time between image validation attempts" - depends on NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + depends on NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 default 5000 help Time between image validation attempts, in milliseconds. From fce1fec2ddd09c14171bdf232c1ff80b759793ef Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 042/149] Revert "[nrf noup] boot: Add retry for image verification" This reverts commit d29c5a5bee2f14560e0d5f2be9f2045ef206aaa4. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 40 ++------------------------------------ boot/zephyr/Kconfig | 17 ---------------- 2 files changed, 2 insertions(+), 55 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index d0ed55d7b..e182707e1 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -52,9 +52,6 @@ #ifdef __ZEPHYR__ #include -#if defined(CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) -#include -#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ #endif #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) @@ -708,42 +705,9 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, } #endif - for (int i = 1; i <= CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT; i++ ) { -#if CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 - BOOT_LOG_DBG("Image validation attempt %d/%d", i, CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT); -#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ + FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, + NULL, 0, NULL); -#if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_SERIAL_RECOVERY) - FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, - NULL, 0, NULL, 0); -#else - FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, - NULL, 0, NULL); -#endif - - if (FIH_EQ(fih_rc, FIH_SUCCESS)) { -#if CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 - BOOT_LOG_DBG("Image validation attempt %d/%d success", i, CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT); -#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ - break; - } else { -#if CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 - BOOT_LOG_WRN("Image validation attempt %d/%d failure: %d", - i, - CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT, fih_rc); -#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ - - if (i < CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT) { -#if defined(CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) -#if CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 - BOOT_LOG_DBG("Waiting %d ms before next attempt", - CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS); -#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ - k_busy_wait(CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS * 1000); -#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ - } - } - } FIH_RET(fih_rc); } diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 4bb54ac91..9f0399fd3 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1333,21 +1333,4 @@ config MCUBOOT_VERIFY_IMG_ADDRESS also be useful when BOOT_DIRECT_XIP is enabled, to ensure that the image linked at the correct address is loaded. -config NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT - int "Number of image validation attempts" - default 1 - help - Number of image validation attempts performed before an image is considered invalid. - A wait is done between each attempt to allow for recovery from a temporary disruption. - This can prevent erasing an image when initial validation fails. - Wait time is controlled by MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS. - -config NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS - int "Time between image validation attempts" - depends on NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 - default 5000 - help - Time between image validation attempts, in milliseconds. - Allows for recovery from transient bit flips or similar situations. - source "Kconfig.zephyr" From 3ba92038eafa8cf1e3fcbbc0bf16bba29c28653e Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 043/149] Revert "[nrf noup] nrf_cleanup: nRF54h: fix missing peripheral cleanup" This reverts commit 4509cebd992d40f7636a518cc7af3e67562b31b0. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/nrf_cleanup.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index 39dfcbc41..f90a46af1 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#if defined(CONFIG_NRFX_CLOCK) +#if !defined(CONFIG_SOC_SERIES_NRF54HX) #include #endif #include @@ -13,9 +13,6 @@ #if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) #include #endif -#if defined(CONFIG_NRF_GRTC_TIMER) - #include -#endif #if defined(NRF_PPI) #include #endif @@ -51,13 +48,6 @@ static inline void nrf_cleanup_rtc(NRF_RTC_Type * rtc_reg) } #endif -#if defined(CONFIG_NRF_GRTC_TIMER) -static inline void nrf_cleanup_grtc(void) -{ - nrfx_grtc_uninit(); -} -#endif - #if defined(NRF_UARTE_CLEANUP) static NRF_UARTE_Type *nrf_uarte_to_clean[] = { #if defined(NRF_UARTE0) @@ -72,13 +62,10 @@ static NRF_UARTE_Type *nrf_uarte_to_clean[] = { #if defined(NRF_UARTE30) NRF_UARTE30, #endif -#if defined(NRF_UARTE136) - NRF_UARTE136, -#endif }; #endif -#if defined(CONFIG_NRFX_CLOCK) +#if !defined(CONFIG_SOC_SERIES_NRF54HX) static void nrf_cleanup_clock(void) { nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); @@ -97,10 +84,6 @@ void nrf_cleanup_peripheral(void) nrf_cleanup_rtc(NRF_RTC2); #endif -#if defined(CONFIG_NRF_GRTC_TIMER) - nrf_cleanup_grtc(); -#endif - #if defined(NRF_UARTE_CLEANUP) for (int i = 0; i < sizeof(nrf_uarte_to_clean) / sizeof(nrf_uarte_to_clean[0]); ++i) { NRF_UARTE_Type *current = nrf_uarte_to_clean[i]; @@ -154,7 +137,7 @@ void nrf_cleanup_peripheral(void) nrf_dppi_channels_disable_all(NRF_DPPIC); #endif -#if defined(CONFIG_NRFX_CLOCK) +#if !defined(CONFIG_SOC_SERIES_NRF54HX) nrf_cleanup_clock(); #endif } From 7a66e56390a88b591db30e10f1e38d9a937695ef Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 044/149] Revert "[nrf noup] nrf_cleanup: nRF54l: disable cleanup on UARTE pins" This reverts commit 5b586d4920f22e1eb28e661694a7d322e749500d. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/nrf_cleanup.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index f90a46af1..1252334ca 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -97,12 +97,6 @@ void nrf_cleanup_peripheral(void) nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_RXTO); nrfy_uarte_disable(current); -#ifndef CONFIG_SOC_SERIES_NRF54LX - /* Disconnect pins UARTE pins - * causes issues on nRF54l SoCs, - * could be enabled once fix to NCSDK-33039 will be implemented. - */ - uint32_t pin[4]; pin[0] = nrfy_uarte_tx_pin_get(current); @@ -117,7 +111,6 @@ void nrf_cleanup_peripheral(void) nrfy_gpio_cfg_default(pin[i]); } } -#endif #if defined(NRF_DPPIC) /* Clear all SUBSCRIBE configurations. */ From d00acf4ba9e9e43540feac2076ca9ca653ad06ca Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 045/149] Revert "[nrf noup] boot/zephyr/nrf_cleanup: cleanup uarte pins" This reverts commit a9918fab45fb9fd0a0ee705ffbc20037152696f6. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/nrf_cleanup.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index 1252334ca..72c601db3 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -9,7 +9,6 @@ #endif #include #include -#include #if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) #include #endif @@ -97,21 +96,6 @@ void nrf_cleanup_peripheral(void) nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_RXTO); nrfy_uarte_disable(current); - uint32_t pin[4]; - - pin[0] = nrfy_uarte_tx_pin_get(current); - pin[1] = nrfy_uarte_rx_pin_get(current); - pin[2] = nrfy_uarte_rts_pin_get(current); - pin[3] = nrfy_uarte_cts_pin_get(current); - - nrfy_uarte_pins_disconnect(current); - - for (int j = 0; j < 4; j++) { - if (pin[j] != NRF_UARTE_PSEL_DISCONNECTED) { - nrfy_gpio_cfg_default(pin[i]); - } - } - #if defined(NRF_DPPIC) /* Clear all SUBSCRIBE configurations. */ memset((uint8_t *)current + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, From 8bd7a437f99d55728cef542f3f0587a40bad1858 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 046/149] Revert "[nrf noup] boot/zephyr: nrf54h20dk cleanup adaptations" This reverts commit a5e4aeb25130206c786632e593f28a0625c39d4e. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/nrf_cleanup.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index 72c601db3..051705ec9 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -4,9 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#if !defined(CONFIG_SOC_SERIES_NRF54HX) #include -#endif #include #include #if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) @@ -64,12 +62,10 @@ static NRF_UARTE_Type *nrf_uarte_to_clean[] = { }; #endif -#if !defined(CONFIG_SOC_SERIES_NRF54HX) static void nrf_cleanup_clock(void) { nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); } -#endif void nrf_cleanup_peripheral(void) { @@ -113,10 +109,7 @@ void nrf_cleanup_peripheral(void) #if defined(NRF_DPPIC) nrf_dppi_channels_disable_all(NRF_DPPIC); #endif - -#if !defined(CONFIG_SOC_SERIES_NRF54HX) nrf_cleanup_clock(); -#endif } #if USE_PARTITION_MANAGER \ From ea9dbc0f38e0c548db9fcddce26c1945eeb84146 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 047/149] Revert "[nrf noup] partition_manager: Add support for internal flash netcore DFU" This reverts commit 4185e97573e4ab34e501cf8dc7904d09e5c67507. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/pm.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml index eec62473c..ab8f6d1c3 100644 --- a/boot/zephyr/pm.yml +++ b/boot/zephyr/pm.yml @@ -78,17 +78,11 @@ mcuboot_pad: mcuboot_primary_1: region: ram_flash size: CONFIG_NRF53_RAM_FLASH_SIZE -#endif /* CONFIG_NRF53_MCUBOOT_PRIMARY_1_RAM_FLASH */ +#endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ #if (CONFIG_NRF53_MULTI_IMAGE_UPDATE) mcuboot_secondary_1: -#if defined(CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY) region: external_flash -#else - placement: - align: {start: CONFIG_FPROTECT_BLOCK_SIZE} - after: mcuboot_secondary -#endif size: CONFIG_NRF53_RAM_FLASH_SIZE #endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ From 5b3a161bc5d86928bb60430d8455985a4b2684bc Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 048/149] Revert "[nrf noup] boot: zephyr: boards: Disabled NCS boot banner for thingy 53" This reverts commit 19e8300332439b8d71e4aada5b90db4625ae6910. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index bbef18460..d68509786 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -47,7 +47,6 @@ CONFIG_USB_CDC_ACM=y CONFIG_CBPRINTF_NANO=y CONFIG_TIMESLICING=n CONFIG_BOOT_BANNER=n -CONFIG_NCS_BOOT_BANNER=n CONFIG_CONSOLE=n CONFIG_CONSOLE_HANDLER=n CONFIG_UART_CONSOLE=n From fadada8cfaa72b19b227027863919be538c9de6a Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 049/149] Revert "[nrf noup] sysflash: Add missing _FLASH_0_ID definitions" This reverts commit dbbf3fd5ed430df4c573bab4870ad6bbc044c960. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/include/sysflash/pm_sysflash.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h index 0cb16292f..42f25182e 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -84,12 +84,4 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #endif /* CONFIG_SINGLE_APPLICATION_SLOT */ -#ifndef SOC_FLASH_0_ID -#define SOC_FLASH_0_ID 0 -#endif - -#ifndef SPI_FLASH_0_ID -#define SPI_FLASH_0_ID 1 -#endif - #endif /* __PM_SYSFLASH_H__ */ From 96751a2b46005d38d1c0bb4d9d238f6d6073e40d Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 050/149] Revert "[nrf noup] boot: Remove child/parent references" This reverts commit eb8734740049d42334fadafd312347204c60c351. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/swap_priv.h | 2 +- boot/zephyr/pm.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/boot/bootutil/src/swap_priv.h b/boot/bootutil/src/swap_priv.h index 10473a9cc..90e0b3742 100644 --- a/boot/bootutil/src/swap_priv.h +++ b/boot/bootutil/src/swap_priv.h @@ -131,7 +131,7 @@ bool swap_write_block_size_check(struct boot_loader_state *state); int app_max_size(struct boot_loader_state *state); #if defined(PM_S1_ADDRESS) && !defined(MCUBOOT_OVERWRITE_ONLY) && \ -CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 +(CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || defined(LEGACY_CHILD_PARENT_S0_S1_UPDATE_ENABLED)) /** * Performs an NSIB update */ diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml index ab8f6d1c3..13ffc44aa 100644 --- a/boot/zephyr/pm.yml +++ b/boot/zephyr/pm.yml @@ -4,7 +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 77919fbc9024c5397b46ad200ba01f395269018d Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 051/149] Revert "[nrf noup] boot: bootutil: loader: Add s0/s1 checking of MCUboot image" This reverts commit 4aba01c40bc3983d3d341b802b1769670b6f9d43. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 68 -------------------------------------- 1 file changed, 68 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index e182707e1..b9e18873d 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -83,40 +83,6 @@ static bool owner_nsib[BOOT_IMAGE_NUMBER] = {false}; static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0}; #endif -#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \ -defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) -#if !defined(__BOOTSIM__) -/* Used for holding static buffers in multiple functions to work around issues - * in older versions of gcc (e.g. 4.8.4) - */ -struct sector_buffer_t { - boot_sector_t primary[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS]; - boot_sector_t secondary[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS]; -#if MCUBOOT_SWAP_USING_SCRATCH - boot_sector_t scratch[BOOT_MAX_IMG_SECTORS]; -#endif -}; - -#endif -#endif - -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 && defined(MCUBOOT_OVERWRITE_ONLY) && \ - defined(MCUBOOT_DOWNGRADE_PREVENTION) -/* s0/s1 package version of the current MCUboot image */ -static const struct image_version mcuboot_s0_s1_image_version = { - .iv_major = CONFIG_MCUBOOT_MCUBOOT_S0_S1_VERSION_MAJOR, - .iv_minor = CONFIG_MCUBOOT_MCUBOOT_S0_S1_VERSION_MINOR, - .iv_revision = CONFIG_MCUBOOT_MCUBOOT_S0_S1_VERSION_REVISION, - .iv_build_num = CONFIG_MCUBOOT_MCUBOOT_S0_S1_VERSION_BUILD_NUMBER, -}; -#endif - -#if (BOOT_IMAGE_NUMBER > 1) -#define IMAGES_ITER(x) for ((x) = 0; (x) < BOOT_IMAGE_NUMBER; ++(x)) -#else -#define IMAGES_ITER(x) -#endif - /* * This macro allows some control on the allocation of local variables. * When running natively on a target, we don't want to allocated huge @@ -980,45 +946,11 @@ boot_validate_slot(struct boot_loader_state *state, int slot, rc = boot_version_cmp( &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); - -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 - if (rc >= 0 && BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { - /* Also check the new version of MCUboot against that of the current s0/s1 MCUboot - * trailer version to prevent downgrades - */ - int version_check; - - version_check = boot_version_cmp(&boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, - &mcuboot_s0_s1_image_version); - - /* Only update rc if the currently running version is newer */ - if (version_check < rc) { - rc = version_check; - } - } -#endif } #else rc = boot_version_cmp( &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); - -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 - if (rc >= 0 && BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { - /* Also check the new version of MCUboot against that of the current s0/s1 MCUboot - * trailer version to prevent downgrades - */ - int version_check; - - version_check = boot_version_cmp(&boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, - &mcuboot_s0_s1_image_version); - - /* Only update rc if the currently running version is newer */ - if (version_check < rc) { - rc = version_check; - } - } -#endif #endif if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) { BOOT_LOG_ERR("insufficient version in secondary slot"); From 8ac241ee1eedde9490e55137a5a72629edaaade5 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 052/149] Revert "[nrf noup] treewide: Add support for sysbuild assigned images" This reverts commit 8a76fc264125264aca061c138548cd199a33ae8d. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/bootutil_misc.c | 12 -- boot/bootutil/src/loader.c | 181 ++++++++------------- 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 | 69 ++++---- 6 files changed, 105 insertions(+), 241 deletions(-) delete mode 100644 boot/bootutil/src/swap_nsib.c diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 396381437..4fc9e8279 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -432,18 +432,6 @@ boot_write_enc_key(const struct flash_area *fap, uint8_t slot, uint32_t bootutil_max_image_size(struct boot_loader_state *state, const struct flash_area *fap) { -#if defined(CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { - /* NSIB is a direct upgrade without any status or trailer, get the full size of the - * primary slot. - */ - const struct flash_area *fap_nsib = BOOT_IMG_AREA(state, 0); - assert(fap_nsib != NULL); - - return flash_area_get_size(fap_nsib); - } -#endif /* CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 */ - #if defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \ defined(MCUBOOT_FIRMWARE_LOADER) || \ defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index b9e18873d..dc463486b 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -144,15 +144,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all, * * Failure to read any headers is a fatal error. */ -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 +#ifdef PM_S1_ADDRESS /* 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) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER && i == 0) { + if (BOOT_CURR_IMG(state) == 1 && i == 0) { continue; } -#endif /* CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 */ +#endif /* PM_S1_ADDRESS */ if (i > 0 && !require_all) { return 0; } else { @@ -940,7 +940,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) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { + if (BOOT_CURR_IMG(state) == 1) { rc = pcd_version_cmp_net(fap, boot_img_hdr(state, BOOT_SECONDARY_SLOT)); } else { rc = boot_version_cmp( @@ -1011,54 +1011,35 @@ 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; if (flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value)) != 0) { fih_rc = FIH_NO_BOOTABLE_IMAGE; 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) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { + if (BOOT_CURR_IMG(state) == 1) { min_addr = PM_CPUNET_APP_ADDRESS; max_addr = PM_CPUNET_APP_ADDRESS + PM_CPUNET_APP_SIZE; - 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) +#ifdef PM_S1_ADDRESS + } else if (BOOT_CURR_IMG(state) == 0) { min_addr = PM_S0_ADDRESS; - max_addr = (PM_S0_ADDRESS + PM_S0_SIZE); -#else - min_addr = PM_S1_ADDRESS; - max_addr = (PM_S1_ADDRESS + PM_S1_SIZE); + max_addr = pri_fa->fa_off + pri_fa->fa_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 (check_addresses == true && (reset_value < min_addr || reset_value > max_addr)) { + if (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"); @@ -1180,54 +1161,36 @@ boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_ #define SEC_SLOT_TOUCHED 1 #define SEC_SLOT_ASSIGNED 2 -static uint8_t sec_slot_assignment[MCUBOOT_IMAGE_NUMBER] = {0}; - -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 -static inline void sec_slot_untouch(struct boot_loader_state *state) -{ - sec_slot_assignment[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] = SEC_SLOT_VIRGIN; - sec_slot_assignment[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] = SEC_SLOT_VIRGIN; -} +#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 + * mocking two logical secondary + */ +#define SEC_SLOT_PHYSICAL_CNT 1 #else -static inline void sec_slot_untouch(struct boot_loader_state *state) -{ -} +#define SEC_SLOT_PHYSICAL_CNT MCUBOOT_IMAGE_NUMBER #endif +static uint8_t sec_slot_assignmnet[SEC_SLOT_PHYSICAL_CNT] = {0}; + static inline void sec_slot_touch(struct boot_loader_state *state) { -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { - if (sec_slot_assignment[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] == SEC_SLOT_VIRGIN) { - sec_slot_assignment[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] = SEC_SLOT_TOUCHED; - } - } else if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { - if (sec_slot_assignment[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] == SEC_SLOT_VIRGIN) { - sec_slot_assignment[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] = SEC_SLOT_TOUCHED; - } - } -#endif + uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); - if (sec_slot_assignment[BOOT_CURR_IMG(state)] == SEC_SLOT_VIRGIN) { - sec_slot_assignment[BOOT_CURR_IMG(state)] = SEC_SLOT_TOUCHED; + if (SEC_SLOT_VIRGIN == sec_slot_assignmnet[idx]) { + sec_slot_assignmnet[idx] = SEC_SLOT_TOUCHED; } } static inline void sec_slot_mark_assigned(struct boot_loader_state *state) { -#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { - sec_slot_assignment[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] = SEC_SLOT_ASSIGNED; - } else if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { - sec_slot_assignment[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] = SEC_SLOT_ASSIGNED; - } -#endif + uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); - sec_slot_assignment[BOOT_CURR_IMG(state)] = SEC_SLOT_ASSIGNED; + sec_slot_assignmnet[idx] = SEC_SLOT_ASSIGNED; } /** - * Cleanup up all secondary slot which couldn't be assigned to any primary slot. + * Cleanu 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. @@ -1239,8 +1202,8 @@ static void sec_slot_cleanup_if_unusable(void) { uint8_t idx; - for (idx = 0; idx < MCUBOOT_IMAGE_NUMBER; idx++) { - if (SEC_SLOT_TOUCHED == sec_slot_assignment[idx]) { + for (idx = 0; idx < SEC_SLOT_PHYSICAL_CNT; idx++) { + if (SEC_SLOT_TOUCHED == sec_slot_assignmnet[idx]) { const struct flash_area *secondary_fa; int rc; @@ -1249,20 +1212,17 @@ 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 image %d", idx); + BOOT_LOG_ERR("Cleaned-up secondary slot of %d. image.", idx); } } if (rc) { - BOOT_LOG_ERR("Failed to clean-up secondary slot of image %d: %d", idx, rc); + BOOT_LOG_ERR("Can not cleanup secondary slot of %d. image.", idx); } } } } #else -static inline void sec_slot_untouch(struct boot_loader_state *state) -{ -} static inline void sec_slot_touch(struct boot_loader_state *state) { } @@ -1294,7 +1254,7 @@ boot_validated_swap_type(struct boot_loader_state *state, owner_nsib[BOOT_CURR_IMG(state)] = false; #endif -#if defined(PM_S1_ADDRESS) || defined(PM_CPUNET_B0N_ADDRESS) +#if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); struct image_header *hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); @@ -1332,31 +1292,31 @@ boot_validated_swap_type(struct boot_loader_state *state, } /* Check start and end of primary slot for current image */ -#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 (reset_addr < primary_fa->fa_off) { +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) + const struct flash_area *nsib_fa; - 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)) { + /* NSIB upgrade slot */ + rc = flash_area_open((uint32_t)_image_1_primary_slot_id, + &nsib_fa); + + 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; + } #else - } else if (reset_addr >= PM_S0_ADDRESS && reset_addr <= (PM_S0_ADDRESS + PM_S0_SIZE)) { + return BOOT_SWAP_TYPE_NONE; + #endif - /* NSIB upgrade but for the wrong slot, must be erased */ - BOOT_LOG_ERR("Image in slot is for wrong s0/s1 image"); - flash_area_erase(secondary_fa, 0, secondary_fa->fa_size); - sec_slot_untouch(state); - BOOT_LOG_ERR("Cleaned-up secondary slot of image %d", BOOT_CURR_IMG(state)); - return BOOT_SWAP_TYPE_FAIL; - } else if (reset_addr < primary_fa->fa_off || reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { + + } else if (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; } @@ -1369,7 +1329,7 @@ boot_validated_swap_type(struct boot_loader_state *state, sec_slot_mark_assigned(state); } -#endif /* PM_S1_ADDRESS || PM_CPUNET_B0N_ADDRESS */ +#endif /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -2027,22 +1987,7 @@ 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 (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); - } + swap_run(state, bs, copy_size); #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT extern int boot_status_fails; @@ -2687,6 +2632,12 @@ 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: @@ -2754,17 +2705,13 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) */ } +#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT #ifdef PM_S1_ADDRESS /* Patch needed for NCS. Image 1 primary is the currently * 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) == - CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER; -#endif - -#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT -#ifdef PM_S1_ADDRESS + bool image_validated_by_nsib = BOOT_CURR_IMG(state) == 1; if (!image_validated_by_nsib) #endif { diff --git a/boot/bootutil/src/swap_nsib.c b/boot/bootutil/src/swap_nsib.c deleted file mode 100644 index 079e193d5..000000000 --- a/boot/bootutil/src/swap_nsib.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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, false); - assert(rc == 0); - - rc = boot_copy_region(state, fap_sec, fap_pri, 0, 0, fap_pri->fa_size); - assert(rc == 0); - - rc = swap_scramble_trailer_sectors(state, fap_sec); - assert(rc == 0); - - rc = boot_scramble_region(fap_sec, 0, MIN((fap_pri->fa_size + sector_sz), fap_sec->fa_size), false); - 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 90e0b3742..b564ea99e 100644 --- a/boot/bootutil/src/swap_priv.h +++ b/boot/bootutil/src/swap_priv.h @@ -130,12 +130,4 @@ bool swap_write_block_size_check(struct boot_loader_state *state); */ 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 10593cdbf..73cb38fa5 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -192,12 +192,6 @@ else() ) endif() endif() - - 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 42f25182e..db60ddd03 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -15,36 +15,48 @@ #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_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 -#else -#define MCUBOOT_S0_S1_SLOTS -#endif +#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 -#if (MCUBOOT_IMAGE_NUMBER == 1) || (MCUBOOT_IMAGE_NUMBER == 2 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1) +#if (MCUBOOT_IMAGE_NUMBER == 1) #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 \ +#elif (MCUBOOT_IMAGE_NUMBER == 2) +#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 \ +#elif (MCUBOOT_IMAGE_NUMBER == 3) +#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 @@ -53,7 +65,6 @@ 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]; }; @@ -61,8 +72,6 @@ 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) @@ -72,6 +81,10 @@ 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 7337f2f5f596e0c270fdef68caa5e2e13e230df0 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 053/149] Revert "[nrf noup] boot: zephyr: Do not lock PCD region with TF-M" This reverts commit 2e29ea662c45ef1bc07dbf36315abe3a35a7eec0. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/main.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index bdc264d94..d192f52d1 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -754,11 +754,7 @@ int main(void) } #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) -#if defined(PM_TFM_SECURE_ADDRESS) - pcd_lock_ram(false); -#else - pcd_lock_ram(true); -#endif + pcd_lock_ram(); #endif #endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */ From 5df29e699a79be35275bb1486ecf106f731d5a0d Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 054/149] Revert "[nrf noup] bootutil: loader: Fix netcore address checking" This reverts commit 919ecf064763a75085bd35f9e5066756f03fb053. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index dc463486b..583f8137b 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1280,7 +1280,7 @@ boot_validated_swap_type(struct boot_loader_state *state, #ifdef PM_S1_ADDRESS #ifdef PM_CPUNET_B0N_ADDRESS - if(!(reset_addr >= PM_CPUNET_APP_ADDRESS && reset_addr < PM_CPUNET_APP_END_ADDRESS)) + if(reset_addr < PM_CPUNET_B0N_ADDRESS) #endif { const struct flash_area *primary_fa; @@ -1353,8 +1353,7 @@ boot_validated_swap_type(struct boot_loader_state *state, * update and indicate to the caller of this function that no update is * available */ - if (upgrade_valid && reset_addr >= PM_CPUNET_APP_ADDRESS && - reset_addr < PM_CPUNET_APP_END_ADDRESS) { + if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) { struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; uint32_t *net_core_fw_addr = (uint32_t *)(vtable_addr); From b2d3d7aafd287afdf288495e2b359c99cdc50fb3 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 055/149] Revert "[nrf noup] boot/../loader: reboot after updating s0/s1" This reverts commit 7e0d80253cf5396ae5bf5f86a8735b3d7532a90f. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 10 ---------- boot/zephyr/Kconfig | 1 - 2 files changed, 11 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 583f8137b..c54b0577d 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -50,10 +50,6 @@ #include "bootutil/boot_hooks.h" #include "bootutil/mcuboot_status.h" -#ifdef __ZEPHYR__ -#include -#endif - #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) #include #ifdef CONFIG_PCD_READ_NETCORE_APP_VERSION @@ -2631,12 +2627,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: diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 9f0399fd3..edbeeb6be 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -18,7 +18,6 @@ config MCUBOOT select MPU_ALLOW_FLASH_WRITE if ARM_MPU select USE_DT_CODE_PARTITION if HAS_FLASH_LOAD_OFFSET select MCUBOOT_BOOTUTIL_LIB - select REBOOT if SECURE_BOOT config BOOT_USE_MBEDTLS bool From 63e5ade5c44b823a653033295b8bed746d77729c Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 056/149] Revert "[nrf noup] boot/../loader: skip downgrade prevention for s1/s0" This reverts commit 6ccfff81eb5f6d2573e8147f0a14ec80afddade8. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/include/bootutil/security_cnt.h | 9 -- boot/bootutil/src/image_validate.c | 20 ----- boot/bootutil/src/loader.c | 83 ------------------- 3 files changed, 112 deletions(-) diff --git a/boot/bootutil/include/bootutil/security_cnt.h b/boot/bootutil/include/bootutil/security_cnt.h index ff3a7371c..228ada8dc 100644 --- a/boot/bootutil/include/bootutil/security_cnt.h +++ b/boot/bootutil/include/bootutil/security_cnt.h @@ -39,15 +39,6 @@ extern "C" { */ fih_ret boot_nv_security_counter_init(void); -/** - * Checks if the specified image should have a security counter present on it or not - * - * @param image_index Index of the image to check (from 0). - * - * @return FIH_SUCCESS if security counter should be present; FIH_FAILURE if otherwise - */ -fih_ret boot_nv_image_should_have_security_counter(uint32_t image_index); - /** * Reads the stored value of a given image's security counter. * diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index cb9ce3466..f40667866 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -241,15 +241,6 @@ bootutil_img_validate(struct boot_loader_state *state, fih_int security_cnt = fih_int_encode(INT_MAX); uint32_t img_security_cnt = 0; FIH_DECLARE(security_counter_valid, FIH_FAILURE); - FIH_DECLARE(security_counter_should_be_present, FIH_FAILURE); - - FIH_CALL(boot_nv_image_should_have_security_counter, security_counter_should_be_present, - image_index); - if (FIH_NOT_EQ(security_counter_should_be_present, FIH_SUCCESS) && - FIH_NOT_EQ(security_counter_should_be_present, FIH_FAILURE)) { - rc = -1; - goto out; - } #endif #ifdef MCUBOOT_UUID_VID struct image_uuid img_uuid_vid = {0x00}; @@ -454,10 +445,6 @@ bootutil_img_validate(struct boot_loader_state *state, goto out; } - if (FIH_EQ(security_counter_should_be_present, FIH_FAILURE)) { - goto skip_security_counter_read; - } - FIH_CALL(boot_nv_security_counter_get, fih_rc, image_index, &security_cnt); if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { @@ -492,7 +479,6 @@ bootutil_img_validate(struct boot_loader_state *state, /* The image's security counter has been successfully verified. */ security_counter_valid = fih_rc; -skip_security_counter_read: break; } #endif /* MCUBOOT_HW_ROLLBACK_PROT */ @@ -570,16 +556,10 @@ bootutil_img_validate(struct boot_loader_state *state, FIH_SET(fih_rc, valid_signature); #endif #ifdef MCUBOOT_HW_ROLLBACK_PROT - if (FIH_EQ(security_counter_should_be_present, FIH_FAILURE)) { - goto skip_security_counter_check; - } - if (FIH_NOT_EQ(security_counter_valid, FIH_SUCCESS)) { rc = -1; goto out; } - -skip_security_counter_check: #endif #ifdef MCUBOOT_UUID_VID diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index c54b0577d..1b7f53f6b 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -71,9 +71,6 @@ int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); BOOT_LOG_MODULE_DECLARE(mcuboot); static struct boot_loader_state boot_data; -#ifdef PM_S1_ADDRESS -static bool owner_nsib[BOOT_IMAGE_NUMBER] = {false}; -#endif #if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING) static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0}; @@ -1057,38 +1054,6 @@ boot_validate_slot(struct boot_loader_state *state, int slot, } #ifdef MCUBOOT_HW_ROLLBACK_PROT -/** - * Checks if the specified image should have a security counter present on it or not - * - * @param image_index Index of the image to check. - * - * @return true if security counter should be present; false if otherwise - */ -fih_ret boot_nv_image_should_have_security_counter(uint32_t image_index) -{ -#if defined(PM_S1_ADDRESS) - if (owner_nsib[image_index]) { - /* - * Downgrade prevention on S0/S1 image is managed by NSIB, which is a software (not - * hardware) check - */ - return FIH_FAILURE; - } -#endif - -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 - if (image_index == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { - /* - * Downgrade prevention on network core image is managed by NSIB which is a software (not - * hardware) check - */ - return FIH_FAILURE; - } -#endif - - return FIH_SUCCESS; -} - /** * Updates the stored security counter value with the image's security counter * value which resides in the given slot, only if it's greater than the stored @@ -1110,26 +1075,6 @@ boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_ uint32_t img_security_cnt; int rc; -#if defined(PM_S1_ADDRESS) - if (owner_nsib[BOOT_CURR_IMG(state)]) { - /* - * Downgrade prevention on S0/S1 image is managed by NSIB which is a software (not - * hardware) check - */ - return 0; - } -#endif - -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { - /* - * Downgrade prevention on network core image is managed by NSIB which is a software (not - * hardware) check - */ - return 0; - } -#endif - fap = BOOT_IMG_AREA(state, slot); assert(fap != NULL); @@ -1246,9 +1191,6 @@ boot_validated_swap_type(struct boot_loader_state *state, int swap_type; FIH_DECLARE(fih_rc, FIH_FAILURE); bool upgrade_valid = false; -#if defined(PM_S1_ADDRESS) - owner_nsib[BOOT_CURR_IMG(state)] = false; -#endif #if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) const struct flash_area *secondary_fa = @@ -1305,7 +1247,6 @@ boot_validated_swap_type(struct boot_loader_state *state, && 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; } #else return BOOT_SWAP_TYPE_NONE; @@ -1316,10 +1257,6 @@ boot_validated_swap_type(struct boot_loader_state *state, /* The image in the secondary slot is not intended for any */ return BOOT_SWAP_TYPE_NONE; } - - if ((primary_fa->fa_off == PM_S0_ADDRESS) || (primary_fa->fa_off == PM_S1_ADDRESS)) { - owner_nsib[BOOT_CURR_IMG(state)] = true; - } } #endif /* PM_S1_ADDRESS */ sec_slot_mark_assigned(state); @@ -2428,26 +2365,6 @@ check_downgrade_prevention(struct boot_loader_state *state) uint32_t security_counter[2]; int rc; -#if defined(PM_S1_ADDRESS) - if (owner_nsib[BOOT_CURR_IMG(state)]) { - /* - * Downgrade prevention on S0/S1 image is managed by NSIB which is a software (not - * hardware) check - */ - return 0; - } -#endif - -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 - if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { - /* - * Downgrade prevention on network core image is managed by NSIB which is a software (not - * hardware) check - */ - return 0; - } -#endif - if (MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER) { /* If there was security no counter in slot 0, allow swap */ rc = bootutil_get_img_security_cnt(state, BOOT_SLOT_PRIMARY, From 082353ec3e1c7b5f3dd58255910767e3025f8329 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 057/149] Revert "[nrf noup] boot/zephyr: fix fw_info search" This reverts commit b054302ac43ccf433f887ff441e28fcfa01a20a2. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/main.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index d192f52d1..bbc7abe97 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -217,14 +217,7 @@ static void do_boot(struct boot_rsp *rsp) #endif #if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED) - uintptr_t fw_start_addr; - - rc = flash_device_base(rsp->br_flash_dev_id, &fw_start_addr); - assert(rc == 0); - - fw_start_addr += rsp->br_image_off + rsp->br_hdr->ih_hdr_size; - - const struct fw_info *firmware_info = fw_info_find(fw_start_addr); + const struct fw_info *firmware_info = fw_info_find((uint32_t) vt); bool provided = fw_info_ext_api_provide(firmware_info, true); #ifdef PM_S0_ADDRESS From d14a3085a9f1e1ec15c3fe460f8ef6faeaec8475 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 058/149] Revert "[nrf noup] loader: remove cleanup for direct xip mode" This reverts commit 210289dfff728925f2e56ffaacfea95aec49d575. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 1b7f53f6b..a70d99f14 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1093,8 +1093,6 @@ boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_ } #endif /* MCUBOOT_HW_ROLLBACK_PROT */ -#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) - #if defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ (defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP)) @@ -1176,6 +1174,7 @@ static inline void sec_slot_cleanup_if_unusable(void) #endif /* defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) */ +#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) /** * Determines which swap operation to perform, if any. If it is determined * that a swap operation is required, the image in the secondary slot is checked From 8b341a9748501f4baeaad9c60ce6693b6535428b Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:54 +0200 Subject: [PATCH 059/149] Revert "[nrf noup] loader: introduced cleanup of unusable secondary slot" This reverts commit 1e13c43c8faa7eff93ebd0ef85bf7d6bf7595000. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 90 -------------------------------------- 1 file changed, 90 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index a70d99f14..7201fc597 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1093,87 +1093,6 @@ boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_ } #endif /* MCUBOOT_HW_ROLLBACK_PROT */ -#if defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ -(defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP)) - -#define SEC_SLOT_VIRGIN 0 -#define SEC_SLOT_TOUCHED 1 -#define SEC_SLOT_ASSIGNED 2 - -#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 - * mocking two logical secondary - */ -#define SEC_SLOT_PHYSICAL_CNT 1 -#else -#define SEC_SLOT_PHYSICAL_CNT MCUBOOT_IMAGE_NUMBER -#endif - -static uint8_t sec_slot_assignmnet[SEC_SLOT_PHYSICAL_CNT] = {0}; - -static inline void sec_slot_touch(struct boot_loader_state *state) -{ - 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; - } -} - -static inline void sec_slot_mark_assigned(struct boot_loader_state *state) -{ - uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); - - sec_slot_assignmnet[idx] = SEC_SLOT_ASSIGNED; -} - -/** - * Cleanu 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. - * - * This function is supposed to be called after boot_validated_swap_type() - * iterates over all the images in context_boot_go(). - */ -static void sec_slot_cleanup_if_unusable(void) -{ - uint8_t idx; - - for (idx = 0; idx < SEC_SLOT_PHYSICAL_CNT; idx++) { - if (SEC_SLOT_TOUCHED == sec_slot_assignmnet[idx]) { - const struct flash_area *secondary_fa; - int rc; - - rc = flash_area_open(flash_area_id_from_multi_image_slot(idx, BOOT_SECONDARY_SLOT), - &secondary_fa); - 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); - } - } - - if (rc) { - BOOT_LOG_ERR("Can not cleanup secondary slot of %d. image.", idx); - } - } - } -} -#else -static inline void sec_slot_touch(struct boot_loader_state *state) -{ -} -static inline void sec_slot_mark_assigned(struct boot_loader_state *state) -{ -} -static inline void sec_slot_cleanup_if_unusable(void) -{ -} -#endif /* defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ - defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) */ - #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) /** * Determines which swap operation to perform, if any. If it is determined @@ -1212,9 +1131,6 @@ boot_validated_swap_type(struct boot_loader_state *state, if (rc != 0) { return BOOT_SWAP_TYPE_FAIL; } - - sec_slot_touch(state); - #ifdef PM_S1_ADDRESS #ifdef PM_CPUNET_B0N_ADDRESS if(reset_addr < PM_CPUNET_B0N_ADDRESS) @@ -1249,7 +1165,6 @@ boot_validated_swap_type(struct boot_loader_state *state, } #else return BOOT_SWAP_TYPE_NONE; - #endif } else if (reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { @@ -1258,9 +1173,7 @@ boot_validated_swap_type(struct boot_loader_state *state, } } #endif /* PM_S1_ADDRESS */ - sec_slot_mark_assigned(state); } - #endif /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); @@ -2470,9 +2383,6 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } } - /* cleanup secondary slots which were recognized unusable*/ - sec_slot_cleanup_if_unusable(); - #if (BOOT_IMAGE_NUMBER > 1) if (has_upgrade) { /* Iterate over all the images and verify whether the image dependencies From 5912f0cc83ea40b454d6575f170bd452278d86a0 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 060/149] Revert "[nrf noup] sysflash: Add support for three images" This reverts commit 7025efda58de8c60794c1622bb76338ad0342eac. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/include/sysflash/pm_sysflash.h | 82 ++++++++++------------ 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h index db60ddd03..377291e8b 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -11,19 +11,37 @@ #include #include -#include #ifndef CONFIG_SINGLE_APPLICATION_SLOT -#if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) +#if (MCUBOOT_IMAGE_NUMBER == 1) + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID + +#elif (MCUBOOT_IMAGE_NUMBER == 2) + /* If B0 is present then two bootloaders are present, and we must use * a single secondary slot for both primary slots. */ +#if defined(PM_B0_ADDRESS) extern uint32_t _image_1_primary_slot_id[]; -#endif /* (MCUBOOT_IMAGE_NUMBER == 2 && defined(PM_B0_ADDRESS) */ +#endif +#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) -#if (MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ - !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) +#elif defined(PM_B0_ADDRESS) #define FLASH_AREA_IMAGE_PRIMARY(x) \ ((x == 0) ? \ @@ -38,52 +56,26 @@ extern uint32_t _image_1_primary_slot_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 - -#if (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, \ - FLASH_AREA_IMAGE_1_SLOTS -#elif (MCUBOOT_IMAGE_NUMBER == 3) -#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS, \ - FLASH_AREA_IMAGE_1_SLOTS, \ - FLASH_AREA_IMAGE_2_SLOTS #else -#error Unsupported number of images -#endif -static inline uint32_t __flash_area_ids_for_slot(int img, int slot) -{ - static const int all_slots[] = { - ALL_AVAILABLE_SLOTS - }; - return all_slots[img * 2 + slot]; -}; +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) -#undef FLASH_AREA_IMAGE_0_SLOTS -#undef FLASH_AREA_IMAGE_1_SLOTS -#undef FLASH_AREA_IMAGE_2_SLOTS -#undef ALL_AVAILABLE_SLOTS +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) -#define FLASH_AREA_IMAGE_PRIMARY(x) __flash_area_ids_for_slot(x, 0) -#define FLASH_AREA_IMAGE_SECONDARY(x) __flash_area_ids_for_slot(x, 1) +#endif /* PM_B0_ADDRESS */ -#if !defined(CONFIG_BOOT_SWAP_USING_MOVE) -#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) - */ +#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID #else /* CONFIG_SINGLE_APPLICATION_SLOT */ From efe48dcdbb57b893ca61ced5c44918477da9b10c Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 061/149] Revert "[nrf noup] sysflash: Move partition manager definitions to pm_sysflash.h" This reverts commit 2c2c2e559f4ae27ca4d3de06815b0e649405b27d. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/include/sysflash/pm_sysflash.h | 92 ---------------------- boot/zephyr/include/sysflash/sysflash.h | 90 +++++++++++++++++++-- 2 files changed, 85 insertions(+), 97 deletions(-) delete mode 100644 boot/zephyr/include/sysflash/pm_sysflash.h diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h deleted file mode 100644 index 377291e8b..000000000 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2023 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#ifndef __PM_SYSFLASH_H__ -#define __PM_SYSFLASH_H__ -/* Blocking the __SYSFLASH_H__ */ -#define __SYSFLASH_H__ - -#include -#include - -#ifndef CONFIG_SINGLE_APPLICATION_SLOT - -#if (MCUBOOT_IMAGE_NUMBER == 1) - -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID - -#elif (MCUBOOT_IMAGE_NUMBER == 2) - -/* If B0 is present then two bootloaders are present, and we must use - * a single secondary slot for both primary slots. - */ -#if defined(PM_B0_ADDRESS) -extern uint32_t _image_1_primary_slot_id[]; -#endif -#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) - -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) -#elif defined(PM_B0_ADDRESS) - -#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 - -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) - -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) - -#endif /* PM_B0_ADDRESS */ - -#endif -#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID - -#else /* CONFIG_SINGLE_APPLICATION_SLOT */ - -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID -/* NOTE: Scratch parition is not used by single image DFU but some of - * functions in common files reference it, so the definitions has been - * provided to allow compilation of common units. - */ -#define FLASH_AREA_IMAGE_SCRATCH 0 - -#endif /* CONFIG_SINGLE_APPLICATION_SLOT */ - -#endif /* __PM_SYSFLASH_H__ */ diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index 3c3638d7f..f1ef4100e 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -4,15 +4,93 @@ * SPDX-License-Identifier: Apache-2.0 */ -#if USE_PARTITION_MANAGER -/* Blocking the rest of the file */ +#ifndef __SYSFLASH_H__ #define __SYSFLASH_H__ -#include + +#if USE_PARTITION_MANAGER +#include +#include + +#ifndef CONFIG_SINGLE_APPLICATION_SLOT + +#if (MCUBOOT_IMAGE_NUMBER == 1) + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID + +#elif (MCUBOOT_IMAGE_NUMBER == 2) + +/* If B0 is present then two bootloaders are present, and we must use + * a single secondary slot for both primary slots. + */ +#if defined(PM_B0_ADDRESS) +extern uint32_t _image_1_primary_slot_id[]; #endif +#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) +#elif defined(PM_B0_ADDRESS) + +#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 + +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) + +#endif /* PM_B0_ADDRESS */ -#ifndef __SYSFLASH_H__ -#define __SYSFLASH_H__ +#endif +#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID + +#else /* CONFIG_SINGLE_APPLICATION_SLOT */ + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID +/* NOTE: Scratch parition is not used by single image DFU but some of + * functions in common files reference it, so the definitions has been + * provided to allow compilation of common units. + */ +#define FLASH_AREA_IMAGE_SCRATCH 0 + +#endif /* CONFIG_SINGLE_APPLICATION_SLOT */ +#else + +#include #include #include #include @@ -71,4 +149,6 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #endif /* CONFIG_SINGLE_APPLICATION_SLOT */ +#endif /* USE_PARTITION_MANAGER */ + #endif /* __SYSFLASH_H__ */ From a985b245a2f90bd09135288c8a28038f0103066f Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 062/149] Revert "[nrf noup] boot: Add support for NSIB and multi-image" This reverts commit 5cb4e7420b182677f120d302e71e3bd8c75f6646. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 42 ++++++------------------- boot/zephyr/include/sysflash/sysflash.h | 19 ++--------- 2 files changed, 11 insertions(+), 50 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 7201fc597..f654acc52 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1020,11 +1020,6 @@ boot_validate_slot(struct boot_loader_state *state, int slot, if (BOOT_CURR_IMG(state) == 1) { 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) { - min_addr = PM_S0_ADDRESS; - max_addr = pri_fa->fa_off + pri_fa->fa_size; -#endif } else #endif { @@ -1138,37 +1133,18 @@ boot_validated_swap_type(struct boot_loader_state *state, { const struct flash_area *primary_fa; rc = flash_area_open(flash_area_id_from_multi_image_slot( - BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT), - &primary_fa); + BOOT_CURR_IMG(state), + BOOT_PRIMARY_SLOT), + &primary_fa); + if (rc != 0) { return BOOT_SWAP_TYPE_FAIL; } - - /* 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; - - /* NSIB upgrade slot */ - rc = flash_area_open((uint32_t)_image_1_primary_slot_id, - &nsib_fa); - - 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; - } -#else - return BOOT_SWAP_TYPE_NONE; -#endif - - } else if (reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { - /* The image in the secondary slot is not intended for any */ + /* Get start and end of primary slot for current image */ + 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 this image + */ return BOOT_SWAP_TYPE_NONE; } } diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index f1ef4100e..7112f9baa 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -23,24 +23,9 @@ /* If B0 is present then two bootloaders are present, and we must use * a single secondary slot for both primary slots. */ -#if defined(PM_B0_ADDRESS) -extern uint32_t _image_1_primary_slot_id[]; -#endif -#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) +#ifdef PM_B0_ADDRESS -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) -#elif defined(PM_B0_ADDRESS) +extern uint32_t _image_1_primary_slot_id[]; #define FLASH_AREA_IMAGE_PRIMARY(x) \ ((x == 0) ? \ From 3d3908fa6d351065ab2d8481432100045c93a0ec Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 063/149] Revert "[nrf noup] loader: Fix missing PCD define check" This reverts commit a23ae31a24f2f9f0bfda39386aa2cf8c364c135f. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index f654acc52..ccd917a68 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1169,7 +1169,7 @@ boot_validated_swap_type(struct boot_loader_state *state, } #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) \ - && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) && defined(CONFIG_PCD_APP) + && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) /* If the update is valid, and it targets the network core: perform the * update and indicate to the caller of this function that no update is * available @@ -1197,8 +1197,7 @@ boot_validated_swap_type(struct boot_loader_state *state, swap_type = BOOT_SWAP_TYPE_NONE; } } -#endif /* CONFIG_SOC_NRF5340_CPUAPP && PM_CPUNET_B0N_ADDRESS && - !CONFIG_NRF53_MULTI_IMAGE_UPDATE && CONFIG_PCD_APP */ +#endif /* CONFIG_SOC_NRF5340_CPUAPP */ } return swap_type; From 65e4e60c8eca11334a887c4b17d7229c54f9eb79 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 064/149] Revert "[nrf noup] boards: thingy53: disable GPIO ISR support" This reverts commit 2c695f49eec83510b9d3df473b20089497491185. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index d68509786..93be36738 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -21,7 +21,6 @@ CONFIG_UART_LINE_CTRL=y # MCUBoot serial CONFIG_GPIO=y -CONFIG_GPIO_NRFX_INTERRUPT=n CONFIG_MCUBOOT_SERIAL=y CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y CONFIG_BOOT_SERIAL_CDC_ACM=y From f21f9840e79461f272e3c5dd2b1e1a7737e095e7 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 065/149] =?UTF-8?q?Revert=20"[nrf=20noup]=C2=A0loader:=20A?= =?UTF-8?q?dd=20firmware=20version=20check=20downgrade=20prevention"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit d1c8f64803b71430c49329cbf6171a76c545ff6d. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index ccd917a68..5781dab21 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -52,10 +52,6 @@ #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) #include -#ifdef CONFIG_PCD_READ_NETCORE_APP_VERSION -#include -int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); -#endif #endif #ifdef MCUBOOT_ENC_IMAGES @@ -930,22 +926,10 @@ boot_validate_slot(struct boot_loader_state *state, int slot, int rc; /* 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 (BOOT_CURR_IMG(state) == 1) { - rc = pcd_version_cmp_net(fap, boot_img_hdr(state, BOOT_SECONDARY_SLOT)); - } else { - rc = boot_version_cmp( - &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, - &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); - } -#else - rc = boot_version_cmp( - &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, - &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); -#endif - if (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) { + rc = boot_version_cmp( + &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, + &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); + if (rc < 0 && boot_check_header_erased(state, BOOT_SLOT_PRIMARY)) { BOOT_LOG_ERR("insufficient version in secondary slot"); boot_scramble_slot(fap, slot); /* Image in the secondary slot does not satisfy version requirement. From bcc53a158c7ff78dd1a53c4c56ec59a328fdc3db Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 066/149] Revert "[nrf noup] zephyr: Boot even if EXT_ABI is not provided" This reverts commit 0f20d8ef9909c6c508024d9ea04bcfaaf4929dc5. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index bbc7abe97..71ec93775 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -217,16 +217,13 @@ static void do_boot(struct boot_rsp *rsp) #endif #if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED) - const struct fw_info *firmware_info = fw_info_find((uint32_t) vt); - bool provided = fw_info_ext_api_provide(firmware_info, true); + bool provided = fw_info_ext_api_provide(fw_info_find((uint32_t)vt), true); #ifdef PM_S0_ADDRESS /* Only fail if the immutable bootloader is present. */ if (!provided) { - if (firmware_info == NULL) { - BOOT_LOG_WRN("Unable to find firmware info structure in %p", vt); - } - BOOT_LOG_ERR("Failed to provide EXT_APIs to %p", vt); + BOOT_LOG_ERR("Failed to provide EXT_APIs\n"); + return; } #endif #endif From 758c8c935c745163073e46a9c85de9e74ec1b3d2 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 067/149] Revert "[nrf noup] zephyr: Add RAM flash configuration to cache for sysbuild" This reverts commit 6512a0366e3d68a3a59fbc3ccd943e85dc98ae2a. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/CMakeLists.txt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 73cb38fa5..00650afa3 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -759,14 +759,3 @@ zephyr_library_sources( ${BOOT_DIR}/zephyr/nrf_cleanup.c ) endif() - -if(SYSBUILD AND CONFIG_PCD_APP) - # Sysbuild requires details of the RAM flash device are stored to the cache of MCUboot so - # that they can be read when running partition manager - dt_nodelabel(ram_flash_dev NODELABEL flash_sim0) - dt_reg_addr(ram_flash_addr PATH ${ram_flash_dev}) - dt_reg_size(ram_flash_size PATH ${ram_flash_dev}) - - set(RAM_FLASH_ADDR "${ram_flash_addr}" CACHE STRING "" FORCE) - set(RAM_FLASH_SIZE "${ram_flash_size}" CACHE STRING "" FORCE) -endif() From 08131d6baa70f6bc3755ccee94f6180e338d0955 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 068/149] Revert "[nrf noup] loader: Do not check reset vector for XIP image" This reverts commit 99de74982aaef827e0fb0e8179f2f74d02230d8a. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 5781dab21..bbb1c6d13 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -973,18 +973,8 @@ boot_validate_slot(struct boot_loader_state *state, int slot, * overwriting an application written to the incorrect slot. * This feature is only supported by ARM platforms. */ -#if MCUBOOT_IMAGE_NUMBER >= 3 - /* Currently the MCUboot can be configured for up to 3 image, where image number 2 is - * designated for XIP, where it is the second part of image stored in slots of image - * 0. This part of image is not bootable, as the XIP setup is done by the app in - * image 0 slot, and it does not carry the reset vector. - */ - if (fap == state->imgs[2][BOOT_SECONDARY_SLOT].area) { - goto out; - } -#endif - if (fap == BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT)) { - const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT); + if (fap == BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY)) { + const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY); 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); From 96401df4bc77d211607656bf6533a07e24855b5a Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 069/149] Revert "[nrf noup] loader: Fix reading reset addr to support ext flash" This reverts commit f239be93f8ac5b71ea65140a30207b8923ffe606. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index bbb1c6d13..281e65f45 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1082,9 +1082,10 @@ boot_validated_swap_type(struct boot_loader_state *state, #if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); - struct image_header *hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); + struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; + uint32_t vtable_addr = 0; + uint32_t *vtable = 0; uint32_t reset_addr = 0; - int rc = 0; /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other * B1 slot S0 or S1) share the same secondary slot, we need to check * whether the update candidate in the secondary slot is intended for @@ -1094,19 +1095,16 @@ boot_validated_swap_type(struct boot_loader_state *state, */ if (hdr->ih_magic == IMAGE_MAGIC) { - rc = flash_area_read(secondary_fa, hdr->ih_hdr_size + - sizeof(uint32_t), &reset_addr, - sizeof(reset_addr)); - if (rc != 0) { - return BOOT_SWAP_TYPE_FAIL; - } + vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; + vtable = (uint32_t *)(vtable_addr); + reset_addr = vtable[1]; #ifdef PM_S1_ADDRESS #ifdef PM_CPUNET_B0N_ADDRESS if(reset_addr < PM_CPUNET_B0N_ADDRESS) #endif { const struct flash_area *primary_fa; - rc = flash_area_open(flash_area_id_from_multi_image_slot( + int rc = flash_area_open(flash_area_id_from_multi_image_slot( BOOT_CURR_IMG(state), BOOT_PRIMARY_SLOT), &primary_fa); @@ -1142,19 +1140,16 @@ boot_validated_swap_type(struct boot_loader_state *state, upgrade_valid = true; } -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) \ - && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) /* If the update is valid, and it targets the network core: perform the * update and indicate to the caller of this function that no update is * available */ if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) { - struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; - uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; - uint32_t *net_core_fw_addr = (uint32_t *)(vtable_addr); uint32_t fw_size = hdr->ih_img_size; + BOOT_LOG_INF("Starting network core update"); - rc = pcd_network_core_update(net_core_fw_addr, fw_size); + int rc = pcd_network_core_update(vtable, fw_size); if (rc != 0) { swap_type = BOOT_SWAP_TYPE_FAIL; From 84da9dcf3571525fb077f8616c2debc58aa42c7d Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 070/149] Revert "[nrf noup] zephyr: Clean up non-secure RAM if enabled" This reverts commit 92da561256d98db5ca2cf07078469d9681c1d4de. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/CMakeLists.txt | 2 +- boot/zephyr/include/nrf_cleanup.h | 5 -- boot/zephyr/main.c | 5 +- boot/zephyr/nrf_cleanup.c | 79 ++++++++----------------------- 4 files changed, 22 insertions(+), 69 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 00650afa3..a1e0679c4 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -754,7 +754,7 @@ if(SYSBUILD) set(mcuboot_image_upgrade_footer_size ${required_upgrade_size} CACHE INTERNAL "Estimated MCUboot update image trailer size" FORCE) endif() -if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL OR CONFIG_MCUBOOT_CLEANUP_NONSECURE_RAM) +if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL) zephyr_library_sources( ${BOOT_DIR}/zephyr/nrf_cleanup.c ) diff --git a/boot/zephyr/include/nrf_cleanup.h b/boot/zephyr/include/nrf_cleanup.h index 9e87e13f5..6b04cedfe 100644 --- a/boot/zephyr/include/nrf_cleanup.h +++ b/boot/zephyr/include/nrf_cleanup.h @@ -16,9 +16,4 @@ */ void nrf_cleanup_peripheral(void); -/** - * Perform cleanup of non-secure RAM that may have been used by MCUBoot. - */ -void nrf_cleanup_ns_ram(void); - #endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 71ec93775..2f39bbabe 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -149,7 +149,7 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #include #endif -#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL || CONFIG_MCUBOOT_NRF_CLEANUP_NONSECURE_RAM +#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL #include #endif @@ -230,9 +230,6 @@ static void do_boot(struct boot_rsp *rsp) #if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL nrf_cleanup_peripheral(); #endif -#if CONFIG_MCUBOOT_NRF_CLEANUP_NONSECURE_RAM && defined(PM_SRAM_NONSECURE_NAME) - nrf_cleanup_ns_ram(); -#endif #if CONFIG_MCUBOOT_CLEANUP_ARM_CORE cleanup_arm_interrupts(); /* Disable and acknowledge all interrupts */ diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index 051705ec9..5bab26b24 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -5,8 +5,9 @@ */ #include -#include -#include +#if defined(NRF_UARTE0) || defined(NRF_UARTE1) + #include +#endif #if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) #include #endif @@ -19,15 +20,6 @@ #include -#if USE_PARTITION_MANAGER -#include -#endif - -#if defined(NRF_UARTE0) || defined(NRF_UARTE1) || defined(NRF_UARTE20) || \ - defined(NRF_UARTE30) -#define NRF_UARTE_CLEANUP -#endif - #define NRF_UARTE_SUBSCRIBE_CONF_OFFS offsetof(NRF_UARTE_Type, SUBSCRIBE_STARTRX) #define NRF_UARTE_SUBSCRIBE_CONF_SIZE (offsetof(NRF_UARTE_Type, EVENTS_CTS) -\ NRF_UARTE_SUBSCRIBE_CONF_OFFS) @@ -45,23 +37,6 @@ static inline void nrf_cleanup_rtc(NRF_RTC_Type * rtc_reg) } #endif -#if defined(NRF_UARTE_CLEANUP) -static NRF_UARTE_Type *nrf_uarte_to_clean[] = { -#if defined(NRF_UARTE0) - NRF_UARTE0, -#endif -#if defined(NRF_UARTE1) - NRF_UARTE1, -#endif -#if defined(NRF_UARTE20) - NRF_UARTE20, -#endif -#if defined(NRF_UARTE30) - NRF_UARTE30, -#endif -}; -#endif - static void nrf_cleanup_clock(void) { nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); @@ -78,31 +53,26 @@ void nrf_cleanup_peripheral(void) #if defined(NRF_RTC2) nrf_cleanup_rtc(NRF_RTC2); #endif - -#if defined(NRF_UARTE_CLEANUP) - for (int i = 0; i < sizeof(nrf_uarte_to_clean) / sizeof(nrf_uarte_to_clean[0]); ++i) { - NRF_UARTE_Type *current = nrf_uarte_to_clean[i]; - - nrfy_uarte_int_disable(current, 0xFFFFFFFF); - nrfy_uarte_int_uninit(current); - nrfy_uarte_task_trigger(current, NRF_UARTE_TASK_STOPRX); - - nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_RXSTARTED); - nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_ENDRX); - nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_RXTO); - nrfy_uarte_disable(current); - +#if defined(NRF_UARTE0) + nrf_uarte_disable(NRF_UARTE0); + nrf_uarte_int_disable(NRF_UARTE0, 0xFFFFFFFF); #if defined(NRF_DPPIC) - /* Clear all SUBSCRIBE configurations. */ - memset((uint8_t *)current + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, - NRF_UARTE_SUBSCRIBE_CONF_SIZE); - /* Clear all PUBLISH configurations. */ - memset((uint8_t *)current + NRF_UARTE_PUBLISH_CONF_OFFS, 0, - NRF_UARTE_PUBLISH_CONF_SIZE); + /* Clear all SUBSCRIBE configurations. */ + memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); + /* Clear all PUBLISH configurations. */ + memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); +#endif +#endif +#if defined(NRF_UARTE1) + nrf_uarte_disable(NRF_UARTE1); + nrf_uarte_int_disable(NRF_UARTE1, 0xFFFFFFFF); +#if defined(NRF_DPPIC) + /* Clear all SUBSCRIBE configurations. */ + memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); + /* Clear all PUBLISH configurations. */ + memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); #endif - } #endif - #if defined(NRF_PPI) nrf_ppi_channels_disable_all(NRF_PPI); #endif @@ -111,12 +81,3 @@ void nrf_cleanup_peripheral(void) #endif nrf_cleanup_clock(); } - -#if USE_PARTITION_MANAGER \ - && defined(CONFIG_ARM_TRUSTZONE_M) \ - && defined(PM_SRAM_NONSECURE_NAME) -void nrf_cleanup_ns_ram(void) -{ - memset((void *) PM_SRAM_NONSECURE_ADDRESS, 0, PM_SRAM_NONSECURE_SIZE); -} -#endif From 62d6ffb0a639b5fec68ee189e3fd83f078910a7d Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 071/149] Revert "[nrf noup] zephyr: clean peripherals state before boot" This reverts commit d6a003b8ebce039fb9bff4e8571cc59f159aa4a4. Signed-off-by: Tomasz Chyrowicz --- boot/zephyr/CMakeLists.txt | 6 --- boot/zephyr/include/nrf_cleanup.h | 19 ------- boot/zephyr/main.c | 8 +-- boot/zephyr/nrf_cleanup.c | 83 ------------------------------- 4 files changed, 1 insertion(+), 115 deletions(-) delete mode 100644 boot/zephyr/include/nrf_cleanup.h delete mode 100644 boot/zephyr/nrf_cleanup.c diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index a1e0679c4..8412ebd43 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -753,9 +753,3 @@ if(SYSBUILD) set(mcuboot_image_footer_size ${required_size} CACHE INTERNAL "Estimated MCUboot image trailer size" FORCE) set(mcuboot_image_upgrade_footer_size ${required_upgrade_size} CACHE INTERNAL "Estimated MCUboot update image trailer size" FORCE) endif() - -if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL) -zephyr_library_sources( - ${BOOT_DIR}/zephyr/nrf_cleanup.c -) -endif() diff --git a/boot/zephyr/include/nrf_cleanup.h b/boot/zephyr/include/nrf_cleanup.h deleted file mode 100644 index 6b04cedfe..000000000 --- a/boot/zephyr/include/nrf_cleanup.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#ifndef H_NRF_CLEANUP_ -#define H_NRF_CLEANUP_ - -/** - * Perform cleanup on some peripheral resources used by MCUBoot prior chainload - * the application. - * - * This function disables all RTC instances and UARTE instances. - * It Disables their interrupts signals as well. - */ -void nrf_cleanup_peripheral(void); - -#endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 2f39bbabe..b41a9c4d4 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -149,10 +149,6 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #include #endif -#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL -#include -#endif - BOOT_LOG_MODULE_REGISTER(mcuboot); void os_heap_init(void); @@ -227,9 +223,7 @@ static void do_boot(struct boot_rsp *rsp) } #endif #endif -#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL - nrf_cleanup_peripheral(); -#endif + #if CONFIG_MCUBOOT_CLEANUP_ARM_CORE cleanup_arm_interrupts(); /* Disable and acknowledge all interrupts */ diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c deleted file mode 100644 index 5bab26b24..000000000 --- a/boot/zephyr/nrf_cleanup.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2020 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#include -#if defined(NRF_UARTE0) || defined(NRF_UARTE1) - #include -#endif -#if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) - #include -#endif -#if defined(NRF_PPI) - #include -#endif -#if defined(NRF_DPPIC) - #include -#endif - -#include - -#define NRF_UARTE_SUBSCRIBE_CONF_OFFS offsetof(NRF_UARTE_Type, SUBSCRIBE_STARTRX) -#define NRF_UARTE_SUBSCRIBE_CONF_SIZE (offsetof(NRF_UARTE_Type, EVENTS_CTS) -\ - NRF_UARTE_SUBSCRIBE_CONF_OFFS) - -#define NRF_UARTE_PUBLISH_CONF_OFFS offsetof(NRF_UARTE_Type, PUBLISH_CTS) -#define NRF_UARTE_PUBLISH_CONF_SIZE (offsetof(NRF_UARTE_Type, SHORTS) -\ - NRF_UARTE_PUBLISH_CONF_OFFS) - -#if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) -static inline void nrf_cleanup_rtc(NRF_RTC_Type * rtc_reg) -{ - nrf_rtc_task_trigger(rtc_reg, NRF_RTC_TASK_STOP); - nrf_rtc_event_disable(rtc_reg, 0xFFFFFFFF); - nrf_rtc_int_disable(rtc_reg, 0xFFFFFFFF); -} -#endif - -static void nrf_cleanup_clock(void) -{ - nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); -} - -void nrf_cleanup_peripheral(void) -{ -#if defined(NRF_RTC0) - nrf_cleanup_rtc(NRF_RTC0); -#endif -#if defined(NRF_RTC1) - nrf_cleanup_rtc(NRF_RTC1); -#endif -#if defined(NRF_RTC2) - nrf_cleanup_rtc(NRF_RTC2); -#endif -#if defined(NRF_UARTE0) - nrf_uarte_disable(NRF_UARTE0); - nrf_uarte_int_disable(NRF_UARTE0, 0xFFFFFFFF); -#if defined(NRF_DPPIC) - /* Clear all SUBSCRIBE configurations. */ - memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); - /* Clear all PUBLISH configurations. */ - memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); -#endif -#endif -#if defined(NRF_UARTE1) - nrf_uarte_disable(NRF_UARTE1); - nrf_uarte_int_disable(NRF_UARTE1, 0xFFFFFFFF); -#if defined(NRF_DPPIC) - /* Clear all SUBSCRIBE configurations. */ - memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); - /* Clear all PUBLISH configurations. */ - memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); -#endif -#endif -#if defined(NRF_PPI) - nrf_ppi_channels_disable_all(NRF_PPI); -#endif -#if defined(NRF_DPPIC) - nrf_dppi_channels_disable_all(NRF_DPPIC); -#endif - nrf_cleanup_clock(); -} From 22a3b04e390d8456219788a1adba3383de65b977 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 072/149] Revert "[nrf noup] boot: nrf53-specific customizations" This reverts commit 7f1fb0c77a823c3824d5fa640f29c8bd28aaeeb5. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 96 +++++-------------- .../boards/thingy53_nrf5340_cpuapp.conf | 74 +------------- boot/zephyr/include/sysflash/sysflash.h | 23 ----- boot/zephyr/main.c | 25 +---- boot/zephyr/pm.yml | 13 --- 5 files changed, 30 insertions(+), 201 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 281e65f45..952099fc4 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -50,10 +50,6 @@ #include "bootutil/boot_hooks.h" #include "bootutil/mcuboot_status.h" -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) -#include -#endif - #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -1077,15 +1073,7 @@ boot_validated_swap_type(struct boot_loader_state *state, { int swap_type; FIH_DECLARE(fih_rc, FIH_FAILURE); - bool upgrade_valid = false; - -#if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) - const struct flash_area *secondary_fa = - BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); - struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; - uint32_t vtable_addr = 0; - uint32_t *vtable = 0; - uint32_t reset_addr = 0; +#ifdef PM_S1_ADDRESS /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other * B1 slot S0 or S1) share the same secondary slot, we need to check * whether the update candidate in the secondary slot is intended for @@ -1093,36 +1081,34 @@ boot_validated_swap_type(struct boot_loader_state *state, * vector. Note that there are good reasons for not using img_num from * the swap info. */ + const struct flash_area *secondary_fa = + BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); + struct image_header *hdr = + (struct image_header *)secondary_fa->fa_off; if (hdr->ih_magic == IMAGE_MAGIC) { - vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; - vtable = (uint32_t *)(vtable_addr); - reset_addr = vtable[1]; -#ifdef PM_S1_ADDRESS -#ifdef PM_CPUNET_B0N_ADDRESS - if(reset_addr < PM_CPUNET_B0N_ADDRESS) -#endif - { - const struct flash_area *primary_fa; - int rc = flash_area_open(flash_area_id_from_multi_image_slot( - BOOT_CURR_IMG(state), - BOOT_PRIMARY_SLOT), - &primary_fa); - - if (rc != 0) { - return BOOT_SWAP_TYPE_FAIL; - } - /* Get start and end of primary slot for current image */ - 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 this image - */ - return BOOT_SWAP_TYPE_NONE; - } - } -#endif /* PM_S1_ADDRESS */ + const struct flash_area *primary_fa; + uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; + uint32_t *vtable = (uint32_t *)(vtable_addr); + uint32_t reset_addr = vtable[1]; + int rc = flash_area_open( + flash_area_id_from_multi_image_slot( + BOOT_CURR_IMG(state), + BOOT_PRIMARY_SLOT), + &primary_fa); + + if (rc != 0) { + return BOOT_SWAP_TYPE_FAIL; + } + /* Get start and end of primary slot for current image */ + 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 this image + */ + return BOOT_SWAP_TYPE_NONE; + } } -#endif /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ +#endif swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -1136,37 +1122,7 @@ boot_validated_swap_type(struct boot_loader_state *state, } else { swap_type = BOOT_SWAP_TYPE_FAIL; } - } else { - upgrade_valid = true; - } - -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) - /* If the update is valid, and it targets the network core: perform the - * update and indicate to the caller of this function that no update is - * available - */ - if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) { - uint32_t fw_size = hdr->ih_img_size; - - BOOT_LOG_INF("Starting network core update"); - int rc = pcd_network_core_update(vtable, fw_size); - - if (rc != 0) { - swap_type = BOOT_SWAP_TYPE_FAIL; - } else { - BOOT_LOG_INF("Done updating network core"); -#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) - /* swap_erase_trailer_sectors is undefined if upgrade only - * method is used. There is no need to erase sectors, because - * the image cannot be reverted. - */ - rc = swap_erase_trailer_sectors(state, - secondary_fa); -#endif - swap_type = BOOT_SWAP_TYPE_NONE; - } } -#endif /* CONFIG_SOC_NRF5340_CPUAPP */ } return swap_type; diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index 93be36738..f2e42fd64 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -1,73 +1,3 @@ -CONFIG_SIZE_OPTIMIZATIONS=y - -CONFIG_SYSTEM_CLOCK_NO_WAIT=y -CONFIG_PM=n - -CONFIG_MAIN_STACK_SIZE=10240 -CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" - -CONFIG_BOOT_MAX_IMG_SECTORS=2048 -CONFIG_BOOT_SIGNATURE_TYPE_RSA=y - -# Flash -CONFIG_FLASH=y -CONFIG_BOOT_ERASE_PROGRESSIVELY=y -CONFIG_SOC_FLASH_NRF_EMULATE_ONE_BYTE_WRITE_ACCESS=y -CONFIG_FPROTECT=y - -# Serial -CONFIG_SERIAL=y -CONFIG_UART_LINE_CTRL=y - -# MCUBoot serial -CONFIG_GPIO=y -CONFIG_MCUBOOT_SERIAL=y -CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y -CONFIG_BOOT_SERIAL_CDC_ACM=y - -# Required by QSPI -CONFIG_NORDIC_QSPI_NOR=y -CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 -CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16 - -# Required by USB -CONFIG_MULTITHREADING=y - -# USB -CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n -CONFIG_USB_DEVICE_REMOTE_WAKEUP=n -CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor ASA" -CONFIG_USB_DEVICE_PRODUCT="Bootloader Thingy:53" -CONFIG_USB_DEVICE_VID=0x1915 -CONFIG_USB_DEVICE_PID=0x5300 -CONFIG_USB_CDC_ACM=y - -# Decrease memory footprint -CONFIG_CBPRINTF_NANO=y -CONFIG_TIMESLICING=n -CONFIG_BOOT_BANNER=n -CONFIG_CONSOLE=n -CONFIG_CONSOLE_HANDLER=n -CONFIG_UART_CONSOLE=n -CONFIG_USE_SEGGER_RTT=n -CONFIG_LOG=n -CONFIG_ERRNO=n -CONFIG_PRINTK=n -CONFIG_RESET_ON_FATAL_ERROR=n +CONFIG_NORDIC_QSPI_NOR=n CONFIG_SPI=n -CONFIG_I2C=n -CONFIG_UART_NRFX=n - -# The following configurations are required to support simultaneous multi image update -CONFIG_PCD_APP=y -CONFIG_UPDATEABLE_IMAGE_NUMBER=2 -CONFIG_BOOT_UPGRADE_ONLY=y -# The network core cannot access external flash directly. The flash simulator must be used to -# provide a memory region that is used to forward the new firmware to the network core. -CONFIG_FLASH_SIMULATOR=y -CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y -CONFIG_FLASH_SIMULATOR_STATS=n - -# Enable custom command to erase settings partition. -CONFIG_ENABLE_MGMT_PERUSER=y -CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE=y +CONFIG_MULTITHREADING=y diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index 7112f9baa..99cbf56b7 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -20,11 +20,6 @@ #elif (MCUBOOT_IMAGE_NUMBER == 2) -/* If B0 is present then two bootloaders are present, and we must use - * a single secondary slot for both primary slots. - */ -#ifdef PM_B0_ADDRESS - extern uint32_t _image_1_primary_slot_id[]; #define FLASH_AREA_IMAGE_PRIMARY(x) \ @@ -40,24 +35,6 @@ extern uint32_t _image_1_primary_slot_id[]; (x == 1) ? \ PM_MCUBOOT_SECONDARY_ID: \ 255 ) -#else - -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) - -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) - -#endif /* PM_B0_ADDRESS */ - #endif #define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index b41a9c4d4..e9a4e20b0 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -98,26 +98,8 @@ const struct boot_uart_funcs boot_funcs = { #include #endif -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) -#include -#endif - -/* CONFIG_LOG_MINIMAL is the legacy Kconfig property, - * replaced by CONFIG_LOG_MODE_MINIMAL. - */ -#if (defined(CONFIG_LOG_MODE_MINIMAL) || defined(CONFIG_LOG_MINIMAL)) -#define ZEPHYR_LOG_MODE_MINIMAL 1 -#endif - -/* CONFIG_LOG_IMMEDIATE is the legacy Kconfig property, - * replaced by CONFIG_LOG_MODE_IMMEDIATE. - */ -#if (defined(CONFIG_LOG_MODE_IMMEDIATE) || defined(CONFIG_LOG_IMMEDIATE)) -#define ZEPHYR_LOG_MODE_IMMEDIATE 1 -#endif - -#if defined(CONFIG_LOG) && !defined(ZEPHYR_LOG_MODE_IMMEDIATE) && \ - !defined(ZEPHYR_LOG_MODE_MINIMAL) +#if defined(CONFIG_LOG) && !defined(CONFIG_LOG_MODE_IMMEDIATE) && \ + !defined(CONFIG_LOG_MODE_MINIMAL) #ifdef CONFIG_LOG_PROCESS_THREAD #warning "The log internal thread for log processing can't transfer the log"\ "well for MCUBoot." @@ -734,9 +716,6 @@ int main(void) ; } -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) - pcd_lock_ram(); -#endif #endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */ ZEPHYR_BOOT_LOG_STOP(); diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml index 13ffc44aa..5df9ae547 100644 --- a/boot/zephyr/pm.yml +++ b/boot/zephyr/pm.yml @@ -75,16 +75,3 @@ mcuboot_pad: #ifdef CONFIG_FPROTECT align: {start: CONFIG_FPROTECT_BLOCK_SIZE} #endif - -#if (CONFIG_NRF53_MCUBOOT_PRIMARY_1_RAM_FLASH) -mcuboot_primary_1: - region: ram_flash - size: CONFIG_NRF53_RAM_FLASH_SIZE -#endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ - -#if (CONFIG_NRF53_MULTI_IMAGE_UPDATE) -mcuboot_secondary_1: - region: external_flash - size: CONFIG_NRF53_RAM_FLASH_SIZE - -#endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ From 5e225c4ab4cfec646ecb20e54e62c71551e63b97 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 23 Oct 2025 19:17:55 +0200 Subject: [PATCH 073/149] Revert "[nrf noup] treewide: add NCS partition manager support" This reverts commit 008144597fd759be49af8eed7dd837b1f07f68f0. Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/src/loader.c | 95 +++---------------------- boot/bootutil/src/swap_move.c | 13 ---- boot/bootutil/src/swap_scratch.c | 13 ---- boot/zephyr/CMakeLists.txt | 7 -- boot/zephyr/Kconfig | 2 - boot/zephyr/include/sysflash/sysflash.h | 48 ------------- boot/zephyr/include/target.h | 4 -- boot/zephyr/main.c | 45 ------------ boot/zephyr/pm.yml | 77 -------------------- ext/nrf/cc310_glue.h | 2 +- zephyr/module.yml | 3 +- 11 files changed, 11 insertions(+), 298 deletions(-) delete mode 100644 boot/zephyr/pm.yml diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 952099fc4..46ddf5b78 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -129,15 +129,6 @@ 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 - /* 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) { - continue; - } -#endif /* PM_S1_ADDRESS */ if (i > 0 && !require_all) { return 0; } else { @@ -980,24 +971,7 @@ 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) { - min_addr = PM_CPUNET_APP_ADDRESS; - max_addr = PM_CPUNET_APP_ADDRESS + PM_CPUNET_APP_SIZE; - } else -#endif - { - min_addr = pri_fa->fa_off; - max_addr = pri_fa->fa_off + pri_fa->fa_size; - } - - if (reset_value < min_addr || reset_value> (max_addr)) { + if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) { BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot"); BOOT_LOG_ERR("Erasing image from secondary slot"); @@ -1073,42 +1047,6 @@ boot_validated_swap_type(struct boot_loader_state *state, { int swap_type; FIH_DECLARE(fih_rc, FIH_FAILURE); -#ifdef PM_S1_ADDRESS - /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other - * B1 slot S0 or S1) share the same secondary slot, we need to check - * whether the update candidate in the secondary slot is intended for - * image 0 or image 1 primary by looking at the address of the reset - * vector. Note that there are good reasons for not using img_num from - * the swap info. - */ - const struct flash_area *secondary_fa = - BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); - struct image_header *hdr = - (struct image_header *)secondary_fa->fa_off; - - if (hdr->ih_magic == IMAGE_MAGIC) { - const struct flash_area *primary_fa; - uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; - uint32_t *vtable = (uint32_t *)(vtable_addr); - uint32_t reset_addr = vtable[1]; - int rc = flash_area_open( - flash_area_id_from_multi_image_slot( - BOOT_CURR_IMG(state), - BOOT_PRIMARY_SLOT), - &primary_fa); - - if (rc != 0) { - return BOOT_SWAP_TYPE_FAIL; - } - /* Get start and end of primary slot for current image */ - 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 this image - */ - return BOOT_SWAP_TYPE_NONE; - } - } -#endif swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -2421,25 +2359,15 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT -#ifdef PM_S1_ADDRESS - /* Patch needed for NCS. Image 1 primary is the currently - * executing MCUBoot image, and is therefore already validated by NSIB and - * does not need to also be validated by MCUBoot. + FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SLOT_PRIMARY, NULL, 0); + /* Check for all possible values is redundant in normal operation it + * is meant to prevent FI attack. */ - bool image_validated_by_nsib = BOOT_CURR_IMG(state) == 1; - if (!image_validated_by_nsib) -#endif - { - FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL, 0); - /* Check for all possible values is redundant in normal operation it - * is meant to prevent FI attack. - */ - if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS) || - FIH_EQ(fih_rc, FIH_FAILURE) || - FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) { - FIH_SET(fih_rc, FIH_FAILURE); - goto out; - } + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS) || + FIH_EQ(fih_rc, FIH_FAILURE) || + FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) { + FIH_SET(fih_rc, FIH_FAILURE); + goto out; } #else /* Even if we're not re-validating the primary slot, we could be booting @@ -2456,16 +2384,11 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } #endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */ -#ifdef PM_S1_ADDRESS - if (!image_validated_by_nsib) -#endif - { rc = boot_update_hw_rollback_protection(state); if (rc != 0) { FIH_SET(fih_rc, FIH_FAILURE); goto out; } - } rc = boot_add_shared_data(state, BOOT_SLOT_PRIMARY); if (rc != 0) { diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index 75dadfe91..88a117f59 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -230,18 +230,6 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz) int boot_slots_compatible(struct boot_loader_state *state) { -#ifdef PM_S1_ADDRESS - /* Patch needed for NCS. In this case, image 1 primary points to the other - * B1 slot (ie S0 or S1), and image 0 primary points to the app. - * With this configuration, image 0 and image 1 share the secondary slot. - * Hence, the primary slot of image 1 will be *smaller* than image 1's - * secondary slot. This is not allowed in upstream mcuboot, so we need - * this patch to allow it. Also, all of these checks are redundant when - * partition manager is in use, and since we have the same sector size - * in all of our flash. - */ - return 1; -#else size_t num_sectors_pri; size_t num_sectors_sec; size_t sector_sz_pri = 0; @@ -307,7 +295,6 @@ boot_slots_compatible(struct boot_loader_state *state) } return 1; -#endif /* PM_S1_ADDRESS */ } #define BOOT_LOG_SWAP_STATE(area, state) \ diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c index f01f407b2..0a994d862 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -271,18 +271,6 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz) int boot_slots_compatible(struct boot_loader_state *state) { -#ifdef PM_S1_ADDRESS - /* Patch needed for NCS. In this case, image 1 primary points to the other - * B1 slot (ie S0 or S1), and image 0 primary points to the app. - * With this configuration, image 0 and image 1 share the secondary slot. - * Hence, the primary slot of image 1 will be *smaller* than image 1's - * secondary slot. This is not allowed in upstream mcuboot, so we need - * this patch to allow it. Also, all of these checks are redundant when - * partition manager is in use, and since we have the same sector size - * in all of our flash. - */ - return 1; -#else size_t num_sectors_primary; size_t num_sectors_secondary; size_t sz0, sz1; @@ -380,7 +368,6 @@ boot_slots_compatible(struct boot_loader_state *state) #endif return 1; -#endif /* PM_S1_ADDRESS */ } #define BOOT_LOG_SWAP_STATE(area, state) \ diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 8412ebd43..0bf92c477 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -373,13 +373,6 @@ if(NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") endif() message("MCUBoot bootloader key file: ${KEY_FILE}") - set_property( - GLOBAL - PROPERTY - KEY_FILE - ${KEY_FILE} - ) - set(mcuboot_default_signature_files ${MCUBOOT_DIR}/root-ec-p256-pkcs8.pem ${MCUBOOT_DIR}/root-ec-p384.pem diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index edbeeb6be..b55564c3b 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -9,8 +9,6 @@ mainmenu "MCUboot configuration" comment "MCUboot-specific configuration options" -source "$(ZEPHYR_NRF_MODULE_DIR)/modules/mcuboot/boot/zephyr/Kconfig" - # Hidden option to mark a project as MCUboot config MCUBOOT default y diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index 99cbf56b7..16d222280 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -7,52 +7,6 @@ #ifndef __SYSFLASH_H__ #define __SYSFLASH_H__ -#if USE_PARTITION_MANAGER -#include -#include - -#ifndef CONFIG_SINGLE_APPLICATION_SLOT - -#if (MCUBOOT_IMAGE_NUMBER == 1) - -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID - -#elif (MCUBOOT_IMAGE_NUMBER == 2) - -extern uint32_t _image_1_primary_slot_id[]; - -#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 ) -#endif -#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID - -#else /* CONFIG_SINGLE_APPLICATION_SLOT */ - -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID -/* NOTE: Scratch parition is not used by single image DFU but some of - * functions in common files reference it, so the definitions has been - * provided to allow compilation of common units. - */ -#define FLASH_AREA_IMAGE_SCRATCH 0 - -#endif /* CONFIG_SINGLE_APPLICATION_SLOT */ - -#else - -#include #include #include #include @@ -111,6 +65,4 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #endif /* CONFIG_SINGLE_APPLICATION_SLOT */ -#endif /* USE_PARTITION_MANAGER */ - #endif /* __SYSFLASH_H__ */ diff --git a/boot/zephyr/include/target.h b/boot/zephyr/include/target.h index 856686785..ea160752e 100644 --- a/boot/zephyr/include/target.h +++ b/boot/zephyr/include/target.h @@ -8,8 +8,6 @@ #ifndef H_TARGETS_TARGET_ #define H_TARGETS_TARGET_ -#ifndef USE_PARTITION_MANAGER - #if defined(MCUBOOT_TARGET_CONFIG) /* * Target-specific definitions are permitted in legacy cases that @@ -49,6 +47,4 @@ #error "Target support is incomplete; cannot build mcuboot." #endif -#endif /* ifndef USE_PARTITION_MANAGER */ - #endif /* H_TARGETS_TARGET_ */ diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index e9a4e20b0..1494002e7 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -76,10 +76,6 @@ #endif /* CONFIG_SOC_FAMILY_ESPRESSIF_ESP32 */ -#ifdef CONFIG_FW_INFO -#include -#endif - #ifdef CONFIG_MCUBOOT_SERIAL #include "boot_serial/boot_serial.h" #include "serial_adapter/serial_adapter.h" @@ -126,11 +122,6 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); * !defined(CONFIG_LOG_MODE_MINIMAL) */ -#if USE_PARTITION_MANAGER && CONFIG_FPROTECT -#include -#include -#endif - BOOT_LOG_MODULE_REGISTER(mcuboot); void os_heap_init(void); @@ -193,19 +184,6 @@ static void do_boot(struct boot_rsp *rsp) /* Disable the USB to prevent it from firing interrupts */ usb_disable(); #endif - -#if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED) - bool provided = fw_info_ext_api_provide(fw_info_find((uint32_t)vt), true); - -#ifdef PM_S0_ADDRESS - /* Only fail if the immutable bootloader is present. */ - if (!provided) { - BOOT_LOG_ERR("Failed to provide EXT_APIs\n"); - return; - } -#endif -#endif - #if CONFIG_MCUBOOT_CLEANUP_ARM_CORE cleanup_arm_interrupts(); /* Disable and acknowledge all interrupts */ @@ -696,30 +674,7 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND); -#if USE_PARTITION_MANAGER && CONFIG_FPROTECT - -#ifdef PM_S1_ADDRESS -/* MCUBoot is stored in either S0 or S1, protect both */ -#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_S0_ADDRESS) -#define PROTECT_ADDR PM_S0_ADDRESS -#else -/* There is only one instance of MCUBoot */ -#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_MCUBOOT_ADDRESS) -#define PROTECT_ADDR PM_MCUBOOT_ADDRESS -#endif - - rc = fprotect_area(PROTECT_ADDR, PROTECT_SIZE); - - if (rc != 0) { - BOOT_LOG_ERR("Protect mcuboot flash failed, cancel startup."); - while (1) - ; - } - -#endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */ - ZEPHYR_BOOT_LOG_STOP(); - do_boot(&rsp); mcuboot_status_change(MCUBOOT_STATUS_BOOT_FAILED); diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml deleted file mode 100644 index 5df9ae547..000000000 --- a/boot/zephyr/pm.yml +++ /dev/null @@ -1,77 +0,0 @@ -#include - -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 - # partition - span: [app] - -mcuboot_primary: - span: [mcuboot_pad, mcuboot_primary_app] - -# Partition for secondary slot is not created if building in single application -# slot configuration. -#if !defined(CONFIG_SINGLE_APPLICATION_SLOT) && !defined(CONFIG_BOOT_DIRECT_XIP) -mcuboot_secondary: - share_size: [mcuboot_primary] -#if defined(CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY) - region: external_flash - placement: - align: {start: 4} -#else - placement: - align: {start: CONFIG_FPROTECT_BLOCK_SIZE} - align_next: CONFIG_FPROTECT_BLOCK_SIZE # Ensure that the next partition does not interfere with this image - after: mcuboot_primary -#endif /* CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY */ - -#endif /* !defined(CONFIG_SINGLE_APPLICATION_SLOT) && !defined(CONFIG_BOOT_DIRECT_XIP) */ - -#if CONFIG_BOOT_DIRECT_XIP - -# Direct XIP is enabled, reserve area for metadata (padding) and name the -# partition so that its clear that it is not the secondary slot, but the direct -# XIP alternative. - -mcuboot_secondary_pad: - share_size: mcuboot_pad - placement: - after: mcuboot_primary - align: {start: CONFIG_FPROTECT_BLOCK_SIZE} - -mcuboot_secondary_app: - share_size: mcuboot_primary_app - placement: - after: mcuboot_secondary_pad - -mcuboot_secondary: - span: [mcuboot_secondary_pad, mcuboot_secondary_app] - -#endif /* CONFIG_BOOT_DIRECT_XIP */ - -#if CONFIG_BOOT_SWAP_USING_SCRATCH -mcuboot_scratch: - size: CONFIG_PM_PARTITION_SIZE_MCUBOOT_SCRATCH - placement: - after: app - align: {start: CONFIG_FPROTECT_BLOCK_SIZE} -#endif /* CONFIG_BOOT_SWAP_USING_SCRATCH */ - -# Padding placed before image to boot. This reserves space for the MCUboot image header -# and it ensures that the boot image gets linked with the correct address offset in flash. -mcuboot_pad: - # MCUboot pad must be placed before the primary application partition. - # The primary application partition includes the secure firmware if present. - size: CONFIG_PM_PARTITION_SIZE_MCUBOOT_PAD - placement: - before: [mcuboot_primary_app] -#ifdef CONFIG_FPROTECT - align: {start: CONFIG_FPROTECT_BLOCK_SIZE} -#endif diff --git a/ext/nrf/cc310_glue.h b/ext/nrf/cc310_glue.h index 22eb94911..ed3ed5c00 100644 --- a/ext/nrf/cc310_glue.h +++ b/ext/nrf/cc310_glue.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include /* diff --git a/zephyr/module.yml b/zephyr/module.yml index 65af58bb5..7a80d166f 100644 --- a/zephyr/module.yml +++ b/zephyr/module.yml @@ -1,8 +1,7 @@ samples: - boot/zephyr build: - cmake-ext: True - kconfig-ext: True + cmake: ./boot/bootutil/zephyr sysbuild-cmake: boot/zephyr/sysbuild package-managers: pip: From 676fea85a0cfa032dbcd03363f0fd1f65f96eb84 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 7 Oct 2025 13:52:10 +0000 Subject: [PATCH 074/149] [nrf fromtree] bootutil: Add MCUBOOT_CHECK_HEADER_LOAD_ADDRESS Adding MCUBOOT_CHECK_HEADER_LOAD_ADDRESS that allows to verify header stored ih_load_addr against target boot slot, to allow MCUboot to reject firmware uploaded for incorrect slot. This option works with encrypted software, as it does not require decrypting image. This option takes precedence over MCUBOOT_VERIFY_IMG_ADDRESS. Note that the change leaves MCUBOOT_VERIFY_IMG_ADDRESS with the bug reported here https://github.com/mcu-tools/mcuboot/issues/2473. This commit also removes dependency on having more then one image to have the check enabled, as it makes no point to block using it on single image. Co-authored-by: Andrzej Puzdrowski Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 1035cc01e19f3665aacb1c327e349db561cfe0d4) --- boot/bootutil/src/loader.c | 39 +++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 46ddf5b78..2448835be 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -81,6 +81,13 @@ static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0}; #define TARGET_STATIC #endif +#if defined(MCUBOOT_VERIFY_IMG_ADDRESS) && defined(MCUBOOT_CHECK_HEADER_LOAD_ADDRESS) +#warning MCUBOOT_CHECK_HEADER_LOAD_ADDRESS takes precedence over MCUBOOT_VERIFY_IMG_ADDRESS +#endif + +/* Valid only for ARM Cortext M */ +#define RESET_OFFSET (2 * sizeof(uin32_t)) + #if BOOT_MAX_ALIGN > 1024 #define BUF_SZ BOOT_MAX_ALIGN #else @@ -954,25 +961,43 @@ boot_validate_slot(struct boot_loader_state *state, int slot, goto out; } -#if MCUBOOT_IMAGE_NUMBER > 1 && !defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_VERIFY_IMG_ADDRESS) +#if defined(MCUBOOT_VERIFY_IMG_ADDRESS) && !defined(MCUBOOT_ENC_IMAGES) || \ + defined(MCUBOOT_CHECK_HEADER_LOAD_ADDRESS) /* Verify that the image in the secondary slot has a reset address * located in the primary slot. This is done to avoid users incorrectly * overwriting an application written to the incorrect slot. * This feature is only supported by ARM platforms. */ if (fap == BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY)) { - const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY); 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 internal_img_addr = 0; /* either the reset handler addres or the image beginning addres */ + uint32_t min_addr; + uint32_t max_addr; + + min_addr = flash_area_get_off(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); + max_addr = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)) + min_addr; - if (flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value)) != 0) { +/* MCUBOOT_CHECK_HEADER_LOAD_ADDRESS takes priority over MCUBOOT_VERIFY_IMG_ADDRESS */ +#ifdef MCUBOOT_CHECK_HEADER_LOAD_ADDRESS + internal_img_addr = secondary_hdr->ih_load_addr; +#else + /* This is platform specific code that should not be here */ + const uint32_t offset = secondary_hdr->ih_hdr_size + RESET_OFFSET; + BOOT_LOG_DBG("Getting image %d internal addr from offset %u", + BOOT_CURR_IMG(state), offset); + if (flash_area_read(fap, offset, &internal_img_addr, sizeof(internal_img_addr)) != 0) + BOOT_LOG_ERR("Failed to read image %d load address", BOOT_CURR_IMG(state)); fih_rc = FIH_NO_BOOTABLE_IMAGE; goto out; } +#endif - if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) { - BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot"); + BOOT_LOG_DBG("Image %d expected load address 0x%x", BOOT_CURR_IMG(state), internal_img_addr); + BOOT_LOG_DBG("Check 0x%x is within [min_addr, max_addr] = [0x%x, 0x%x)", + internal_img_addr, min_addr, max_addr); + if (internal_img_addr < min_addr || internal_img_addr >= max_addr) { + BOOT_LOG_ERR("Binary in secondary slot of image %d is not designated for the primary slot", + BOOT_CURR_IMG(state)); BOOT_LOG_ERR("Erasing image from secondary slot"); /* The vector table in the image located in the secondary From f5c9d09249e6c9a35c4f2603ef827b4c3844ef0f Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 7 Oct 2025 14:00:24 +0000 Subject: [PATCH 075/149] [nrf fromtree] zephyr: Added MCUBOOT_CHECK_HEADER_LOAD_ADDRESS Kconfig Allows to enable MCUboot config MCUBOOT_CHECK_HEADER_LOAD_ADDRESS. Co-authored-by: Andrzej Puzdrowski Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit fd2c14287500bcc50091a4014e14a01f7294b5a9) --- boot/zephyr/Kconfig | 8 ++++++++ boot/zephyr/include/mcuboot_config/mcuboot_config.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index b55564c3b..487f81d47 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1312,6 +1312,14 @@ config USB_DEVICE_PRODUCT config MCUBOOT_BOOTUTIL_LIB_OWN_LOG bool +config MCUBOOT_CHECK_HEADER_LOAD_ADDRESS + bool "Use load address to verify application is in proper slot" + help + The bootloader will use the load address, from the image header, + to verify that binary is in slot designated for its execution. + When not selected reset vector, read from image, is used for + the same purpose. + config MCUBOOT_VERIFY_IMG_ADDRESS bool "Verify reset address of image in secondary slot" depends on UPDATEABLE_IMAGE_NUMBER > 1 diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 5062d02fd..c12ff9028 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -305,6 +305,10 @@ #define MCUBOOT_FIND_NEXT_SLOT_HOOKS #endif +#ifdef CONFIG_MCUBOOT_CHECK_HEADER_LOAD_ADDRESS +#define MCUBOOT_CHECK_HEADER_LOAD_ADDRESS +#endif + #ifdef CONFIG_MCUBOOT_VERIFY_IMG_ADDRESS #define MCUBOOT_VERIFY_IMG_ADDRESS #endif From c3848d43343d38868898654fe5354b267852a1c6 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 8 Oct 2025 13:07:00 +0000 Subject: [PATCH 076/149] [nrf fromtree] sim: Parametrize make_bad_secondary_slot_image Add ImageManipulation parameter to the function to allow creating images broken in various ways. Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit ef4a5aba2a4be4f0aec4e2c65c7fadad3968b289) --- sim/src/image.rs | 4 ++-- sim/src/lib.rs | 2 +- sim/tests/core.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sim/src/image.rs b/sim/src/image.rs index 9703714b3..846783a06 100644 --- a/sim/src/image.rs +++ b/sim/src/image.rs @@ -297,7 +297,7 @@ impl ImagesBuilder { images } - pub fn make_bad_secondary_slot_image(self) -> Images { + pub fn make_bad_secondary_slot_image(self, img_manipulation : ImageManipulation) -> Images { let mut bad_flash = self.flash; let ram = self.ram.clone(); // TODO: Avoid this clone. let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| { @@ -305,7 +305,7 @@ impl ImagesBuilder { let primaries = install_image(&mut bad_flash, &self.areadesc, &slots, 0, maximal(32784), &ram, &dep, ImageManipulation::None, Some(0)); let upgrades = install_image(&mut bad_flash, &self.areadesc, &slots, 1, - maximal(41928), &ram, &dep, ImageManipulation::BadSignature, Some(0)); + maximal(41928), &ram, &dep, img_manipulation, Some(0)); OneImage { slots, primaries, diff --git a/sim/src/lib.rs b/sim/src/lib.rs index 8c648ca63..a496db9db 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -202,7 +202,7 @@ impl RunStatus { // Creates a badly signed image in the secondary slot to check that // it is not upgraded to - let bad_secondary_slot_image = run.clone().make_bad_secondary_slot_image(); + let bad_secondary_slot_image = run.clone().make_bad_secondary_slot_image(ImageManipulation::BadSignature); failed |= bad_secondary_slot_image.run_signfail_upgrade(); diff --git a/sim/tests/core.rs b/sim/tests/core.rs index 69745ab26..55571a012 100644 --- a/sim/tests/core.rs +++ b/sim/tests/core.rs @@ -49,7 +49,7 @@ macro_rules! sim_test { }; } -sim_test!(bad_secondary_slot, make_bad_secondary_slot_image(), run_signfail_upgrade()); +sim_test!(bad_secondary_slot, make_bad_secondary_slot_image(ImageManipulation::BadSignature), run_signfail_upgrade()); sim_test!(secondary_trailer_leftover, make_erased_secondary_image(), run_secondary_leftover_trailer()); sim_test!(bootstrap, make_bootstrap_image(), run_bootstrap()); sim_test!(oversized_bootstrap, make_oversized_bootstrap_image(), run_oversized_bootstrap()); From f16344224a5b972d0c39d05d4274066b0386c22c Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 8 Oct 2025 13:31:02 +0000 Subject: [PATCH 077/149] [nrf fromtree] sim: Add test for MCUBOOT_CHECK_HEADER_LOAD_ADDRESS Testing MCUBOOT_CHECK_HEADER_LOAD_ADDRESS for non-RAM load binaries. Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 5c8d226f713a117a3fccd568e13a63a6ecf13cc8) --- sim/Cargo.toml | 1 + sim/mcuboot-sys/Cargo.toml | 3 +++ sim/mcuboot-sys/build.rs | 5 +++++ sim/src/image.rs | 22 ++++++++++++++++++---- sim/tests/core.rs | 16 +++++++++++++--- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/sim/Cargo.toml b/sim/Cargo.toml index 6d2262d90..f7d3505a5 100644 --- a/sim/Cargo.toml +++ b/sim/Cargo.toml @@ -34,6 +34,7 @@ direct-xip = ["mcuboot-sys/direct-xip"] downgrade-prevention = ["mcuboot-sys/downgrade-prevention"] max-align-32 = ["mcuboot-sys/max-align-32"] hw-rollback-protection = ["mcuboot-sys/hw-rollback-protection"] +check-load-addr = ["mcuboot-sys/check-load-addr"] [dependencies] byteorder = "1.4" diff --git a/sim/mcuboot-sys/Cargo.toml b/sim/mcuboot-sys/Cargo.toml index f2eb70634..b3e46082f 100644 --- a/sim/mcuboot-sys/Cargo.toml +++ b/sim/mcuboot-sys/Cargo.toml @@ -99,6 +99,9 @@ hw-rollback-protection = [] # Enable the PSA Crypto APIs where supported for cryptography related operations. psa-crypto-api = [] +# Test for ih_load_addr in upgrade/next boot slot +check-load-addr = [] + [build-dependencies] cc = "1.0.25" diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs index b2595689b..b04bab404 100644 --- a/sim/mcuboot-sys/build.rs +++ b/sim/mcuboot-sys/build.rs @@ -39,6 +39,7 @@ fn main() { let direct_xip = env::var("CARGO_FEATURE_DIRECT_XIP").is_ok(); let max_align_32 = env::var("CARGO_FEATURE_MAX_ALIGN_32").is_ok(); let hw_rollback_protection = env::var("CARGO_FEATURE_HW_ROLLBACK_PROTECTION").is_ok(); + let check_load_addr = env::var("CARGO_FEATURE_CHECK_LOAD_ADDR").is_ok(); let mut conf = CachedBuild::new(); conf.conf.define("__BOOTSIM__", None); @@ -64,6 +65,10 @@ fn main() { conf.conf.define("MCUBOOT_OVERWRITE_ONLY_FAST", None); } + if check_load_addr { + conf.conf.define("MCUBOOT_CHECK_HEADER_LOAD_ADDRESS", None); + } + if validate_primary_slot { conf.conf.define("MCUBOOT_VALIDATE_PRIMARY_SLOT", None); } diff --git a/sim/src/image.rs b/sim/src/image.rs index 846783a06..227617d7d 100644 --- a/sim/src/image.rs +++ b/sim/src/image.rs @@ -899,8 +899,8 @@ impl Images { fails > 0 } - // Test taht too big upgrade image will be rejected - pub fn run_oversizefail_upgrade(&self) -> bool { + // Test expecting failed upgrade and primary slot left untouched + pub fn run_fail_upgrade_primary_intact(&self) -> bool { let mut flash = self.flash.clone(); let mut fails = 0; @@ -940,7 +940,7 @@ impl Images { } if fails > 0 { - error!("Expected an upgrade failure when image has to big size"); + error!("Expected an upgrade failure and primary slot left untouched"); } fails > 0 @@ -1930,7 +1930,21 @@ fn install_image(flash: &mut SimMultiFlash, areadesc: &AreaDesc, slots: &[SlotIn _ => place.offset } } else { - 0 + if cfg!(feature = "check-load-addr") { + let wrong_off = match img_manipulation { + ImageManipulation::WrongOffset => true, + _ => false + }; + if wrong_off { + u32::MAX + } else if cfg!(feature = "direct-xip") { + slots[slot_ind].base_off as u32 + } else { + slots[0].base_off as u32 + } + } else { + 0 + } }; let len = match len { diff --git a/sim/tests/core.rs b/sim/tests/core.rs index 55571a012..b7be7530d 100644 --- a/sim/tests/core.rs +++ b/sim/tests/core.rs @@ -59,23 +59,33 @@ sim_test!(revert_with_fails, make_image(&NO_DEPS, false), run_revert_with_fails( sim_test!(perm_with_fails, make_image(&NO_DEPS, true), run_perm_with_fails()); sim_test!(perm_with_random_fails, make_image(&NO_DEPS, true), run_perm_with_random_fails(5)); sim_test!(norevert, make_image(&NO_DEPS, true), run_norevert()); -sim_test!(oversized_secondary_slot, make_oversized_secondary_slot_image(), run_oversizefail_upgrade()); +sim_test!(oversized_secondary_slot, make_oversized_secondary_slot_image(), run_fail_upgrade_primary_intact()); +#[cfg(feature = "check-load-addr")] +sim_test!(wrong_load_addr, make_bad_secondary_slot_image(ImageManipulation::WrongOffset), run_fail_upgrade_primary_intact()); sim_test!(status_write_fails_complete, make_image(&NO_DEPS, true), run_with_status_fails_complete()); sim_test!(status_write_fails_with_reset, make_image(&NO_DEPS, true), run_with_status_fails_with_reset()); sim_test!(downgrade_prevention, make_image(&REV_DEPS, true), run_nodowngrade()); sim_test!(direct_xip_first, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_direct_xip()); +#[cfg(not(feature = "check-load-addr"))] sim_test!(ram_load_first, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_ram_load()); +#[cfg(not(feature = "check-load-addr"))] sim_test!(ram_load_split, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_split_ram_load()); +#[cfg(not(feature = "check-load-addr"))] sim_test!(ram_load_from_flash, make_no_upgrade_image(&NO_DEPS, ImageManipulation::None), run_ram_load_from_flash()); -sim_test!(hw_prot_failed_security_cnt_check, make_image_with_security_counter(Some(0)), run_hw_rollback_prot()); -sim_test!(hw_prot_missing_security_cnt, make_image_with_security_counter(None), run_hw_rollback_prot()); +#[cfg(not(feature = "check-load-addr"))] sim_test!(ram_load_out_of_bounds, make_no_upgrade_image(&NO_DEPS, ImageManipulation::WrongOffset), run_ram_load_boot_with_result(false)); +#[cfg(not(feature = "check-load-addr"))] sim_test!(ram_load_missing_header_flag, make_no_upgrade_image(&NO_DEPS, ImageManipulation::IgnoreRamLoadFlag), run_ram_load_boot_with_result(false)); +#[cfg(not(feature = "check-load-addr"))] sim_test!(ram_load_failed_validation, make_no_upgrade_image(&NO_DEPS, ImageManipulation::BadSignature), run_ram_load_boot_with_result(false)); +#[cfg(not(feature = "check-load-addr"))] sim_test!(ram_load_corrupt_higher_version_image, make_no_upgrade_image(&NO_DEPS, ImageManipulation::CorruptHigherVersionImage), run_ram_load_boot_with_result(true)); +sim_test!(hw_prot_missing_security_cnt, make_image_with_security_counter(None), run_hw_rollback_prot()); +sim_test!(hw_prot_failed_security_cnt_check, make_image_with_security_counter(Some(0)), run_hw_rollback_prot()); + #[cfg(feature = "multiimage")] sim_test!(ram_load_overlapping_images_same_base, make_no_upgrade_image(&NO_DEPS, ImageManipulation::OverlapImages(true)), run_ram_load_boot_with_result(false)); #[cfg(feature = "multiimage")] From 20f981e4d8ef2bb913389e0446d8dc5bb9031953 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 8 Oct 2025 13:36:34 +0000 Subject: [PATCH 078/149] [nrf fromtree] zephyr: Deprecate MCUBOOT_VERIFY_IMG_ADDRESS Please use MCUBOOT_CHECK_HEADER_LOAD_ADDRESS instead. Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 15d43f2002de1363d646acef38abaaad8e03feaa) --- boot/zephyr/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 487f81d47..b57c17b6f 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1321,12 +1321,15 @@ config MCUBOOT_CHECK_HEADER_LOAD_ADDRESS the same purpose. config MCUBOOT_VERIFY_IMG_ADDRESS - bool "Verify reset address of image in secondary slot" + bool "Verify reset address of image in secondary slot [DEPRECATED]" + select DEPRECATED depends on UPDATEABLE_IMAGE_NUMBER > 1 depends on !BOOT_ENCRYPT_IMAGE depends on ARM default y if BOOT_UPGRADE_ONLY help + This option is deprecated, please use MCUBOOT_CHECK_HEADER_LOAD_ADDRESS + instead. Verify that the reset address in the image located in the secondary slot is contained within the corresponding primary slot. This is recommended if swapping is not used (that is, BOOT_UPGRADE_ONLY is set). If a user From 06383a09e0e03e3d84260bfe4fb5dd32d72a33c7 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 9 Oct 2025 17:01:11 +0000 Subject: [PATCH 079/149] [nrf fromtree] bootutil: Move boot_enc_init in boot_swap_image Encryption context intialization can happen before we read the key. Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 028d80c36118df54a301012caa22d70c238bc9db) --- boot/bootutil/src/loader.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 2448835be..0c4b346a9 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1675,6 +1675,9 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) #ifdef MCUBOOT_ENC_IMAGES for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { + + boot_enc_init(BOOT_CURR_ENC(state), slot); + rc = boot_read_enc_key(fap, slot, bs); assert(rc == 0); @@ -1684,8 +1687,6 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) } } - boot_enc_init(BOOT_CURR_ENC(state), slot); - if (i != BOOT_ENC_KEY_SIZE) { boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs); } From e5718271365be503da84c68a726e14bc72fe5e87 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 14 Oct 2025 14:45:33 +0000 Subject: [PATCH 080/149] [nrf fromtree] bootutil: Replace literal slot indexes with identifiers Use BOOT_SLOT_PRIMARY/BOOT_SLOT_SECONDARY instead of 0/1. Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 80a39c6472d15d617b1b2e57ebe6041a9292122d) --- boot/boot_serial/src/boot_serial_encryption.c | 8 ++++---- boot/bootutil/src/loader.c | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/boot/boot_serial/src/boot_serial_encryption.c b/boot/boot_serial/src/boot_serial_encryption.c index 4bbe74dc3..fe9427068 100644 --- a/boot/boot_serial/src/boot_serial_encryption.c +++ b/boot/boot_serial/src/boot_serial_encryption.c @@ -31,11 +31,11 @@ boot_image_validate_encrypted(struct boot_loader_state *state, int rc; if (MUST_DECRYPT(fa_p, BOOT_CURR_IMG(state), hdr)) { - rc = boot_enc_load(state, 1, hdr, fa_p, bs); + rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, hdr, fa_p, bs); if (rc < 0) { FIH_RET(fih_rc); } - rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs); + rc = boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_SECONDARY, bs); if (rc < 0) { FIH_RET(fih_rc); } @@ -235,11 +235,11 @@ decrypt_image_inplace(const struct flash_area *fa_p, #endif memset(&boot_data, 0, sizeof(struct boot_loader_state)); /* Load the encryption keys into cache */ - rc = boot_enc_load(state, 0, hdr, fa_p, bs); + rc = boot_enc_load(state, BOOT_SLOT_PRIMARY, hdr, fa_p, bs); if (rc < 0) { FIH_RET(fih_rc); } - if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs)) { + if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_PRIMARY, bs)) { FIH_RET(fih_rc); } } diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 0c4b346a9..11f7d718c 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -644,11 +644,11 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, */ #if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD) if (MUST_DECRYPT(fap, BOOT_CURR_IMG(state), hdr)) { - rc = boot_enc_load(state, 1, hdr, fap, bs); + rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, hdr, fap, bs); if (rc < 0) { FIH_RET(fih_rc); } - if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) { + if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_SECONDARY, bs)) { FIH_RET(fih_rc); } } @@ -1499,7 +1499,7 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) if (rc < 0) { return BOOT_EBADIMAGE; } - if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) { + if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_SECONDARY, bs)) { return BOOT_EBADIMAGE; } } @@ -1617,17 +1617,17 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) #ifdef MCUBOOT_ENC_IMAGES if (IS_ENCRYPTED(hdr)) { fap = BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY); - rc = boot_enc_load(state, 0, hdr, fap, bs); + rc = boot_enc_load(state, BOOT_SLOT_PRIMARY, hdr, fap, bs); assert(rc >= 0); if (rc == 0) { - rc = boot_enc_set_key(BOOT_CURR_ENC(state), 0, bs); + rc = boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_PRIMARY, bs); assert(rc == 0); } else { rc = 0; } } else { - memset(bs->enckey[0], 0xff, BOOT_ENC_KEY_ALIGN_SIZE); + memset(bs->enckey[BOOT_SLOT_PRIMARY], 0xff, BOOT_ENC_KEY_ALIGN_SIZE); } #endif @@ -1641,17 +1641,17 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY); if (IS_ENCRYPTED(hdr)) { fap = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); - rc = boot_enc_load(state, 1, hdr, fap, bs); + rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, hdr, fap, bs); assert(rc >= 0); if (rc == 0) { - rc = boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs); + rc = boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_SECONDARY, bs); assert(rc == 0); } else { rc = 0; } } else { - memset(bs->enckey[1], 0xff, BOOT_ENC_KEY_ALIGN_SIZE); + memset(bs->enckey[BOOT_SLOT_SECONDARY], 0xff, BOOT_ENC_KEY_ALIGN_SIZE); } #endif From 663cd8714a43a8a6dbfbd44108ada9877784a0a2 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 14 Oct 2025 16:06:52 +0000 Subject: [PATCH 081/149] [nrf fromtree] bootutil: Replace boot_write_enc_key with boot_write_enc_keys All keys are written at once anyway. Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit ee9efe01e9ccc5356b3f5405b0565326621c8dcc) --- boot/bootutil/src/bootutil_misc.c | 26 ++++++++++++++------------ boot/bootutil/src/bootutil_priv.h | 3 +-- boot/bootutil/src/swap_misc.c | 6 +----- boot/bootutil/src/swap_scratch.c | 6 +----- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 4fc9e8279..790ee24bf 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -407,23 +407,25 @@ boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size) #ifdef MCUBOOT_ENC_IMAGES int -boot_write_enc_key(const struct flash_area *fap, uint8_t slot, - const struct boot_status *bs) +boot_write_enc_keys(const struct flash_area *fap, const struct boot_status *bs) { - uint32_t off; - int rc; + int slot; - off = boot_enc_key_off(fap, slot); - BOOT_LOG_DBG("writing enc_key; fa_id=%d off=0x%lx (0x%lx)", - flash_area_get_id(fap), (unsigned long)off, - (unsigned long)flash_area_get_off(fap) + off); + for (slot = 0; slot < BOOT_NUM_SLOTS; ++slot) { + uint32_t off = boot_enc_key_off(fap, slot); + int rc; + + BOOT_LOG_DBG("writing enc_key; fa_id=%d off=0x%lx (0x%lx)", + flash_area_get_id(fap), (unsigned long)off, + (unsigned long)flash_area_get_off(fap) + off); #if MCUBOOT_SWAP_SAVE_ENCTLV - rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE); + rc = flash_area_write(fap, off, bs->enctlv[slot], BOOT_ENC_TLV_ALIGN_SIZE); #else - rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE); + rc = flash_area_write(fap, off, bs->enckey[slot], BOOT_ENC_KEY_ALIGN_SIZE); #endif - if (rc != 0) { - return BOOT_EFLASH; + if (rc != 0) { + return BOOT_EFLASH; + } } return 0; diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 784baf7e7..76aef0115 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -371,8 +371,7 @@ int boot_scramble_slot(const struct flash_area *fap, int slot); bool boot_status_is_reset(const struct boot_status *bs); #ifdef MCUBOOT_ENC_IMAGES -int boot_write_enc_key(const struct flash_area *fap, uint8_t slot, - const struct boot_status *bs); +int boot_write_enc_keys(const struct flash_area *fap, const struct boot_status *bs); int boot_read_enc_key(const struct flash_area *fap, uint8_t slot, struct boot_status *bs); #endif diff --git a/boot/bootutil/src/swap_misc.c b/boot/bootutil/src/swap_misc.c index 99aac2b02..588fba444 100644 --- a/boot/bootutil/src/swap_misc.c +++ b/boot/bootutil/src/swap_misc.c @@ -137,11 +137,7 @@ swap_status_init(const struct boot_loader_state *state, assert(rc == 0); #ifdef MCUBOOT_ENC_IMAGES - rc = boot_write_enc_key(fap, 0, bs); - assert(rc == 0); - - rc = boot_write_enc_key(fap, 1, bs); - assert(rc == 0); + rc = boot_write_enc_keys(fap, bs); #endif rc = boot_write_magic(fap); diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c index 0a994d862..59b64ad43 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -884,11 +884,7 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state, assert(rc == 0); #ifdef MCUBOOT_ENC_IMAGES - rc = boot_write_enc_key(fap_primary_slot, 0, bs); - assert(rc == 0); - - rc = boot_write_enc_key(fap_primary_slot, 1, bs); - assert(rc == 0); + rc = boot_write_enc_keys(fap_primary_slot, bs); #endif rc = boot_write_magic(fap_primary_slot); assert(rc == 0); From 88c7a773c6e5e170319cf2a9be3558066d01cee7 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 15 Oct 2025 12:49:42 +0100 Subject: [PATCH 082/149] [nrf fromtree] boot: bootutil: swap_offset: Fix not including unprotected TLVs Fixes an issue whereby the size of unprotected TLVs were not included in the size of the image to swap. Because this information is not present in the MCUboot header and because swap using offset includes swapping data that might mangle this area, extra space in the swap status trailer needs to be reserved and used Signed-off-by: Jamie McCrae Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 5b7bccf9def7b1f4e013ea091027e41c74afb563) --- boot/bootutil/src/bootutil_misc.c | 44 +++++++++++++++++++++++++++++++ boot/bootutil/src/bootutil_misc.h | 14 ++++++++++ boot/bootutil/src/bootutil_priv.h | 10 +++++++ boot/bootutil/src/swap_misc.c | 9 ++++++- boot/bootutil/src/swap_offset.c | 29 +++++++++++++++----- 5 files changed, 99 insertions(+), 7 deletions(-) diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 790ee24bf..5359e0d26 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -126,6 +126,10 @@ boot_trailer_info_sz(void) #endif /* swap_type + copy_done + image_ok + swap_size */ BOOT_MAX_ALIGN * 4 + +#ifdef MCUBOOT_SWAP_USING_OFFSET + /* TLV size for both slots */ + BOOT_MAX_ALIGN + +#endif BOOT_MAGIC_ALIGN_SIZE ); } @@ -361,6 +365,27 @@ boot_read_swap_size(const struct flash_area *fap, uint32_t *swap_size) return rc; } +#ifdef MCUBOOT_SWAP_USING_OFFSET +int +boot_read_unprotected_tlv_sizes(const struct flash_area *fap, uint16_t *tlv_size_primary, + uint16_t *tlv_size_secondary) +{ + uint32_t off; + uint32_t combined_tlv_sizes = 0; + int rc; + + off = boot_unprotected_tlv_sizes_off(fap); + rc = flash_area_read(fap, off, &combined_tlv_sizes, sizeof(combined_tlv_sizes)); + + if (rc == 0) { + *tlv_size_primary = (uint16_t)(combined_tlv_sizes & 0xffff); + *tlv_size_secondary = (uint16_t)((combined_tlv_sizes & 0xffff0000) >> 16); + } + + return rc; +} +#endif + #ifdef MCUBOOT_ENC_IMAGES int boot_read_enc_key(const struct flash_area *fap, uint8_t slot, struct boot_status *bs) @@ -405,6 +430,25 @@ boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size) return boot_write_trailer(fap, off, (const uint8_t *) &swap_size, 4); } +#if defined(MCUBOOT_SWAP_USING_OFFSET) +int +boot_write_unprotected_tlv_sizes(const struct flash_area *fap, uint16_t tlv_size_primary, + uint16_t tlv_size_secondary) +{ + uint32_t off; + uint32_t tlv_sizes_combined; + + off = boot_unprotected_tlv_sizes_off(fap); + tlv_sizes_combined = ((uint32_t)tlv_size_secondary << 16) | (uint32_t)tlv_size_primary; + BOOT_LOG_DBG("writing unprotected_tlv_sizes; fa_id=%d off=0x%lx (0x%lx) vals=0x%x,0x%x (0x%lx)", + flash_area_get_id(fap), (unsigned long)off, + ((unsigned long)flash_area_get_off(fap) + off), tlv_size_primary, + tlv_size_secondary, (unsigned long)tlv_sizes_combined); + return boot_write_trailer(fap, off, (const uint8_t *)&tlv_sizes_combined, + sizeof(tlv_sizes_combined)); +} +#endif + #ifdef MCUBOOT_ENC_IMAGES int boot_write_enc_keys(const struct flash_area *fap, const struct boot_status *bs) diff --git a/boot/bootutil/src/bootutil_misc.h b/boot/bootutil/src/bootutil_misc.h index 1fcaabdfc..9c3a2d2f8 100644 --- a/boot/bootutil/src/bootutil_misc.h +++ b/boot/bootutil/src/bootutil_misc.h @@ -43,10 +43,24 @@ boot_copy_done_off(const struct flash_area *fap) return boot_image_ok_off(fap) - BOOT_MAX_ALIGN; } +#if defined(MCUBOOT_SWAP_USING_OFFSET) +static inline uint32_t +boot_unprotected_tlv_sizes_off(const struct flash_area *fap) +{ + return boot_swap_info_off(fap) - BOOT_MAX_ALIGN; +} + +static inline uint32_t +boot_swap_size_off(const struct flash_area *fap) +{ + return boot_unprotected_tlv_sizes_off(fap) - BOOT_MAX_ALIGN; +} +#else static inline uint32_t boot_swap_size_off(const struct flash_area *fap) { return boot_swap_info_off(fap) - BOOT_MAX_ALIGN; } +#endif #endif /* H_BOOTUTIL_MISC_ */ diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 76aef0115..439b9d91b 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -242,6 +242,9 @@ struct boot_loader_state { const struct flash_area *area; boot_sector_t *sectors; uint32_t num_sectors; +#if defined(MCUBOOT_SWAP_USING_OFFSET) + uint16_t unprotected_tlv_size; +#endif } imgs[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS]; #if MCUBOOT_SWAP_USING_SCRATCH @@ -342,6 +345,12 @@ int boot_write_trailer(const struct flash_area *fap, uint32_t off, int boot_write_trailer_flag(const struct flash_area *fap, uint32_t off, uint8_t flag_val); int boot_read_swap_size(const struct flash_area *fap, uint32_t *swap_size); +#if defined(MCUBOOT_SWAP_USING_OFFSET) +int boot_write_unprotected_tlv_sizes(const struct flash_area *fap, uint16_t tlv_size_primary, + uint16_t tlv_size_secondary); +int boot_read_unprotected_tlv_sizes(const struct flash_area *fap, uint16_t *tlv_size_primary, + uint16_t *tlv_size_secondary); +#endif int boot_slots_compatible(struct boot_loader_state *state); uint32_t boot_status_internal_off(const struct boot_status *bs, int elem_sz); int boot_read_image_header(struct boot_loader_state *state, int slot, @@ -479,6 +488,7 @@ static inline bool boot_u16_safe_add(uint16_t *dest, uint16_t a, uint16_t b) #endif #define BOOT_IMG(state, slot) ((state)->imgs[BOOT_CURR_IMG(state)][(slot)]) #define BOOT_IMG_AREA(state, slot) (BOOT_IMG(state, slot).area) +#define BOOT_IMG_UNPROTECTED_TLV_SIZE(state, slot) (BOOT_IMG(state, slot).unprotected_tlv_size) #define BOOT_WRITE_SZ(state) ((state)->write_sz[BOOT_CURR_IMG(state)]) #define BOOT_SWAP_TYPE(state) ((state)->swap_type[BOOT_CURR_IMG(state)]) #define BOOT_TLV_OFF(hdr) ((hdr)->ih_hdr_size + (hdr)->ih_img_size) diff --git a/boot/bootutil/src/swap_misc.c b/boot/bootutil/src/swap_misc.c index 588fba444..c00f281a7 100644 --- a/boot/bootutil/src/swap_misc.c +++ b/boot/bootutil/src/swap_misc.c @@ -2,6 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * * Copyright (c) 2019 JUUL Labs + * Copyright (c) 2025 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. @@ -136,6 +137,13 @@ swap_status_init(const struct boot_loader_state *state, rc = boot_write_swap_size(fap, bs->swap_size); assert(rc == 0); +#ifdef MCUBOOT_SWAP_USING_OFFSET + rc = boot_write_unprotected_tlv_sizes(fap, + BOOT_IMG_UNPROTECTED_TLV_SIZE(state, BOOT_SLOT_PRIMARY), + BOOT_IMG_UNPROTECTED_TLV_SIZE(state, BOOT_SLOT_SECONDARY)); + assert(rc == 0); +#endif + #ifdef MCUBOOT_ENC_IMAGES rc = boot_write_enc_keys(fap, bs); #endif @@ -243,5 +251,4 @@ swap_set_image_ok(uint8_t image_index) return rc; } - #endif /* defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET) */ diff --git a/boot/bootutil/src/swap_offset.c b/boot/bootutil/src/swap_offset.c index f0b2d0634..eda68ab91 100644 --- a/boot/bootutil/src/swap_offset.c +++ b/boot/bootutil/src/swap_offset.c @@ -593,12 +593,20 @@ void swap_run(struct boot_loader_state *state, struct boot_status *bs, const struct flash_area *fap_pri = NULL; const struct flash_area *fap_sec = NULL; int rc; + uint16_t unprotected_tlv_size_pri; + uint16_t unprotected_tlv_size_sec; BOOT_LOG_INF("Starting swap using offset algorithm."); last_idx = find_last_idx(state, copy_size); sector_sz = boot_img_sector_size(state, BOOT_SLOT_PRIMARY, 0); + fap_pri = BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY); + assert(fap_pri != NULL); + + fap_sec = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); + assert(fap_sec != NULL); + /* When starting a new swap upgrade, check that there is enough space */ if (boot_status_is_reset(bs)) { sz = 0; @@ -623,12 +631,6 @@ void swap_run(struct boot_loader_state *state, struct boot_status *bs, } } - fap_pri = BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY); - assert(fap_pri != NULL); - - fap_sec = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); - assert(fap_sec != NULL); - fixup_revert(state, bs, fap_sec); /* Init areas for storing swap status */ @@ -647,14 +649,24 @@ void swap_run(struct boot_loader_state *state, struct boot_status *bs, assert(rc == 0); } + /* Read the unprotected TLV sizes from the boot swap status area, this information might get + * jangled if rebooted during an update so it needs to be stored in this area for safe + * retrieval + */ + boot_read_unprotected_tlv_sizes(fap_pri, &unprotected_tlv_size_pri, &unprotected_tlv_size_sec); + BOOT_LOG_DBG("Unprotected TLV sizes image=%d: pri=%d, sec=%d", BOOT_CURR_IMG(state), + unprotected_tlv_size_pri, unprotected_tlv_size_sec); + bs->op = BOOT_STATUS_OP_SWAP; idx = 0; used_sectors_pri = ((state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_PRIMARY].hdr.ih_hdr_size + + unprotected_tlv_size_pri + state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_PRIMARY].hdr.ih_protect_tlv_size + state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_PRIMARY].hdr.ih_img_size) + sector_sz - 1) / sector_sz; used_sectors_sec = ((state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_SECONDARY].hdr.ih_hdr_size + state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_SECONDARY].hdr.ih_protect_tlv_size + + unprotected_tlv_size_sec + state->imgs[BOOT_CURR_IMG(state)][BOOT_SLOT_SECONDARY].hdr.ih_img_size) + sector_sz - 1) / sector_sz; @@ -770,6 +782,11 @@ int boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *si goto done; } + /* This is needed as unprotected TLV size cannot be calculated once a swap has been started, + * it is only able to be properly calculated when images are in pristine states + */ + BOOT_IMG_UNPROTECTED_TLV_SIZE(state, slot) = info.it_tlv_tot; + *size = off + protect_tlv_size + info.it_tlv_tot; rc = 0; From 7571f8cc6eb9c3faef2bc55e734d46bba22a17e2 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Wed, 15 Oct 2025 13:09:34 +0100 Subject: [PATCH 083/149] [nrf fromtree] docs: design: Add update on swap using offset Adds the new unprotected TLV sizes field that swap using offset mode uses Signed-off-by: Jamie McCrae Signed-off-by: Tomasz Chyrowicz (cherry picked from commit cf2387c2e17b49d50cee37eedb9fbc4cc7427c51) --- docs/design.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/design.md b/docs/design.md index 595c6a401..484066d60 100755 --- a/docs/design.md +++ b/docs/design.md @@ -571,6 +571,12 @@ image trailer. An image trailer has the following structure: | 0xff padding as needed | | (BOOT_MAX_ALIGN minus 4 octets from Swap size) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unprotected TLV size [*2] | Unprotected TLV size [*2] | + | Secondary slot (2 octets) | Primary slot (2 octets) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | 0xff padding as needed [*2] | + | (BOOT_MAX_ALIGN minus 4 octets from unprotected TLV sizes) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Swap info | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Copy done | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) | @@ -586,6 +592,7 @@ image trailer. An image trailer has the following structure: ``` [*]: Only present if the encryption option is enabled (`MCUBOOT_ENC_IMAGES`). +[*2]: Only present if swap using offset mode is used (`MCUBOOT_SWAP_USING_OFFSET`). The offset immediately following such a record represents the start of the next flash area. From 2439b0a873465065b3f2a4954bf79bb2ecfba176 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 17 Oct 2025 19:27:07 +0000 Subject: [PATCH 084/149] [nrf fromtree] bootutil: Drop slot number and boot_state from most boot_enc functions Step forward in reducing entanglement between internal APIs. Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 2fc1bd843db81c0267f197075fd356ceeabd0f94) --- boot/boot_serial/src/boot_serial_encryption.c | 6 +-- boot/bootutil/include/bootutil/enc_key.h | 14 +++---- boot/bootutil/src/bootutil_img_hash.c | 7 +--- boot/bootutil/src/bootutil_priv.h | 2 + boot/bootutil/src/encrypted.c | 37 +++++++++---------- boot/bootutil/src/loader.c | 16 ++++---- boot/bootutil/src/ram_load.c | 4 +- 7 files changed, 41 insertions(+), 45 deletions(-) diff --git a/boot/boot_serial/src/boot_serial_encryption.c b/boot/boot_serial/src/boot_serial_encryption.c index fe9427068..de1f8b57a 100644 --- a/boot/boot_serial/src/boot_serial_encryption.c +++ b/boot/boot_serial/src/boot_serial_encryption.c @@ -35,7 +35,7 @@ boot_image_validate_encrypted(struct boot_loader_state *state, if (rc < 0) { FIH_RET(fih_rc); } - rc = boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_SECONDARY, bs); + rc = boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY), bs->enckey[BOOT_SLOT_SECONDARY]); if (rc < 0) { FIH_RET(fih_rc); } @@ -169,7 +169,7 @@ decrypt_region_inplace(struct boot_loader_state *state, blk_sz = tlv_off - (off + bytes_copied); } } - boot_enc_decrypt(BOOT_CURR_ENC(state), slot, + boot_enc_decrypt(BOOT_CURR_ENC_SLOT(state, slot), (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz, blk_off, &buf[idx]); } @@ -239,7 +239,7 @@ decrypt_image_inplace(const struct flash_area *fa_p, if (rc < 0) { FIH_RET(fih_rc); } - if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_PRIMARY, bs)) { + if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_PRIMARY), bs->enckey[BOOT_SLOT_PRIMARY])) { FIH_RET(fih_rc); } } diff --git a/boot/bootutil/include/bootutil/enc_key.h b/boot/bootutil/include/bootutil/enc_key.h index 89411bf17..6fa0db18e 100644 --- a/boot/bootutil/include/bootutil/enc_key.h +++ b/boot/bootutil/include/bootutil/enc_key.h @@ -61,18 +61,18 @@ struct boot_loader_state; /* Decrypt random, symmetric encryption key */ int boot_decrypt_key(const uint8_t *buf, uint8_t *enckey); -int boot_enc_init(struct enc_key_data *enc_state, uint8_t slot); -int boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot); -int boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot, - const struct boot_status *bs); +int boot_enc_init(struct enc_key_data *enc_state); +int boot_enc_drop(struct enc_key_data *enc_state); +int boot_enc_set_key(struct enc_key_data *enc_state, const uint8_t *key); int boot_enc_load(struct boot_loader_state *state, int slot, const struct image_header *hdr, const struct flash_area *fap, struct boot_status *bs); -bool boot_enc_valid(struct enc_key_data *enc_state, int slot); -void boot_enc_encrypt(struct enc_key_data *enc_state, int slot, +bool boot_enc_valid(const struct enc_key_data *enc_state); +void boot_enc_encrypt(struct enc_key_data *enc_state, uint32_t off, uint32_t sz, uint32_t blk_off, uint8_t *buf); -void boot_enc_decrypt(struct enc_key_data *enc_state, int slot, +void boot_enc_decrypt(struct enc_key_data *enc_state, uint32_t off, uint32_t sz, uint32_t blk_off, uint8_t *buf); +/* Note that boot_enc_zeorize takes BOOT_CURR_ENC, not BOOT_CURR_ENC_SLOT */ void boot_enc_zeroize(struct enc_key_data *enc_state); #ifdef __cplusplus diff --git a/boot/bootutil/src/bootutil_img_hash.c b/boot/bootutil/src/bootutil_img_hash.c index ff8340d70..ae52ffb91 100644 --- a/boot/bootutil/src/bootutil_img_hash.c +++ b/boot/bootutil/src/bootutil_img_hash.c @@ -65,7 +65,6 @@ bootutil_img_hash(struct boot_loader_state *state, int fa_ret; #endif #if defined(MCUBOOT_ENC_IMAGES) - struct enc_key_data *enc_state; int image_index; #endif #if defined(MCUBOOT_SWAP_USING_OFFSET) @@ -91,16 +90,14 @@ bootutil_img_hash(struct boot_loader_state *state, #ifdef MCUBOOT_ENC_IMAGES if (state == NULL) { - enc_state = NULL; image_index = 0; } else { - enc_state = BOOT_CURR_ENC(state); image_index = BOOT_CURR_IMG(state); } /* Encrypted images only exist in the secondary slot */ if (MUST_DECRYPT(fap, image_index, hdr) && - !boot_enc_valid(enc_state, 1)) { + !boot_enc_valid(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY))) { BOOT_LOG_DBG("bootutil_img_hash: error encrypted image found in primary slot"); return -1; } @@ -182,7 +179,7 @@ bootutil_img_hash(struct boot_loader_state *state, if (off >= hdr_size && off < tlv_off) { blk_off = (off - hdr_size) & 0xf; - boot_enc_decrypt(enc_state, slot, off - hdr_size, + boot_enc_decrypt(BOOT_CURR_ENC_SLOT(state, slot), off - hdr_size, blk_sz, blk_off, tmp_buf); } } diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 439b9d91b..3282243ec 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -483,8 +483,10 @@ static inline bool boot_u16_safe_add(uint16_t *dest, uint16_t a, uint16_t b) #endif #ifdef MCUBOOT_ENC_IMAGES #define BOOT_CURR_ENC(state) ((state)->enc[BOOT_CURR_IMG(state)]) +#define BOOT_CURR_ENC_SLOT(state, slot) (&((state)->enc[BOOT_CURR_IMG(state)][slot])) #else #define BOOT_CURR_ENC(state) NULL +#define BOOT_CURR_ENC_SLOT(state, slot) NULL #endif #define BOOT_IMG(state, slot) ((state)->imgs[BOOT_CURR_IMG(state)][(slot)]) #define BOOT_IMG_AREA(state, slot) (BOOT_IMG(state, slot).area) diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index 97791994f..9f86bb457 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -573,7 +573,7 @@ boot_enc_load(struct boot_loader_state *state, int slot, const struct image_header *hdr, const struct flash_area *fap, struct boot_status *bs) { - struct enc_key_data *enc_state = BOOT_CURR_ENC(state); + struct enc_key_data *enc_state = BOOT_CURR_ENC_SLOT(state, slot); uint32_t off; uint16_t len; struct image_tlv_iter it; @@ -587,13 +587,13 @@ boot_enc_load(struct boot_loader_state *state, int slot, BOOT_LOG_DBG("boot_enc_load: slot %d", slot); /* Already loaded... */ - if (enc_state[slot].valid) { + if (boot_enc_valid(enc_state)) { BOOT_LOG_DBG("boot_enc_load: already loaded"); return 1; } /* Initialize the AES context */ - boot_enc_init(enc_state, slot); + boot_enc_init(enc_state); #if defined(MCUBOOT_SWAP_USING_OFFSET) it.start_off = boot_get_state_secondary_offset(state, fap); @@ -627,48 +627,46 @@ boot_enc_load(struct boot_loader_state *state, int slot, } int -boot_enc_init(struct enc_key_data *enc_state, uint8_t slot) +boot_enc_init(struct enc_key_data *enc_state) { - bootutil_aes_ctr_init(&enc_state[slot].aes_ctr); + bootutil_aes_ctr_init(&enc_state->aes_ctr); return 0; } int -boot_enc_drop(struct enc_key_data *enc_state, uint8_t slot) +boot_enc_drop(struct enc_key_data *enc_state) { - bootutil_aes_ctr_drop(&enc_state[slot].aes_ctr); - enc_state[slot].valid = 0; + bootutil_aes_ctr_drop(&enc_state->aes_ctr); + enc_state->valid = 0; return 0; } int -boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot, - const struct boot_status *bs) +boot_enc_set_key(struct enc_key_data *enc_state, const uint8_t *key) { int rc; - rc = bootutil_aes_ctr_set_key(&enc_state[slot].aes_ctr, bs->enckey[slot]); + rc = bootutil_aes_ctr_set_key(&enc_state->aes_ctr, key); if (rc != 0) { - boot_enc_drop(enc_state, slot); + boot_enc_drop(enc_state); return -1; } - enc_state[slot].valid = 1; + enc_state->valid = 1; return 0; } bool -boot_enc_valid(struct enc_key_data *enc_state, int slot) +boot_enc_valid(const struct enc_key_data *enc_state) { - return enc_state[slot].valid; + return enc_state->valid; } void -boot_enc_encrypt(struct enc_key_data *enc_state, int slot, uint32_t off, +boot_enc_encrypt(struct enc_key_data *enc, uint32_t off, uint32_t sz, uint32_t blk_off, uint8_t *buf) { - struct enc_key_data *enc = &enc_state[slot]; uint8_t nonce[16]; /* Nothing to do with size == 0 */ @@ -688,10 +686,9 @@ boot_enc_encrypt(struct enc_key_data *enc_state, int slot, uint32_t off, } void -boot_enc_decrypt(struct enc_key_data *enc_state, int slot, uint32_t off, +boot_enc_decrypt(struct enc_key_data *enc, uint32_t off, uint32_t sz, uint32_t blk_off, uint8_t *buf) { - struct enc_key_data *enc = &enc_state[slot]; uint8_t nonce[16]; /* Nothing to do with size == 0 */ @@ -718,7 +715,7 @@ boot_enc_zeroize(struct enc_key_data *enc_state) { uint8_t slot; for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { - (void)boot_enc_drop(enc_state, slot); + (void)boot_enc_drop(&enc_state[slot]); } memset(enc_state, 0, sizeof(struct enc_key_data) * BOOT_NUM_SLOTS); } diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 11f7d718c..dea9388d6 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -648,7 +648,7 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, if (rc < 0) { FIH_RET(fih_rc); } - if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_SECONDARY, bs)) { + if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY), bs->enckey[BOOT_SLOT_SECONDARY])) { FIH_RET(fih_rc); } } @@ -1381,11 +1381,11 @@ boot_copy_region(struct boot_loader_state *state, } } if (source_slot == 0) { - boot_enc_encrypt(BOOT_CURR_ENC(state), source_slot, + boot_enc_encrypt(BOOT_CURR_ENC_SLOT(state, source_slot), (abs_off + idx) - hdr->ih_hdr_size, blk_sz, blk_off, &buf[idx]); } else { - boot_enc_decrypt(BOOT_CURR_ENC(state), source_slot, + boot_enc_decrypt(BOOT_CURR_ENC_SLOT(state, source_slot), (abs_off + idx) - hdr->ih_hdr_size, blk_sz, blk_off, &buf[idx]); } @@ -1499,7 +1499,7 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) if (rc < 0) { return BOOT_EBADIMAGE; } - if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_SECONDARY, bs)) { + if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY), bs->enckey[BOOT_SLOT_SECONDARY])) { return BOOT_EBADIMAGE; } } @@ -1621,7 +1621,7 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) assert(rc >= 0); if (rc == 0) { - rc = boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_PRIMARY, bs); + rc = boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_PRIMARY), bs->enckey[BOOT_SLOT_PRIMARY]); assert(rc == 0); } else { rc = 0; @@ -1645,7 +1645,7 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) assert(rc >= 0); if (rc == 0) { - rc = boot_enc_set_key(BOOT_CURR_ENC(state), BOOT_SLOT_SECONDARY, bs); + rc = boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY), bs->enckey[BOOT_SLOT_SECONDARY]); assert(rc == 0); } else { rc = 0; @@ -1676,7 +1676,7 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) #ifdef MCUBOOT_ENC_IMAGES for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { - boot_enc_init(BOOT_CURR_ENC(state), slot); + boot_enc_init(BOOT_CURR_ENC_SLOT(state, slot)); rc = boot_read_enc_key(fap, slot, bs); assert(rc == 0); @@ -1688,7 +1688,7 @@ boot_swap_image(struct boot_loader_state *state, struct boot_status *bs) } if (i != BOOT_ENC_KEY_SIZE) { - boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs); + boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, slot), bs->enckey[slot]); } } #endif diff --git a/boot/bootutil/src/ram_load.c b/boot/bootutil/src/ram_load.c index cfbee60ca..692db0b34 100644 --- a/boot/bootutil/src/ram_load.c +++ b/boot/bootutil/src/ram_load.c @@ -155,7 +155,7 @@ boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state, } /* if rc > 0 then the key has already been loaded */ - if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) { + if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, slot), bs.enckey[slot])) { goto done; } @@ -176,7 +176,7 @@ boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state, * Part of the chunk is encrypted payload */ blk_sz = tlv_off - (bytes_copied); } - boot_enc_decrypt(BOOT_CURR_ENC(state), slot, + boot_enc_decrypt(BOOT_CURR_ENC_SLOT(state, slot), (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz, blk_off, cur_dst); bytes_copied += chunk_sz; From 6b2fd50d40ccd9659658ed207204ec34a0634dcb Mon Sep 17 00:00:00 2001 From: Stefan Gloor Date: Thu, 2 Oct 2025 14:14:48 +0200 Subject: [PATCH 085/149] [nrf fromtree] boot: bootutil: fix image_index definition image_index is used when when MCUBOOT_BUILTIN_KEY and EXPECTED_SIG_TLV is set, but in this case this variable is never defined. Signed-off-by: Stefan Gloor Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 17a6ecd279d631abfd865bfa041d40964f9ecc62) --- boot/bootutil/src/image_validate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index f40667866..0639aac10 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -204,8 +204,10 @@ bootutil_img_validate(struct boot_loader_state *state, int seed_len, uint8_t *out_hash ) { -#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) \ - || defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) +#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || \ + (defined(EXPECTED_SIG_TLV) && defined(MCUBOOT_BUILTIN_KEY)) || \ + defined(MCUBOOT_HW_ROLLBACK_PROT) || \ + defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state)); #endif uint32_t off; From 157bac2b2ef7e958505918192d8d2847a186bd0b Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Wed, 22 Oct 2025 16:41:04 +0200 Subject: [PATCH 086/149] [nrf fromtree] loader: Fix compile-time issues in loader.c Fix a few minor issues in loader.c file when MCUBOOT_VERIFY_IMG_ADDRESS is enabled. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 5311589b5ff5f9f4a29ffd31074bbc59f4ae100a) --- boot/bootutil/src/loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index dea9388d6..098895299 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -86,7 +86,7 @@ static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0}; #endif /* Valid only for ARM Cortext M */ -#define RESET_OFFSET (2 * sizeof(uin32_t)) +#define RESET_OFFSET (2 * sizeof(uint32_t)) #if BOOT_MAX_ALIGN > 1024 #define BUF_SZ BOOT_MAX_ALIGN @@ -985,7 +985,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, const uint32_t offset = secondary_hdr->ih_hdr_size + RESET_OFFSET; BOOT_LOG_DBG("Getting image %d internal addr from offset %u", BOOT_CURR_IMG(state), offset); - if (flash_area_read(fap, offset, &internal_img_addr, sizeof(internal_img_addr)) != 0) + if (flash_area_read(fap, offset, &internal_img_addr, sizeof(internal_img_addr)) != 0) { BOOT_LOG_ERR("Failed to read image %d load address", BOOT_CURR_IMG(state)); fih_rc = FIH_NO_BOOTABLE_IMAGE; goto out; From fb94c2fc76b176afaaec37c5f71f6b785e954ca9 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 21 Oct 2025 11:24:12 +0200 Subject: [PATCH 087/149] [nrf fromtree] loader: Rename boot_version_cmp Rename boot_version_cmp(..) to boot_compare_version(..). Reason: most of the boot APIs use verb as the second part of the function name. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 76e56e4f8aef53ab66a0c2383c84bf07e00ce866) --- boot/bootutil/src/loader.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 098895299..ace275f94 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -246,8 +246,7 @@ fill_rsp(struct boot_loader_state *state, struct boot_rsp *rsp) * @retval 1 If ver1 is greater than ver2. */ static int -boot_version_cmp(const struct image_version *ver1, - const struct image_version *ver2) +boot_compare_version(const struct image_version *ver1, const struct image_version *ver2) { #if !defined(MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER) BOOT_LOG_DBG("boot_version_cmp: ver1 %u.%u.%u vs ver2 %u.%u.%u", @@ -330,7 +329,7 @@ boot_verify_slot_dependency(struct boot_loader_state *state, dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver; - rc = boot_version_cmp(dep_version, &dep->image_min_version); + rc = boot_compare_version(dep_version, &dep->image_min_version); #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) if (rc < 0) { /* Dependency not satisfied. @@ -920,7 +919,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, int rc; /* Check if version of secondary slot is sufficient */ - rc = boot_version_cmp( + rc = boot_compare_version( &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); if (rc < 0 && boot_check_header_erased(state, BOOT_SLOT_PRIMARY)) { @@ -2159,8 +2158,9 @@ check_downgrade_prevention(struct boot_loader_state *state) } } else { - rc = boot_version_cmp(&boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, - &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); + rc = boot_compare_version( + &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, + &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); } if (rc < 0) { /* Image in slot 0 prevents downgrade, delete image in slot 1 */ @@ -2589,7 +2589,7 @@ find_slot_with_highest_version(struct boot_loader_state *state) if (candidate_slot == BOOT_SLOT_NONE) { candidate_slot = slot; } else { - rc = boot_version_cmp( + rc = boot_compare_version( &boot_img_hdr(state, slot)->ih_ver, &boot_img_hdr(state, candidate_slot)->ih_ver); if (rc == 1) { From 1db194b108e25c6d01861532143a07582f211f80 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 21 Oct 2025 11:28:19 +0200 Subject: [PATCH 088/149] [nrf fromtree] loader: Optimize boot_check_header_erased(..) The boot_check_header_erased(..) function may use a common function to check for a buffer value (bootutil_buffer_is_erased). Checking function should return bool intead of int. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 257265c8971c9c8a4881bb42b18dc44bcaf085e4) --- boot/bootutil/src/loader.c | 42 +++++++++----------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index ace275f94..936312b28 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -757,40 +757,21 @@ boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fa return true; } -/* - * Check that a memory area consists of a given value. - */ -static inline bool -boot_data_is_set_to(uint8_t val, void *data, size_t len) -{ - uint8_t i; - uint8_t *p = (uint8_t *)data; - for (i = 0; i < len; i++) { - if (val != p[i]) { - return false; - } - } - return true; -} - -static int +static bool boot_check_header_erased(struct boot_loader_state *state, int slot) { const struct flash_area *fap = NULL; struct image_header *hdr; - uint8_t erased_val; fap = BOOT_IMG_AREA(state, slot); assert(fap != NULL); - erased_val = flash_area_erased_val(fap); - hdr = boot_img_hdr(state, slot); - if (!boot_data_is_set_to(erased_val, &hdr->ih_magic, sizeof(hdr->ih_magic))) { - return -1; + if (bootutil_buffer_is_erased(fap, &hdr->ih_magic, sizeof(hdr->ih_magic))) { + return true; } - return 0; + return false; } #if defined(MCUBOOT_DIRECT_XIP) @@ -857,8 +838,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, assert(fap != NULL); hdr = boot_img_hdr(state, slot); - if (boot_check_header_erased(state, slot) == 0 || - (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) { + if (boot_check_header_erased(state, slot) || (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) { #if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET) /* * This fixes an issue where an image might be erased, but a trailer @@ -922,7 +902,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, rc = boot_compare_version( &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); - if (rc < 0 && boot_check_header_erased(state, BOOT_SLOT_PRIMARY)) { + if (rc < 0 && !boot_check_header_erased(state, BOOT_SLOT_PRIMARY)) { BOOT_LOG_ERR("insufficient version in secondary slot"); boot_scramble_slot(fap, slot); /* Image in the secondary slot does not satisfy version requirement. @@ -1734,9 +1714,8 @@ boot_perform_update(struct boot_loader_state *state, struct boot_status *bs) * already been checked). */ FIH_DECLARE(fih_rc, FIH_FAILURE); - rc = boot_check_header_erased(state, BOOT_SLOT_PRIMARY); FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SLOT_PRIMARY, bs, 0); - if (rc == 0 || FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + if (boot_check_header_erased(state, BOOT_SLOT_PRIMARY) || FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { rc = boot_copy_image(state, bs); } else { rc = boot_swap_image(state, bs); @@ -1966,7 +1945,7 @@ boot_prepare_image_for_update(struct boot_loader_state *state, rc = boot_read_image_headers(state, !boot_status_is_reset(bs), bs); #ifdef MCUBOOT_BOOTSTRAP /* When bootstrapping it's OK to not have image magic in the primary slot */ - if (rc != 0 && boot_check_header_erased(state, BOOT_SLOT_PRIMARY) != 0) { + if (rc != 0 && !boot_check_header_erased(state, BOOT_SLOT_PRIMARY)) { #else if (rc != 0) { #endif @@ -2045,11 +2024,10 @@ boot_prepare_image_for_update(struct boot_loader_state *state, * magic, so also run validation on the primary slot to be * sure it's not OK. */ - rc = boot_check_header_erased(state, BOOT_SLOT_PRIMARY); FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SLOT_PRIMARY, bs, 0); - - if (rc == 0 || FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + if (boot_check_header_erased(state, BOOT_SLOT_PRIMARY) || + FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { rc = (boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_magic == IMAGE_MAGIC) ? 1: 0; FIH_CALL(boot_validate_slot, fih_rc, From e3a2d6618a3c7845f9311958374cb64ecad42198 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 21 Oct 2025 11:30:02 +0200 Subject: [PATCH 089/149] [nrf fromtree] loader: Unify header_valid(..) API Rename boot_is_header_valid(..) to boot_check_header_valid(..). The fap and hdr arguments are misleading - they should always point to the same slot. Change the function signature to use slot number instead. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit dcc66e511d88cb3025371c7f68290d1fe3b64e6d) --- boot/bootutil/src/loader.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 936312b28..7f5b47f94 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -701,13 +701,16 @@ split_image_check(struct image_header *app_hdr, * are present but these features are not enabled. */ static bool -boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fap, - struct boot_loader_state *state) +boot_check_header_valid(struct boot_loader_state *state, int slot) { + const struct flash_area *fap = NULL; + struct image_header *hdr; uint32_t size; - (void)state; + fap = BOOT_IMG_AREA(state, slot); + assert(fap != NULL); + hdr = boot_img_hdr(state, slot); if (hdr->ih_magic != IMAGE_MAGIC) { return false; } @@ -913,7 +916,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, } } #endif - if (!boot_is_header_valid(hdr, fap, state)) { + if (!boot_check_header_valid(state, slot)) { fih_rc = FIH_FAILURE; } else { BOOT_HOOK_CALL_FIH(boot_image_check_hook, FIH_BOOT_HOOK_REGULAR, @@ -2528,7 +2531,7 @@ boot_get_slot_usage(struct boot_loader_state *state) for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { hdr = boot_img_hdr(state, slot); - if (boot_is_header_valid(hdr, BOOT_IMG_AREA(state, slot), state)) { + if (boot_check_header_valid(state, slot)) { state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = true; BOOT_LOG_IMAGE_INFO(slot, hdr); } else { From bea9d0adefc960ba5d9af36e187500c0b7e9098e Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 21 Oct 2025 11:33:34 +0200 Subject: [PATCH 090/149] [nrf fromtree] loader: Unify image check API. Rename boot_image_check(..) to boot_check_image(..). Most of boot APIs use verb as the second part of the function name. The fap and hdr arguments are misleading - they should always point to the same slot. Change the function signature to use slot number instead. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit f2d3f00a67796d699cde278ea24f1ae958b1939d) --- boot/bootutil/src/loader.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 7f5b47f94..9b0d09c90 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -624,16 +624,18 @@ boot_write_status(const struct boot_loader_state *state, struct boot_status *bs) * Validate image hash/signature and optionally the security counter in a slot. */ static fih_ret -boot_image_check(struct boot_loader_state *state, struct image_header *hdr, - const struct flash_area *fap, struct boot_status *bs) +boot_check_image(struct boot_loader_state *state, struct boot_status *bs, int slot) { TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ]; int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); + const struct flash_area *fap = NULL; + struct image_header *hdr; -#if (BOOT_IMAGE_NUMBER == 1) - (void)state; -#endif + fap = BOOT_IMG_AREA(state, slot); + assert(fap != NULL); + + hdr = boot_img_hdr(state, slot); (void)bs; (void)rc; @@ -922,7 +924,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, BOOT_HOOK_CALL_FIH(boot_image_check_hook, FIH_BOOT_HOOK_REGULAR, fih_rc, BOOT_CURR_IMG(state), slot); if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) { - FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs); + FIH_CALL(boot_check_image, fih_rc, state, bs, slot); } } #if defined(MCUBOOT_SWAP_USING_OFFSET) From 6cb0be48ee7e812477dce31fc441d81d6048c321 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 21 Oct 2025 11:35:14 +0200 Subject: [PATCH 091/149] [nrf fromtree] bootutil: Add missing docs Add missing API docs for the following functions: - boot_get_loader_state() - boot_get_image_max_sizes() - image_max_size *boot_get_max_app_size() Restrict visibility of the app_size* APIs, based on the configuration. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit fbb88f0899b9a64e592847da723cc0080b9248ba) --- boot/bootutil/include/bootutil/bootutil.h | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/boot/bootutil/include/bootutil/bootutil.h b/boot/bootutil/include/bootutil/bootutil.h index a666b2a31..48d56d1a8 100644 --- a/boot/bootutil/include/bootutil/bootutil.h +++ b/boot/bootutil/include/bootutil/bootutil.h @@ -88,9 +88,36 @@ fih_ret boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id); void boot_state_clear(struct boot_loader_state *state); fih_ret context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp); + +/** + * Returns a pointer to the boot loader state structure. + * + * @return Pointer to the boot loader state structure. + */ struct boot_loader_state *boot_get_loader_state(void); + +#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING) +/** + * Returns pointer to array of image maximum sizes. + * + * @note This function provides a RAW access to the structure. The sizes may not be + * calculated yet. Use boot_get_max_app_size() to ensure the sizes are calculated. + * + * @return Pointer to array of image maximum sizes. + */ struct image_max_size *boot_get_image_max_sizes(void); + +/** + * Fetches the maximum allowed size of all application images. + * + * @note In contrast to boot_get_image_max_sizes(), this function will fetch the sizes + * if they are not yet calculated. + * + * @return A pointer to the structure containing the maximum sizes of images. + */ const struct image_max_size *boot_get_max_app_size(void); +#endif /* MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO || MCUBOOT_DATA_SHARING */ + void boot_fetch_slot_state_sizes(void); uint32_t boot_get_state_secondary_offset(struct boot_loader_state *state, const struct flash_area *fap); From 568a35dd6fbabac02768a7a1dad604b4ed323147 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 21 Oct 2025 11:42:14 +0200 Subject: [PATCH 092/149] [nrf fromtree] bootutil: Move state-independent area APIs Move functions, that operate on the flash area and does not require the bootloader state or bootloader status into a separate, dedicated file. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 0248a0234de042b3f1b4b49ac8595972783f0a3e) --- boot/bootutil/CMakeLists.txt | 1 + boot/bootutil/src/bootutil_area.c | 400 ++++++++++++++++++++++++++++++ boot/bootutil/src/bootutil_area.h | 163 ++++++++++++ boot/bootutil/src/bootutil_misc.c | 259 ------------------- boot/bootutil/src/bootutil_priv.h | 68 +---- boot/bootutil/src/loader.c | 143 ----------- boot/espressif/CMakeLists.txt | 1 + boot/zephyr/CMakeLists.txt | 1 + sim/mcuboot-sys/build.rs | 1 + 9 files changed, 568 insertions(+), 469 deletions(-) create mode 100644 boot/bootutil/src/bootutil_area.c create mode 100644 boot/bootutil/src/bootutil_area.h diff --git a/boot/bootutil/CMakeLists.txt b/boot/bootutil/CMakeLists.txt index 950a4c152..e77c3cb3d 100644 --- a/boot/bootutil/CMakeLists.txt +++ b/boot/bootutil/CMakeLists.txt @@ -21,6 +21,7 @@ target_sources(bootutil src/bootutil_img_hash.c src/bootutil_img_security_cnt.c src/bootutil_misc.c + src/bootutil_area.c src/bootutil_public.c src/caps.c src/encrypted.c diff --git a/boot/bootutil/src/bootutil_area.c b/boot/bootutil/src/bootutil_area.c new file mode 100644 index 000000000..302d3f897 --- /dev/null +++ b/boot/bootutil/src/bootutil_area.c @@ -0,0 +1,400 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2017-2019 Linaro LTD + * Copyright (c) 2016-2019 JUUL Labs + * Copyright (c) 2019-2020 Arm Limited + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * Original license: + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 "bootutil_area.h" +#include "bootutil/image.h" +#include "bootutil/bootutil_public.h" +#ifdef MCUBOOT_ENC_IMAGES +#include "bootutil/enc_key.h" +#endif +#include "bootutil/bootutil_log.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +#if !defined(MCUBOOT_OVERWRITE_ONLY) && \ + !defined(MCUBOOT_SWAP_USING_MOVE) && \ + !defined(MCUBOOT_SWAP_USING_OFFSET) && \ + !defined(MCUBOOT_DIRECT_XIP) && \ + !defined(MCUBOOT_RAM_LOAD) && \ + !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) && \ + !defined(MCUBOOT_FIRMWARE_LOADER) +#define MCUBOOT_SWAP_USING_SCRATCH 1 +#endif + +/** + * Amount of space used to save information required when doing a swap, + * or while a swap is under progress, but not the status of sector swap + * progress itself. + */ +static inline uint32_t +boot_trailer_info_sz(void) +{ + return ( +#ifdef MCUBOOT_ENC_IMAGES + /* encryption keys */ +# if MCUBOOT_SWAP_SAVE_ENCTLV + BOOT_ENC_TLV_ALIGN_SIZE * 2 + +# else + BOOT_ENC_KEY_ALIGN_SIZE * 2 + +# endif +#endif + /* swap_type + copy_done + image_ok + swap_size */ + BOOT_MAX_ALIGN * 4 + +#ifdef MCUBOOT_SWAP_USING_OFFSET + /* TLV size for both slots */ + BOOT_MAX_ALIGN + +#endif + BOOT_MAGIC_ALIGN_SIZE + ); +} + +/** + * Amount of space used to maintain progress information for a single swap + * operation. + */ +static inline uint32_t +boot_status_entry_sz(uint32_t min_write_sz) +{ +#if defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \ + defined(MCUBOOT_FIRMWARE_LOADER) || \ + defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD) + /* Single image MCUboot modes do not have a swap status fields */ + return 0; +#else + return BOOT_STATUS_STATE_COUNT * min_write_sz; +#endif +} + +uint32_t +boot_status_sz(uint32_t min_write_sz) +{ + return BOOT_STATUS_MAX_ENTRIES * boot_status_entry_sz(min_write_sz); +} + +uint32_t +boot_trailer_sz(uint32_t min_write_sz) +{ + return boot_status_sz(min_write_sz) + boot_trailer_info_sz(); +} + +#if MCUBOOT_SWAP_USING_SCRATCH +uint32_t boot_scratch_trailer_sz(uint32_t min_write_sz) +{ + return boot_status_entry_sz(min_write_sz) + boot_trailer_info_sz(); +} +#endif + +#if defined(MCUBOOT_MINIMAL_SCRAMBLE) +/** + * Get size of header aligned to device erase unit or write block, depending on whether device has + * erase or not. + * + * @param fa The flash_area containing the header. + * @param slot The slot the header belongs to. + * @param off Pointer to variable to store the offset of the header. + * @param size Pointer to variable to store the size of the header. + * + * @return 0 on success; nonzero on failure. + */ +static int +boot_header_scramble_off_sz(const struct flash_area *fa, int slot, size_t *off, size_t *size) +{ + int ret = 0; + const size_t write_block = flash_area_align(fa); + size_t loff = 0; + struct flash_sector sector; + + BOOT_LOG_DBG("boot_header_scramble_off_sz: slot %d", slot); + + (void)slot; +#if defined(MCUBOOT_SWAP_USING_OFFSET) + /* In case of swap offset, header of secondary slot image is positioned + * in second sector of slot. + */ + if (slot == BOOT_SLOT_SECONDARY) { + ret = flash_area_get_sector(fa, 0, §or); + if (ret < 0) { + return ret; + } + loff = flash_sector_get_off(§or); + } +#endif + + if (device_requires_erase(fa)) { + /* For device requiring erase align to erase unit */ + ret = flash_area_get_sector(fa, loff, §or); + if (ret < 0) { + return ret; + } + + *size = flash_sector_get_size(§or); + } else { + /* For device not requiring erase align to write block */ + *size = ALIGN_UP(sizeof(((struct image_header *)0)->ih_magic), write_block); + } + *off = loff; + + BOOT_LOG_DBG("boot_header_scramble_off_sz: size %u", (unsigned int)*size); + + return ret; +} +#endif /* MCUBOOT_MINIMAL_SCRAMBLE */ + +int +boot_trailer_scramble_offset(const struct flash_area *fa, size_t alignment, size_t *off) +{ + int ret = 0; + + BOOT_LOG_DBG("boot_trailer_scramble_offset: flash_area %p, alignment %u", + fa, (unsigned int)alignment); + + /* Not allowed to enforce alignment smaller than device allows */ + if (alignment < flash_area_align(fa)) { + alignment = flash_area_align(fa); + } + + if (device_requires_erase(fa)) { + /* For device requiring erase align to erase unit */ + struct flash_sector sector; + + ret = flash_area_get_sector(fa, flash_area_get_size(fa) - boot_trailer_sz(alignment), + §or); + if (ret < 0) { + return ret; + } + + *off = flash_sector_get_off(§or); + } else { + /* For device not requiring erase align to write block */ + *off = flash_area_get_size(fa) - ALIGN_DOWN(boot_trailer_sz(alignment), alignment); + } + + BOOT_LOG_DBG("boot_trailer_scramble_offset: final alignment %u, offset %u", + (unsigned int)alignment, (unsigned int)*off); + + return ret; +} + +int +boot_erase_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool backwards) +{ + int rc = 0; + + BOOT_LOG_DBG("boot_erase_region: flash_area %p, offset %d, size %d, backwards == %d", + fa, off, size, (int)backwards); + + if (off >= flash_area_get_size(fa) || (flash_area_get_size(fa) - off) < size) { + rc = -1; + goto end; + } else if (device_requires_erase(fa)) { + uint32_t end_offset = 0; + struct flash_sector sector; + + BOOT_LOG_DBG("boot_erase_region: device with erase"); + + if (backwards) { + /* Get the lowest page offset first */ + rc = flash_area_get_sector(fa, off, §or); + + if (rc < 0) { + goto end; + } + + end_offset = flash_sector_get_off(§or); + + /* Set boundary condition, the highest probable offset to erase, within + * last sector to erase + */ + off += size - 1; + } else { + /* Get the highest page offset first */ + rc = flash_area_get_sector(fa, (off + size - 1), §or); + + if (rc < 0) { + goto end; + } + + end_offset = flash_sector_get_off(§or); + } + + while (true) { + /* Size to read in this iteration */ + size_t csize; + + /* Get current sector and, also, correct offset */ + rc = flash_area_get_sector(fa, off, §or); + + if (rc < 0) { + goto end; + } + + /* Corrected offset and size of current sector to erase */ + off = flash_sector_get_off(§or); + csize = flash_sector_get_size(§or); + + rc = flash_area_erase(fa, off, csize); + + if (rc < 0) { + goto end; + } + + MCUBOOT_WATCHDOG_FEED(); + + if (backwards) { + if (end_offset >= off) { + /* Reached the first offset in range and already erased it */ + break; + } + + /* Move down to previous sector, the flash_area_get_sector will + * correct the value to real page offset + */ + off -= 1; + } else { + /* Move up to next sector */ + off += csize; + + if (off > end_offset) { + /* Reached the end offset in range and already erased it */ + break; + } + + /* Workaround for flash_sector_get_off() being broken in mynewt, hangs with + * infinite loop if this is not present, should be removed if bug is fixed. + */ + off += 1; + } + } + } else { + BOOT_LOG_DBG("boot_erase_region: device without erase"); + } + +end: + return rc; +} + +int +boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool backwards) +{ + int rc = 0; + + BOOT_LOG_DBG("boot_scramble_region: %p %d %d %d", fa, off, size, (int)backwards); + + if (size == 0) { + goto done; + } + + if (device_requires_erase(fa)) { + rc = boot_erase_region(fa, off, size, backwards); + } else if (off >= flash_area_get_size(fa) || (flash_area_get_size(fa) - off) < size) { + rc = -1; + goto done; + } else { + uint8_t buf[BOOT_MAX_ALIGN]; + const size_t write_block = flash_area_align(fa); + uint32_t end_offset; + + BOOT_LOG_DBG("boot_scramble_region: device without erase, overwriting"); + memset(buf, flash_area_erased_val(fa), sizeof(buf)); + + if (backwards) { + end_offset = ALIGN_DOWN(off, write_block); + /* Starting at the last write block in range */ + off += size - write_block; + } else { + end_offset = ALIGN_DOWN((off + size), write_block); + } + BOOT_LOG_DBG("boot_scramble_region: start offset %u, end offset %u", off, end_offset); + + while (off != end_offset) { + /* Write over the area to scramble data that is there */ + rc = flash_area_write(fa, off, buf, write_block); + if (rc != 0) { + BOOT_LOG_DBG("boot_scramble_region: error %d for %p %d %u", + rc, fa, off, (unsigned int)write_block); + break; + } + + MCUBOOT_WATCHDOG_FEED(); + + if (backwards) { + if (end_offset >= off) { + /* Reached the first offset in range and already scrambled it */ + break; + } + + off -= write_block; + } else { + off += write_block; + + if (end_offset <= off) { + /* Reached the end offset in range and already scrambled it */ + break; + } + } + } + } + +done: + return rc; +} + +int +boot_scramble_slot(const struct flash_area *fa, int slot) +{ + size_t size; + int ret = 0; + + (void)slot; + + /* Without minimal entire area needs to be scrambled */ +#if !defined(MCUBOOT_MINIMAL_SCRAMBLE) + size = flash_area_get_size(fa); + ret = boot_scramble_region(fa, 0, size, false); +#else + size_t off = 0; + + ret = boot_header_scramble_off_sz(fa, slot, &off, &size); + if (ret < 0) { + return ret; + } + + ret = boot_scramble_region(fa, off, size, false); + if (ret < 0) { + return ret; + } + + ret = boot_trailer_scramble_offset(fa, 0, &off); + if (ret < 0) { + return ret; + } + + ret = boot_scramble_region(fa, off, (flash_area_get_size(fa) - off), true); +#endif + return ret; +} diff --git a/boot/bootutil/src/bootutil_area.h b/boot/bootutil/src/bootutil_area.h new file mode 100644 index 000000000..5189e9034 --- /dev/null +++ b/boot/bootutil/src/bootutil_area.h @@ -0,0 +1,163 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2017-2019 Linaro LTD + * Copyright (c) 2016-2019 JUUL Labs + * Copyright (c) 2019-2020 Arm Limited + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * Original license: + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +#ifndef H_BOOTUTIL_AREA_ +#define H_BOOTUTIL_AREA_ + +#include +#include +#include +#include +#include + +#if MCUBOOT_SWAP_USING_MOVE +#define BOOT_STATUS_MOVE_STATE_COUNT 1 +#define BOOT_STATUS_SWAP_STATE_COUNT 2 +#define BOOT_STATUS_STATE_COUNT (BOOT_STATUS_MOVE_STATE_COUNT + BOOT_STATUS_SWAP_STATE_COUNT) +#elif MCUBOOT_SWAP_USING_OFFSET +#define BOOT_STATUS_SWAP_STATE_COUNT 2 +#define BOOT_STATUS_STATE_COUNT BOOT_STATUS_SWAP_STATE_COUNT +#else +#define BOOT_STATUS_STATE_COUNT 3 +#endif + +/** Maximum number of image sectors supported by the bootloader. */ +#define BOOT_MAX_IMG_SECTORS MCUBOOT_MAX_IMG_SECTORS +#define BOOT_STATUS_MAX_ENTRIES BOOT_MAX_IMG_SECTORS + +#define BOOT_STATUS_SOURCE_NONE 0 +#define BOOT_STATUS_SOURCE_SCRATCH 1 +#define BOOT_STATUS_SOURCE_PRIMARY_SLOT 2 + +/* Helper macro to avoid compile errors with systems that do not + * provide function to check device type. + * Note: it used to be inline, but somehow compiler would not + * optimize out branches that were impossible when this evaluated to + * just "true". + */ +#if defined(MCUBOOT_SUPPORT_DEV_WITHOUT_ERASE) && defined(MCUBOOT_SUPPORT_DEV_WITH_ERASE) +#define device_requires_erase(fa) (flash_area_erase_required(fa)) +#elif defined(MCUBOOT_SUPPORT_DEV_WITHOUT_ERASE) +#define device_requires_erase(fa) (false) +#else +#define device_requires_erase(fa) (true) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Amount of space used to maintain progress information for all swap + * operations. + */ +uint32_t boot_status_sz(uint32_t min_write_sz); + +/** + * Amount of space used to maintain progress information for all swap + * operations as well as to save information required when doing a swap, + * or while a swap is under progress. + */ +uint32_t boot_trailer_sz(uint32_t min_write_sz); + +/* + * Similar to `boot_trailer_sz` but this function returns the space used to + * store status in the scratch partition. The scratch partition only stores + * status during the swap of the last sector from primary/secondary (which + * is the first swap operation) and thus only requires space for one swap. + */ +uint32_t boot_scratch_trailer_sz(uint32_t min_write_sz); + +/** + * Get offset of trailer aligned to either device erase unit or alignment depending on whether + * device has erase or not. + * + * @param fa The flash_area containing the trailer. + * @param alignment The required alignment for the trailer. + * @param off Pointer to variable to store the offset of the trailer. + * + * @return 0 on success; nonzero on failure. + */ +int boot_trailer_scramble_offset(const struct flash_area *fa, size_t alignment, size_t *off); + +/** + * Erases a region of device that requires erase prior to write; does + * nothing on devices without erase. + * + * @param fa The flash_area containing the region to erase. + * @param off The offset within the flash area to start the erase. + * @param size The number of bytes to erase. + * @param backwards If set to true will erase from end to start addresses, otherwise erases from + * start to end addresses. + * + * @return 0 on success; nonzero on failure. + */ +int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz, bool backwards); + +/** + * Removes data from specified region either by writing erase value in place of data or by doing + * erase, if device has such hardware requirement. + * + * @note This function will fail if off or size are not aligned to device write block size or erase + * block size. + * + * @param fa The flash_area containing the region to erase. + * @param off The offset within the flash area to start the erase. + * @param size The number of bytes to erase. + * @param backwards If set to true will erase from end to start addresses, otherwise erases from + * start to end addresses. + * + * @return 0 on success; nonzero on failure. + */ +int boot_scramble_region(const struct flash_area *fap, uint32_t off, uint32_t sz, bool backwards); + +/** + * Removes enough data from slot to mark it as unused. + * + * This function either scrambles header magic, header sector or entire slot, depending on + * configuration. + * + * @warning This function assumes that header and trailer are not overlapping on write block or + * erase block, if device has erase requirement. + * + * @note This function is intended for removing data not preparing device for write. + * @note Slot is passed here because at this point there is no function matching flash_area object + * to slot. + * + * @param fa Pointer to flash area object for slot + * @param slot Slot the @p fa represents + * + * @return 0 on success; nonzero on failure. + */ +int boot_scramble_slot(const struct flash_area *fap, int slot); + +#ifdef __cplusplus +} +#endif + +#endif /* H_BOOTUTIL_AREA_ */ diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 5359e0d26..67210030d 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -107,153 +107,6 @@ fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n) } #endif -/* - * Amount of space used to save information required when doing a swap, - * or while a swap is under progress, but not the status of sector swap - * progress itself. - */ -static inline uint32_t -boot_trailer_info_sz(void) -{ - return ( -#ifdef MCUBOOT_ENC_IMAGES - /* encryption keys */ -# if MCUBOOT_SWAP_SAVE_ENCTLV - BOOT_ENC_TLV_ALIGN_SIZE * 2 + -# else - BOOT_ENC_KEY_ALIGN_SIZE * 2 + -# endif -#endif - /* swap_type + copy_done + image_ok + swap_size */ - BOOT_MAX_ALIGN * 4 + -#ifdef MCUBOOT_SWAP_USING_OFFSET - /* TLV size for both slots */ - BOOT_MAX_ALIGN + -#endif - BOOT_MAGIC_ALIGN_SIZE - ); -} - -/* - * Amount of space used to maintain progress information for a single swap - * operation. - */ -static inline uint32_t -boot_status_entry_sz(uint32_t min_write_sz) -{ -#if defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \ - defined(MCUBOOT_FIRMWARE_LOADER) || \ - defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD) - /* Single image MCUboot modes do not have a swap status fields */ - return 0; -#else - return BOOT_STATUS_STATE_COUNT * min_write_sz; -#endif -} - -uint32_t -boot_status_sz(uint32_t min_write_sz) -{ - return BOOT_STATUS_MAX_ENTRIES * boot_status_entry_sz(min_write_sz); -} - -uint32_t -boot_trailer_sz(uint32_t min_write_sz) -{ - return boot_status_sz(min_write_sz) + boot_trailer_info_sz(); -} - -int boot_trailer_scramble_offset(const struct flash_area *fa, size_t alignment, - size_t *off) -{ - int ret = 0; - - BOOT_LOG_DBG("boot_trailer_scramble_offset: flash_area %p, alignment %u", - fa, (unsigned int)alignment); - - /* Not allowed to enforce alignment smaller than device allows */ - if (alignment < flash_area_align(fa)) { - alignment = flash_area_align(fa); - } - - if (device_requires_erase(fa)) { - /* For device requiring erase align to erase unit */ - struct flash_sector sector; - - ret = flash_area_get_sector(fa, flash_area_get_size(fa) - boot_trailer_sz(alignment), - §or); - if (ret < 0) { - return ret; - } - - *off = flash_sector_get_off(§or); - } else { - /* For device not requiring erase align to write block */ - *off = flash_area_get_size(fa) - ALIGN_DOWN(boot_trailer_sz(alignment), alignment); - } - - BOOT_LOG_DBG("boot_trailer_scramble_offset: final alignment %u, offset %u", - (unsigned int)alignment, (unsigned int)*off); - - return ret; -} - -int boot_header_scramble_off_sz(const struct flash_area *fa, int slot, size_t *off, - size_t *size) -{ - int ret = 0; - const size_t write_block = flash_area_align(fa); - size_t loff = 0; - struct flash_sector sector; - - BOOT_LOG_DBG("boot_header_scramble_off_sz: slot %d", slot); - - (void)slot; -#if defined(MCUBOOT_SWAP_USING_OFFSET) - /* In case of swap offset, header of secondary slot image is positioned - * in second sector of slot. - */ - if (slot == BOOT_SLOT_SECONDARY) { - ret = flash_area_get_sector(fa, 0, §or); - if (ret < 0) { - return ret; - } - loff = flash_sector_get_off(§or); - } -#endif - - if (device_requires_erase(fa)) { - /* For device requiring erase align to erase unit */ - ret = flash_area_get_sector(fa, loff, §or); - if (ret < 0) { - return ret; - } - - *size = flash_sector_get_size(§or); - } else { - /* For device not requiring erase align to write block */ - *size = ALIGN_UP(sizeof(((struct image_header *)0)->ih_magic), write_block); - } - *off = loff; - - BOOT_LOG_DBG("boot_header_scramble_off_sz: size %u", (unsigned int)*size); - - return ret; -} - -#if MCUBOOT_SWAP_USING_SCRATCH -/* - * Similar to `boot_trailer_sz` but this function returns the space used to - * store status in the scratch partition. The scratch partition only stores - * status during the swap of the last sector from primary/secondary (which - * is the first swap operation) and thus only requires space for one swap. - */ -uint32_t boot_scratch_trailer_sz(uint32_t min_write_sz) -{ - return boot_status_entry_sz(min_write_sz) + boot_trailer_info_sz(); -} -#endif - int boot_status_entries(int image_index, const struct flash_area *fap) { @@ -557,118 +410,6 @@ boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size) } #endif /* !MCUBOOT_OVERWRITE_ONLY */ -/** - * Erases a region of device that requires erase prior to write; does - * nothing on devices without erase. - * - * @param fa The flash_area containing the region to erase. - * @param off The offset within the flash area to start the - * erase. - * @param size The number of bytes to erase. - * @param backwards If set to true will erase from end to start - * addresses, otherwise erases from start to end - * addresses. - * - * @return 0 on success; nonzero on failure. - */ -int -boot_erase_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool backwards) -{ - int rc = 0; - - BOOT_LOG_DBG("boot_erase_region: flash_area %p, offset %d, size %d, backwards == %d", - fa, off, size, (int)backwards); - - if (off >= flash_area_get_size(fa) || (flash_area_get_size(fa) - off) < size) { - rc = -1; - goto end; - } else if (device_requires_erase(fa)) { - uint32_t end_offset = 0; - struct flash_sector sector; - - BOOT_LOG_DBG("boot_erase_region: device with erase"); - - if (backwards) { - /* Get the lowest page offset first */ - rc = flash_area_get_sector(fa, off, §or); - - if (rc < 0) { - goto end; - } - - end_offset = flash_sector_get_off(§or); - - /* Set boundary condition, the highest probable offset to erase, within - * last sector to erase - */ - off += size - 1; - } else { - /* Get the highest page offset first */ - rc = flash_area_get_sector(fa, (off + size - 1), §or); - - if (rc < 0) { - goto end; - } - - end_offset = flash_sector_get_off(§or); - } - - while (true) { - /* Size to read in this iteration */ - size_t csize; - - /* Get current sector and, also, correct offset */ - rc = flash_area_get_sector(fa, off, §or); - - if (rc < 0) { - goto end; - } - - /* Corrected offset and size of current sector to erase */ - off = flash_sector_get_off(§or); - csize = flash_sector_get_size(§or); - - rc = flash_area_erase(fa, off, csize); - - if (rc < 0) { - goto end; - } - - MCUBOOT_WATCHDOG_FEED(); - - if (backwards) { - if (end_offset >= off) { - /* Reached the first offset in range and already erased it */ - break; - } - - /* Move down to previous sector, the flash_area_get_sector will - * correct the value to real page offset - */ - off -= 1; - } else { - /* Move up to next sector */ - off += csize; - - if (off > end_offset) { - /* Reached the end offset in range and already erased it */ - break; - } - - /* Workaround for flash_sector_get_off() being broken in mynewt, hangs with - * infinite loop if this is not present, should be removed if bug is fixed. - */ - off += 1; - } - } - } else { - BOOT_LOG_DBG("boot_erase_region: device without erase"); - } - -end: - return rc; -} - #if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \ defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) int diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 3282243ec..14c56cd21 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -37,6 +37,7 @@ #include "bootutil/bootutil.h" #include "bootutil/image.h" #include "bootutil/fault_injection_hardening.h" +#include "bootutil_area.h" #include "mcuboot_config/mcuboot_config.h" #ifdef MCUBOOT_ENC_IMAGES @@ -196,8 +197,6 @@ _Static_assert(sizeof(boot_img_magic) == BOOT_MAGIC_SZ, "Invalid size for image #endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_ENC_IMAGES */ #endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */ -#define BOOT_MAX_IMG_SECTORS MCUBOOT_MAX_IMG_SECTORS - #define BOOT_LOG_IMAGE_INFO(slot, hdr) \ BOOT_LOG_INF("%-9s slot: version=%u.%u.%u+%u", \ ((slot) == BOOT_SLOT_PRIMARY) ? "Primary" : "Secondary", \ @@ -206,24 +205,6 @@ _Static_assert(sizeof(boot_img_magic) == BOOT_MAGIC_SZ, "Invalid size for image (hdr)->ih_ver.iv_revision, \ (hdr)->ih_ver.iv_build_num) -#if MCUBOOT_SWAP_USING_MOVE -#define BOOT_STATUS_MOVE_STATE_COUNT 1 -#define BOOT_STATUS_SWAP_STATE_COUNT 2 -#define BOOT_STATUS_STATE_COUNT (BOOT_STATUS_MOVE_STATE_COUNT + BOOT_STATUS_SWAP_STATE_COUNT) -#elif MCUBOOT_SWAP_USING_OFFSET -#define BOOT_STATUS_SWAP_STATE_COUNT 2 -#define BOOT_STATUS_STATE_COUNT BOOT_STATUS_SWAP_STATE_COUNT -#else -#define BOOT_STATUS_STATE_COUNT 3 -#endif - -/** Maximum number of image sectors supported by the bootloader. */ -#define BOOT_STATUS_MAX_ENTRIES BOOT_MAX_IMG_SECTORS - -#define BOOT_STATUS_SOURCE_NONE 0 -#define BOOT_STATUS_SOURCE_SCRATCH 1 -#define BOOT_STATUS_SOURCE_PRIMARY_SLOT 2 - /** * Compatibility shim for flash sector type. * @@ -317,18 +298,6 @@ fih_ret boot_fih_memequal(const void *s1, const void *s2, size_t n); const struct flash_area *boot_find_status(const struct boot_loader_state *state, int image_index); int boot_magic_compatible_check(uint8_t tbl_val, uint8_t val); -uint32_t boot_status_sz(uint32_t min_write_sz); -uint32_t boot_trailer_sz(uint32_t min_write_sz); -/* Get offset of trailer aligned to either device erase unit or alignment - * depending on whether device has erase or not. - */ -int boot_trailer_scramble_offset(const struct flash_area *fa, size_t alignment, - size_t *off); -/* Get size of header aligned to device erase unit or write block, - * depending on whether device has erase or not. - */ -int boot_header_scramble_off_sz(const struct flash_area *fa, int slot, size_t *off, - size_t *size); int boot_status_entries(int image_index, const struct flash_area *fap); uint32_t boot_status_off(const struct flash_area *fap); int boot_read_swap_state(const struct flash_area *fap, @@ -366,17 +335,6 @@ int boot_copy_region(struct boot_loader_state *state, const struct flash_area *fap_dst, uint32_t off_src, uint32_t off_dst, uint32_t sz); #endif -/* Prepare for write device that requires erase prior to write. This will - * do nothing on devices without erase requirement. - */ -int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz, bool backwards); -/* Similar to boot_erase_region but will always remove data */ -int boot_scramble_region(const struct flash_area *fap, uint32_t off, uint32_t sz, bool backwards); -/* Makes slot unbootable, either by scrambling header magic, header sector - * or entire slot, depending on settings. - * Note: slot is passed here becuase at this point there is no function - * matching flash_area object to slot */ -int boot_scramble_slot(const struct flash_area *fap, int slot); bool boot_status_is_reset(const struct boot_status *bs); #ifdef MCUBOOT_ENC_IMAGES @@ -385,16 +343,6 @@ int boot_read_enc_key(const struct flash_area *fap, uint8_t slot, struct boot_status *bs); #endif -#if MCUBOOT_SWAP_USING_SCRATCH -/* - * Similar to `boot_trailer_sz` but this function returns the space used to - * store status in the scratch partition. The scratch partition only stores - * status during the swap of the last sector from primary/secondary (which - * is the first swap operation) and thus only requires space for one swap. - */ -uint32_t boot_scratch_trailer_sz(uint32_t min_write_sz); -#endif - /** * Checks that a buffer is erased according to what the erase value for the * flash device provided in `flash_area` is. @@ -601,20 +549,6 @@ uint32_t bootutil_max_image_size(struct boot_loader_state *state, const struct f int boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size); -/* Helper macro to avoid compile errors with systems that do not - * provide function to check device type. - * Note: it used to be inline, but somehow compiler would not - * optimize out branches that were impossible when this evaluated to - * just "true". - */ -#if defined(MCUBOOT_SUPPORT_DEV_WITHOUT_ERASE) && defined(MCUBOOT_SUPPORT_DEV_WITH_ERASE) -#define device_requires_erase(fa) (flash_area_erase_required(fa)) -#elif defined(MCUBOOT_SUPPORT_DEV_WITHOUT_ERASE) -#define device_requires_erase(fa) (false) -#else -#define device_requires_erase(fa) (true) -#endif - #ifdef __cplusplus } #endif diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 9b0d09c90..8513d02c6 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1076,149 +1076,6 @@ boot_validated_swap_type(struct boot_loader_state *state, } #endif -/** - * Removes data from specified region either by writing erase value in place of - * data or by doing erase, if device has such hardware requirement. - * Note that function will fail if off or size are not aligned to device - * write block size or erase block size. - * - * @param fa The flash_area containing the region to erase. - * @param off The offset within the flash area to start the - * erase. - * @param size The number of bytes to erase. - * @param backwards If set to true will erase from end to start - * addresses, otherwise erases from start to end - * addresses. - * - * @return 0 on success; nonzero on failure. - */ -int -boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool backwards) -{ - int rc = 0; - - BOOT_LOG_DBG("boot_scramble_region: %p %d %d %d", fa, off, size, (int)backwards); - - if (size == 0) { - goto done; - } - - if (device_requires_erase(fa)) { - rc = boot_erase_region(fa, off, size, backwards); - } else if (off >= flash_area_get_size(fa) || (flash_area_get_size(fa) - off) < size) { - rc = -1; - goto done; - } else { - uint8_t buf[BOOT_MAX_ALIGN]; - const size_t write_block = flash_area_align(fa); - uint32_t end_offset; - - BOOT_LOG_DBG("boot_scramble_region: device without erase, overwriting"); - memset(buf, flash_area_erased_val(fa), sizeof(buf)); - - if (backwards) { - end_offset = ALIGN_DOWN(off, write_block); - /* Starting at the last write block in range */ - off += size - write_block; - } else { - end_offset = ALIGN_DOWN((off + size), write_block); - } - BOOT_LOG_DBG("boot_scramble_region: start offset %u, end offset %u", off, end_offset); - - while (off != end_offset) { - /* Write over the area to scramble data that is there */ - rc = flash_area_write(fa, off, buf, write_block); - if (rc != 0) { - BOOT_LOG_DBG("boot_scramble_region: error %d for %p %d %u", - rc, fa, off, (unsigned int)write_block); - break; - } - - MCUBOOT_WATCHDOG_FEED(); - - if (backwards) { - if (end_offset >= off) { - /* Reached the first offset in range and already scrambled it */ - break; - } - - off -= write_block; - } else { - off += write_block; - - if (end_offset <= off) { - /* Reached the end offset in range and already scrambled it */ - break; - } - } - } - } - -done: - return rc; -} - -/** - * Removes data from specified region backwards either by writing erase_value - * in place of data or by doing erase, if device has such hardware requirement. - * Note that function will fail if off or size are not aligned to device - * write block size or erase block size. - * - * @param fa The flash_area containing the region to erase. - * @param off The offset within the flash area to start the - * erase. - * @param size The number of bytes to erase. - * - * @return 0 on success; nonzero on failure. - */ - -/** - * Remove enough data from slot to mark is as unused - * Assumption: header and trailer are not overlapping on write block or - * erase block, if device has erase requirement. - * Note that this function is intended for removing data not preparing device - * for write. - * - * @param fa Pointer to flash area object for slot - * @param slot Slot the @p fa represents - * - * @return 0 on success; nonzero on failure. - */ -int -boot_scramble_slot(const struct flash_area *fa, int slot) -{ - size_t size; - int ret = 0; - - (void)slot; - - /* Without minimal entire area needs to be scrambled */ -#if !defined(MCUBOOT_MINIMAL_SCRAMBLE) - size = flash_area_get_size(fa); - ret = boot_scramble_region(fa, 0, size, false); -#else - size_t off = 0; - - ret = boot_header_scramble_off_sz(fa, slot, &off, &size); - if (ret < 0) { - return ret; - } - - ret = boot_scramble_region(fa, off, size, false); - if (ret < 0) { - return ret; - } - - ret = boot_trailer_scramble_offset(fa, 0, &off); - if (ret < 0) { - return ret; - } - - ret = boot_scramble_region(fa, off, (flash_area_get_size(fa) - off), true); -#endif - return ret; -} - #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) #if defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_SWAP_SAVE_ENCTLV) diff --git a/boot/espressif/CMakeLists.txt b/boot/espressif/CMakeLists.txt index 0fa2759ea..7195223c4 100644 --- a/boot/espressif/CMakeLists.txt +++ b/boot/espressif/CMakeLists.txt @@ -240,6 +240,7 @@ set(bootutil_srcs ${BOOTUTIL_DIR}/src/bootutil_img_hash.c ${BOOTUTIL_DIR}/src/bootutil_img_security_cnt.c ${BOOTUTIL_DIR}/src/bootutil_misc.c + ${BOOTUTIL_DIR}/src/bootutil_area.c ${BOOTUTIL_DIR}/src/bootutil_public.c ${BOOTUTIL_DIR}/src/caps.c ${BOOTUTIL_DIR}/src/encrypted.c diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 0bf92c477..367299144 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -114,6 +114,7 @@ zephyr_library_sources( ${BOOT_DIR}/bootutil/src/image_ecdsa.c ${BOOT_DIR}/bootutil/src/image_ed25519.c ${BOOT_DIR}/bootutil/src/bootutil_misc.c + ${BOOT_DIR}/bootutil/src/bootutil_area.c ${BOOT_DIR}/bootutil/src/fault_injection_hardening.c ) diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs index b04bab404..d9bd0c18f 100644 --- a/sim/mcuboot-sys/build.rs +++ b/sim/mcuboot-sys/build.rs @@ -492,6 +492,7 @@ fn main() { conf.file("../../boot/bootutil/src/swap_offset.c"); conf.file("../../boot/bootutil/src/caps.c"); conf.file("../../boot/bootutil/src/bootutil_misc.c"); + conf.file("../../boot/bootutil/src/bootutil_area.c"); conf.file("../../boot/bootutil/src/bootutil_public.c"); conf.file("../../boot/bootutil/src/tlv.c"); conf.file("../../boot/bootutil/src/fault_injection_hardening.c"); From 37f00fa2d70a3536c210cdef979b63c1a29ba608 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 21 Oct 2025 11:50:40 +0200 Subject: [PATCH 093/149] [nrf fromtree] loader: Move boot_get_max_app_size(..) API Move the boot_get_max_app_size(..) API into bootutil_misc.c as this file has the remaining functions, that operate on the size array (i.e. boot_fetch_slot_state_sizes(..)) and is independent from the update type, thus moving it will reduce the code duplication in the future. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit fccd89052308bf9c16c8834bafb6637c25d6ef49) --- boot/bootutil/src/bootutil_misc.c | 25 +++++++++++++++++++++++++ boot/bootutil/src/loader.c | 27 --------------------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 67210030d..7c8d04012 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -594,6 +594,31 @@ void boot_fetch_slot_state_sizes(void) memset(state, 0, sizeof(struct boot_loader_state)); } #endif +#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING) +const struct image_max_size *boot_get_max_app_size(void) +{ + const struct image_max_size *image_max_sizes = boot_get_image_max_sizes(); + +#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) + uint8_t i = 0; + + while (i < BOOT_IMAGE_NUMBER) { + if (image_max_sizes[i].calculated == true) { + break; + } + + ++i; + } + + if (i == BOOT_IMAGE_NUMBER) { + /* Information not available, need to fetch it */ + boot_fetch_slot_state_sizes(); + } +#endif + + return image_max_sizes; +} +#endif /** * Clears the boot state, so that previous operations have no effect on new diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 8513d02c6..ad7ad28da 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -2886,33 +2886,6 @@ boot_close_all_flash_areas(struct boot_loader_state *state) } } -#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING) -/** - * Fetches the maximum allowed size of the image - */ -const struct image_max_size *boot_get_max_app_size(void) -{ -#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) - uint8_t i = 0; - - while (i < BOOT_IMAGE_NUMBER) { - if (image_max_sizes[i].calculated == true) { - break; - } - - ++i; - } - - if (i == BOOT_IMAGE_NUMBER) { - /* Information not available, need to fetch it */ - boot_fetch_slot_state_sizes(); - } -#endif - - return image_max_sizes; -} -#endif - #if defined(MCUBOOT_SWAP_USING_OFFSET) uint32_t boot_get_state_secondary_offset(struct boot_loader_state *state, const struct flash_area *fap) From 591da85c7817cbefedacc787b178239cb81767b7 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 21 Oct 2025 11:48:08 +0200 Subject: [PATCH 094/149] [nrf fromtree] bootutil: Move update-independent code Move functions from loader.c that are independent from the update type into a dedicated file. That way it will be easier to provide alternative loader type without massive code duplication. This file is intended to be used by loader-like files instead and should not be included in the bootutil/_priv.h headers. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 56538cf698caaebdf80c9308e62e2aca9d9b6c02) --- boot/bootutil/CMakeLists.txt | 1 + boot/bootutil/src/bootutil_loader.c | 383 ++++++++++++++++++++++++++ boot/bootutil/src/bootutil_loader.h | 185 +++++++++++++ boot/bootutil/src/loader.c | 400 +--------------------------- boot/espressif/CMakeLists.txt | 1 + boot/zephyr/CMakeLists.txt | 1 + sim/mcuboot-sys/build.rs | 1 + 7 files changed, 574 insertions(+), 398 deletions(-) create mode 100644 boot/bootutil/src/bootutil_loader.c create mode 100644 boot/bootutil/src/bootutil_loader.h diff --git a/boot/bootutil/CMakeLists.txt b/boot/bootutil/CMakeLists.txt index e77c3cb3d..b6abb7fff 100644 --- a/boot/bootutil/CMakeLists.txt +++ b/boot/bootutil/CMakeLists.txt @@ -22,6 +22,7 @@ target_sources(bootutil src/bootutil_img_security_cnt.c src/bootutil_misc.c src/bootutil_area.c + src/bootutil_loader.c src/bootutil_public.c src/caps.c src/encrypted.c diff --git a/boot/bootutil/src/bootutil_loader.c b/boot/bootutil/src/bootutil_loader.c new file mode 100644 index 000000000..e71137ec9 --- /dev/null +++ b/boot/bootutil/src/bootutil_loader.c @@ -0,0 +1,383 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2016-2020 Linaro LTD + * Copyright (c) 2016-2019 JUUL Labs + * Copyright (c) 2019-2023 Arm Limited + * Copyright (c) 2024-2025 Nordic Semiconductor ASA + * + * Original license: + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * This file provides an interface to the manifest-based boot loader. + * Functions defined in this file should only be called while the boot loader is + * running. + */ + +#include "bootutil_loader.h" +#include "bootutil/boot_record.h" +#include "bootutil/boot_hooks.h" +#ifdef MCUBOOT_ENC_IMAGES +#include "bootutil/enc_key.h" +#endif +#ifdef MCUBOOT_HW_ROLLBACK_PROT +#include "bootutil/security_cnt.h" +#endif +#if defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET) || \ + defined(MCUBOOT_SWAP_USING_SCRATCH) +#include "swap_priv.h" +#endif +#include "bootutil/bootutil_log.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +bool +boot_check_header_erased(struct boot_loader_state *state, int slot) +{ + const struct flash_area *fap = NULL; + struct image_header *hdr; + + fap = BOOT_IMG_AREA(state, slot); + assert(fap != NULL); + + hdr = boot_img_hdr(state, slot); + if (bootutil_buffer_is_erased(fap, &hdr->ih_magic, sizeof(hdr->ih_magic))) { + return true; + } + + return false; +} + +bool +boot_check_header_valid(struct boot_loader_state *state, int slot) +{ + const struct flash_area *fap = NULL; + struct image_header *hdr; + uint32_t size; + + fap = BOOT_IMG_AREA(state, slot); + assert(fap != NULL); + + hdr = boot_img_hdr(state, slot); + if (hdr->ih_magic != IMAGE_MAGIC) { + return false; + } + + if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size)) { + return false; + } + +#ifdef MCUBOOT_DECOMPRESS_IMAGES + if (!MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), hdr)) { +#else + if (1) { +#endif + if (!boot_u32_safe_add(&size, size, hdr->ih_protect_tlv_size)) { + return false; + } + } + + if (size >= flash_area_get_size(fap)) { + return false; + } + +#if !defined(MCUBOOT_ENC_IMAGES) + if (IS_ENCRYPTED(hdr)) { + return false; + } +#else + if ((hdr->ih_flags & IMAGE_F_ENCRYPTED_AES128) && + (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES256)) + { + return false; + } +#endif + +#if !defined(MCUBOOT_DECOMPRESS_IMAGES) + if (IS_COMPRESSED(hdr)) { + return false; + } +#else + if ((hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1) && + (hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) + { + return false; + } +#endif + + return true; +} + +int +boot_read_image_headers(struct boot_loader_state *state, bool require_all, struct boot_status *bs) +{ + int rc; + int i; + + for (i = 0; i < BOOT_NUM_SLOTS; i++) { + rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR, + BOOT_CURR_IMG(state), i, boot_img_hdr(state, i)); + if (rc == BOOT_HOOK_REGULAR) + { + rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs); + } + if (rc != 0) { + /* If `require_all` is set, fail on any single fail, otherwise + * if at least the first slot's header was read successfully, + * then the boot loader can attempt a boot. + * + * Failure to read any headers is a fatal error. + */ + if (i > 0 && !require_all) { + return 0; + } else { + return rc; + } + } + } + + return 0; +} + +fih_ret +boot_check_image(struct boot_loader_state *state, struct boot_status *bs, int slot) +{ + TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ]; + int rc; + FIH_DECLARE(fih_rc, FIH_FAILURE); + const struct flash_area *fap = NULL; + struct image_header *hdr; + + fap = BOOT_IMG_AREA(state, slot); + assert(fap != NULL); + + hdr = boot_img_hdr(state, slot); + + (void)bs; + (void)rc; + + /* In the case of ram loading the image has already been decrypted as it is + * decrypted when copied in ram + */ +#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD) + if (MUST_DECRYPT(fap, BOOT_CURR_IMG(state), hdr)) { + rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, hdr, fap, bs); + if (rc < 0) { + FIH_RET(fih_rc); + } + if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY), + bs->enckey[BOOT_SLOT_SECONDARY])) { + FIH_RET(fih_rc); + } + } +#endif + + FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, + NULL, 0, NULL); + + FIH_RET(fih_rc); +} + +int +boot_compare_version(const struct image_version *ver1, const struct image_version *ver2) +{ +#if !defined(MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER) + BOOT_LOG_DBG("boot_version_cmp: ver1 %u.%u.%u vs ver2 %u.%u.%u", + (unsigned)ver1->iv_major, (unsigned)ver1->iv_minor, + (unsigned)ver1->iv_revision, (unsigned)ver2->iv_major, + (unsigned)ver2->iv_minor, (unsigned)ver2->iv_revision); +#else + BOOT_LOG_DBG("boot_version_cmp: ver1 %u.%u.%u.%u vs ver2 %u.%u.%u.%u", + (unsigned)ver1->iv_major, (unsigned)ver1->iv_minor, + (unsigned)ver1->iv_revision, (unsigned)ver1->iv_build_num, + (unsigned)ver2->iv_major, (unsigned)ver2->iv_minor, + (unsigned)ver2->iv_revision, (unsigned)ver2->iv_build_num); +#endif + + if (ver1->iv_major > ver2->iv_major) { + return 1; + } + if (ver1->iv_major < ver2->iv_major) { + return -1; + } + /* The major version numbers are equal, continue comparison. */ + if (ver1->iv_minor > ver2->iv_minor) { + return 1; + } + if (ver1->iv_minor < ver2->iv_minor) { + return -1; + } + /* The minor version numbers are equal, continue comparison. */ + if (ver1->iv_revision > ver2->iv_revision) { + return 1; + } + if (ver1->iv_revision < ver2->iv_revision) { + return -1; + } + +#if defined(MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER) + /* The revisions are equal, continue comparison. */ + if (ver1->iv_build_num > ver2->iv_build_num) { + return 1; + } + if (ver1->iv_build_num < ver2->iv_build_num) { + return -1; + } +#endif + + return 0; +} + +#ifdef MCUBOOT_HW_ROLLBACK_PROT +int +boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_slot_idx) +{ + const struct flash_area *fap = NULL; + uint32_t img_security_cnt; + int rc; + + fap = BOOT_IMG_AREA(state, slot); + assert(fap != NULL); + + rc = bootutil_get_img_security_cnt(state, hdr_slot_idx, fap, &img_security_cnt); + if (rc != 0) { + goto done; + } + + rc = boot_nv_security_counter_update(BOOT_CURR_IMG(state), img_security_cnt); + if (rc != 0) { + goto done; + } + +done: + return rc; +} +#endif /* MCUBOOT_HW_ROLLBACK_PROT */ + +int +boot_add_shared_data(struct boot_loader_state *state, uint8_t active_slot) +{ +#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING) + int rc; + +#ifdef MCUBOOT_MEASURED_BOOT + rc = boot_save_boot_status(BOOT_CURR_IMG(state), + boot_img_hdr(state, active_slot), + BOOT_IMG_AREA(state, active_slot)); + if (rc != 0) { + BOOT_LOG_ERR("Failed to add image data to shared area"); + return rc; + } +#endif /* MCUBOOT_MEASURED_BOOT */ + +#ifdef MCUBOOT_DATA_SHARING + rc = boot_save_shared_data(boot_img_hdr(state, active_slot), + BOOT_IMG_AREA(state, active_slot), + active_slot, boot_get_image_max_sizes()); + if (rc != 0) { + BOOT_LOG_ERR("Failed to add data to shared memory area."); + return rc; + } +#endif /* MCUBOOT_DATA_SHARING */ + + return 0; + +#else /* MCUBOOT_MEASURED_BOOT || MCUBOOT_DATA_SHARING */ + (void) (state); + (void) (active_slot); + + return 0; +#endif +} + +#if !defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD) && !defined(MCUBOOT_SINGLE_APPLICATION_SLOT) +int +boot_open_all_flash_areas(struct boot_loader_state *state) +{ + size_t slot; + int rc = 0; + int fa_id; + int image_index; + + IMAGES_ITER(BOOT_CURR_IMG(state)) { +#if BOOT_IMAGE_NUMBER > 1 + if (state->img_mask[BOOT_CURR_IMG(state)]) { + continue; + } +#endif + image_index = BOOT_CURR_IMG(state); + + for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { + fa_id = flash_area_id_from_multi_image_slot(image_index, slot); + rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot)); + assert(rc == 0); + + if (rc != 0) { + BOOT_LOG_ERR("Failed to open flash area ID %d (image %d slot %zu): %d", + fa_id, image_index, slot, rc); + goto out; + } + } + } + +#if MCUBOOT_SWAP_USING_SCRATCH + rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &BOOT_SCRATCH_AREA(state)); + assert(rc == 0); + + if (rc != 0) { + BOOT_LOG_ERR("Failed to open scratch flash area: %d", rc); + goto out; + } +#endif + +out: + if (rc != 0) { + boot_close_all_flash_areas(state); + } + + return rc; +} + +void +boot_close_all_flash_areas(struct boot_loader_state *state) +{ + uint32_t slot; + +#if MCUBOOT_SWAP_USING_SCRATCH + if (BOOT_SCRATCH_AREA(state) != NULL) { + flash_area_close(BOOT_SCRATCH_AREA(state)); + } +#endif + + IMAGES_ITER(BOOT_CURR_IMG(state)) { +#if BOOT_IMAGE_NUMBER > 1 + if (state->img_mask[BOOT_CURR_IMG(state)]) { + continue; + } +#endif + for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { + if (BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot) != NULL) { + flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot)); + } + } + } +} +#endif /* !MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD && !MCUBOOT_SINGLE_APPLICATION_SLOT */ diff --git a/boot/bootutil/src/bootutil_loader.h b/boot/bootutil/src/bootutil_loader.h new file mode 100644 index 000000000..530f09131 --- /dev/null +++ b/boot/bootutil/src/bootutil_loader.h @@ -0,0 +1,185 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2017-2020 Linaro LTD + * Copyright (c) 2017-2019 JUUL Labs + * Copyright (c) 2019-2021 Arm Limited + * Copyright (c) 2024-2025 Nordic Semiconductor ASA + * + * Original license: + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +#ifndef H_BOOTUTIL_LOADER_ +#define H_BOOTUTIL_LOADER_ + +#include +#include + +#include "bootutil/image.h" +#include "bootutil/fault_injection_hardening.h" +#include "bootutil/bootutil.h" +#include "bootutil_priv.h" + +/* + * This macro allows some control on the allocation of local variables. + * When running natively on a target, we don't want to allocated huge + * variables on the stack, so make them global instead. For the simulator + * we want to run as many threads as there are tests, and it's safer + * to just make those variables stack allocated. + */ +#if !defined(__BOOTSIM__) +#define TARGET_STATIC static +#else +#define TARGET_STATIC +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Check whether the header in the given slot is erased. + * + * @param state Boot loader state where the current image's slot will be checked. + * @param slot Slot number. + * + * @return true if the header is erased, false otherwise. + */ +bool boot_check_header_erased(struct boot_loader_state *state, int slot); + +/** + * Check whether the header is valid. + * + * Valid means that the magic is correct, and that the sizes/offsets are "sane". + * Sane means that there is no overflow on the arithmetic, and that the result fits within the flash + * area we are in. + * Also check the flags in the image and class the image as invalid if flags for + * encryption/compression are present but these features are not enabled. + * + * @param state Boot loader state where the current image's slot will be checked. + * @param slot Slot number. + * + * @return true if the header is valid, false otherwise. + */ +bool boot_check_header_valid(struct boot_loader_state *state, int slot); + +/** + * Reads image headers from all slots for the current image. + * + * This function uses boot_read_image_header() to read each slot's image header. + * In all update scenarios, this function checks if an image contains the valid magic tag. + * In swap type updates, it also configures/restores the bootloader state as well as status to + * continue any interrupted swap operations. + * + * @param state Boot loader status information. + * @param require_all If true, all image headers must be read successfully; + * if false, reading at least the first slot's header is sufficient. + * @param bs Pointer to boot status structure; may be NULL. + * + * @return 0 on success; nonzero on failure. + */ +int boot_read_image_headers(struct boot_loader_state *state, bool require_all, + struct boot_status *bs); + +/** + * Validate image hash/signature and optionally the security counter in a slot. + * + * @note This function uses bootutil_img_validate() to perform the actual validation. + * + * @param state Boot loader state where the current image's slot will be checked. + * @param bs Pointer to the boot status structure. Used only when encrypted images are validated. + * @param slot Slot number. + * + * @return FIH_SUCCESS if the image is valid, FIH_FAILURE otherwise. + */ +fih_ret boot_check_image(struct boot_loader_state *state, struct boot_status *bs, int slot); + +/** + * Compare image version numbers + * + * By default, the comparison does not take build number into account. + * Enable MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER to take the build number into account. + * + * @param ver1 Pointer to the first image version to compare. + * @param ver2 Pointer to the second image version to compare. + * + * @retval -1 If ver1 is less than ver2. + * @retval 0 If the image version numbers are equal. + * @retval 1 If ver1 is greater than ver2. + */ +int boot_compare_version(const struct image_version *ver1, const struct image_version *ver2); + +#ifdef MCUBOOT_HW_ROLLBACK_PROT +/** + * Updates the stored security counter value with the image's security counter value which resides + * in the given slot, only if it's greater than the stored value. + * + * @param state Boot state where the current image's security counter will be updated. + * @param slot Slot number of the image. + * @param hdr_slot_idx Index of the header in the state current image variable containing the + * pointer to the image header structure of the image that is currently stored + * in the given slot. + * + * @return 0 on success; nonzero on failure. + */ +int boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_slot_idx); +#endif /* MCUBOOT_HW_ROLLBACK_PROT */ + +/** + * Saves boot status and shared data for current image. + * + * @note This function is a helper routine, that uses boot_save_boot_status() and + * boot_add_shared_data() to append the respective information, depending on the + * configuration. + * + * @param state Boot loader status information. + * @param active_slot Index of the slot will be loaded for current image. + * + * @return 0 on success; nonzero on failure. + */ +int boot_add_shared_data(struct boot_loader_state *state, uint8_t active_slot); + +/** + * Opens the flash areas of all images. + * + * @note This function opens all areas for all images, including scratch area if + * MCUBOOT_SWAP_USING_SCRATCH is defined. + * + * @param state Bootloader state. + * + * @return 0 on success; nonzero on failure. + */ +int boot_open_all_flash_areas(struct boot_loader_state *state); + +/** + * Closes the flash areas of all images. + * + * @note This function closes all areas for all images, including scratch area if + * MCUBOOT_SWAP_USING_SCRATCH is defined. + * + * @param state Bootloader state. + */ +void boot_close_all_flash_areas(struct boot_loader_state *state); + +#ifdef __cplusplus +} +#endif + +#endif /* H_BOOTUTIL_LOADER_ */ diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index ad7ad28da..547fe6951 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -49,6 +49,7 @@ #include "bootutil/ramload.h" #include "bootutil/boot_hooks.h" #include "bootutil/mcuboot_status.h" +#include "bootutil_loader.h" #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" @@ -68,19 +69,6 @@ static struct boot_loader_state boot_data; static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0}; #endif -/* - * This macro allows some control on the allocation of local variables. - * When running natively on a target, we don't want to allocated huge - * variables on the stack, so make them global instead. For the simulator - * we want to run as many threads as there are tests, and it's safer - * to just make those variables stack allocated. - */ -#if !defined(__BOOTSIM__) -#define TARGET_STATIC static -#else -#define TARGET_STATIC -#endif - #if defined(MCUBOOT_VERIFY_IMG_ADDRESS) && defined(MCUBOOT_CHECK_HEADER_LOAD_ADDRESS) #warning MCUBOOT_CHECK_HEADER_LOAD_ADDRESS takes precedence over MCUBOOT_VERIFY_IMG_ADDRESS #endif @@ -107,91 +95,13 @@ struct boot_loader_state *boot_get_loader_state(void) return &boot_data; } -#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) +#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING) struct image_max_size *boot_get_image_max_sizes(void) { return image_max_sizes; } #endif - -static int -boot_read_image_headers(struct boot_loader_state *state, bool require_all, - struct boot_status *bs) -{ - int rc; - int i; - - for (i = 0; i < BOOT_NUM_SLOTS; i++) { - rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR, - BOOT_CURR_IMG(state), i, boot_img_hdr(state, i)); - if (rc == BOOT_HOOK_REGULAR) - { - rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs); - } - if (rc != 0) { - /* If `require_all` is set, fail on any single fail, otherwise - * if at least the first slot's header was read successfully, - * then the boot loader can attempt a boot. - * - * Failure to read any headers is a fatal error. - */ - if (i > 0 && !require_all) { - return 0; - } else { - return rc; - } - } - } - - return 0; -} - -/** - * Saves boot status and shared data for current image. - * - * @param state Boot loader status information. - * @param active_slot Index of the slot will be loaded for current image. - * - * @return 0 on success; nonzero on failure. - */ -static int -boot_add_shared_data(struct boot_loader_state *state, - uint8_t active_slot) -{ -#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING) - int rc; - -#ifdef MCUBOOT_MEASURED_BOOT - rc = boot_save_boot_status(BOOT_CURR_IMG(state), - boot_img_hdr(state, active_slot), - BOOT_IMG_AREA(state, active_slot)); - if (rc != 0) { - BOOT_LOG_ERR("Failed to add image data to shared area"); - return rc; - } -#endif /* MCUBOOT_MEASURED_BOOT */ - -#ifdef MCUBOOT_DATA_SHARING - rc = boot_save_shared_data(boot_img_hdr(state, active_slot), - BOOT_IMG_AREA(state, active_slot), - active_slot, image_max_sizes); - if (rc != 0) { - BOOT_LOG_ERR("Failed to add data to shared memory area."); - return rc; - } -#endif /* MCUBOOT_DATA_SHARING */ - - return 0; - -#else /* MCUBOOT_MEASURED_BOOT || MCUBOOT_DATA_SHARING */ - (void) (state); - (void) (active_slot); - - return 0; -#endif -} - /** * Fills rsp to indicate how booting should occur. * @@ -228,74 +138,6 @@ fill_rsp(struct boot_loader_state *state, struct boot_rsp *rsp) rsp->br_hdr = boot_img_hdr(state, active_slot); } -#if (BOOT_IMAGE_NUMBER > 1) || \ - defined(MCUBOOT_DIRECT_XIP) || \ - defined(MCUBOOT_RAM_LOAD) || \ - defined(MCUBOOT_DOWNGRADE_PREVENTION) -/** - * Compare image version numbers - * - * By default, the comparison does not take build number into account. - * Enable MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER to take the build number into account. - * - * @param ver1 Pointer to the first image version to compare. - * @param ver2 Pointer to the second image version to compare. - * - * @retval -1 If ver1 is less than ver2. - * @retval 0 If the image version numbers are equal. - * @retval 1 If ver1 is greater than ver2. - */ -static int -boot_compare_version(const struct image_version *ver1, const struct image_version *ver2) -{ -#if !defined(MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER) - BOOT_LOG_DBG("boot_version_cmp: ver1 %u.%u.%u vs ver2 %u.%u.%u", - (unsigned)ver1->iv_major, (unsigned)ver1->iv_minor, - (unsigned)ver1->iv_revision, (unsigned)ver2->iv_major, - (unsigned)ver2->iv_minor, (unsigned)ver2->iv_revision); -#else - BOOT_LOG_DBG("boot_version_cmp: ver1 %u.%u.%u.%u vs ver2 %u.%u.%u.%u", - (unsigned)ver1->iv_major, (unsigned)ver1->iv_minor, - (unsigned)ver1->iv_revision, (unsigned)ver1->iv_build_num, - (unsigned)ver2->iv_major, (unsigned)ver2->iv_minor, - (unsigned)ver2->iv_revision, (unsigned)ver2->iv_build_num); -#endif - - if (ver1->iv_major > ver2->iv_major) { - return 1; - } - if (ver1->iv_major < ver2->iv_major) { - return -1; - } - /* The major version numbers are equal, continue comparison. */ - if (ver1->iv_minor > ver2->iv_minor) { - return 1; - } - if (ver1->iv_minor < ver2->iv_minor) { - return -1; - } - /* The minor version numbers are equal, continue comparison. */ - if (ver1->iv_revision > ver2->iv_revision) { - return 1; - } - if (ver1->iv_revision < ver2->iv_revision) { - return -1; - } - -#if defined(MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER) - /* The revisions are equal, continue comparison. */ - if (ver1->iv_build_num > ver2->iv_build_num) { - return 1; - } - if (ver1->iv_build_num < ver2->iv_build_num) { - return -1; - } -#endif - - return 0; -} -#endif - #if (BOOT_IMAGE_NUMBER > 1) static int @@ -620,47 +462,6 @@ boot_write_status(const struct boot_loader_state *state, struct boot_status *bs) #endif /* !MCUBOOT_RAM_LOAD */ #endif /* !MCUBOOT_DIRECT_XIP */ -/* - * Validate image hash/signature and optionally the security counter in a slot. - */ -static fih_ret -boot_check_image(struct boot_loader_state *state, struct boot_status *bs, int slot) -{ - TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ]; - int rc; - FIH_DECLARE(fih_rc, FIH_FAILURE); - const struct flash_area *fap = NULL; - struct image_header *hdr; - - fap = BOOT_IMG_AREA(state, slot); - assert(fap != NULL); - - hdr = boot_img_hdr(state, slot); - - (void)bs; - (void)rc; - - /* In the case of ram loading the image has already been decrypted as it is - * decrypted when copied in ram - */ -#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD) - if (MUST_DECRYPT(fap, BOOT_CURR_IMG(state), hdr)) { - rc = boot_enc_load(state, BOOT_SLOT_SECONDARY, hdr, fap, bs); - if (rc < 0) { - FIH_RET(fih_rc); - } - if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY), bs->enckey[BOOT_SLOT_SECONDARY])) { - FIH_RET(fih_rc); - } - } -#endif - - FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, - NULL, 0, NULL); - - FIH_RET(fih_rc); -} - #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) static fih_ret split_image_check(struct image_header *app_hdr, @@ -694,91 +495,6 @@ split_image_check(struct image_header *app_hdr, } #endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */ -/* - * Check that this is a valid header. Valid means that the magic is - * correct, and that the sizes/offsets are "sane". Sane means that - * there is no overflow on the arithmetic, and that the result fits - * within the flash area we are in. Also check the flags in the image - * and class the image as invalid if flags for encryption/compression - * are present but these features are not enabled. - */ -static bool -boot_check_header_valid(struct boot_loader_state *state, int slot) -{ - const struct flash_area *fap = NULL; - struct image_header *hdr; - uint32_t size; - - fap = BOOT_IMG_AREA(state, slot); - assert(fap != NULL); - - hdr = boot_img_hdr(state, slot); - if (hdr->ih_magic != IMAGE_MAGIC) { - return false; - } - - if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size)) { - return false; - } - -#ifdef MCUBOOT_DECOMPRESS_IMAGES - if (!MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), hdr)) { -#else - if (1) { -#endif - if (!boot_u32_safe_add(&size, size, hdr->ih_protect_tlv_size)) { - return false; - } - } - - if (size >= flash_area_get_size(fap)) { - return false; - } - -#if !defined(MCUBOOT_ENC_IMAGES) - if (IS_ENCRYPTED(hdr)) { - return false; - } -#else - if ((hdr->ih_flags & IMAGE_F_ENCRYPTED_AES128) && - (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES256)) - { - return false; - } -#endif - -#if !defined(MCUBOOT_DECOMPRESS_IMAGES) - if (IS_COMPRESSED(hdr)) { - return false; - } -#else - if ((hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1) && - (hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) - { - return false; - } -#endif - - return true; -} - -static bool -boot_check_header_erased(struct boot_loader_state *state, int slot) -{ - const struct flash_area *fap = NULL; - struct image_header *hdr; - - fap = BOOT_IMG_AREA(state, slot); - assert(fap != NULL); - - hdr = boot_img_hdr(state, slot); - if (bootutil_buffer_is_erased(fap, &hdr->ih_magic, sizeof(hdr->ih_magic))) { - return true; - } - - return false; -} - #if defined(MCUBOOT_DIRECT_XIP) /** * Check if image in slot has been set with specific ROM address to run from @@ -1001,46 +717,6 @@ boot_validate_slot(struct boot_loader_state *state, int slot, FIH_RET(fih_rc); } -#ifdef MCUBOOT_HW_ROLLBACK_PROT -/** - * Updates the stored security counter value with the image's security counter - * value which resides in the given slot, only if it's greater than the stored - * value. - * - * @param state Boot state where the current image's security counter will - * be updated. - * @param slot Slot number of the image. - * @param hdr_slot_idx Index of the header in the state current image variable - * containing the pointer to the image header structure of the - * image that is currently stored in the given slot. - * - * @return 0 on success; nonzero on failure. - */ -static int -boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_slot_idx) -{ - const struct flash_area *fap = NULL; - uint32_t img_security_cnt; - int rc; - - fap = BOOT_IMG_AREA(state, slot); - assert(fap != NULL); - - rc = bootutil_get_img_security_cnt(state, hdr_slot_idx, fap, &img_security_cnt); - if (rc != 0) { - goto done; - } - - rc = boot_nv_security_counter_update(BOOT_CURR_IMG(state), img_security_cnt); - if (rc != 0) { - goto done; - } - -done: - return rc; -} -#endif /* MCUBOOT_HW_ROLLBACK_PROT */ - #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) /** * Determines which swap operation to perform, if any. If it is determined @@ -2814,78 +2490,6 @@ boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id) FIH_RET(fih_rc); } -int -boot_open_all_flash_areas(struct boot_loader_state *state) -{ - size_t slot; - int rc = 0; - int fa_id; - int image_index; - - IMAGES_ITER(BOOT_CURR_IMG(state)) { -#if BOOT_IMAGE_NUMBER > 1 - if (state->img_mask[BOOT_CURR_IMG(state)]) { - continue; - } -#endif - image_index = BOOT_CURR_IMG(state); - - for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { - fa_id = flash_area_id_from_multi_image_slot(image_index, slot); - rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot)); - assert(rc == 0); - - if (rc != 0) { - BOOT_LOG_ERR("Failed to open flash area ID %d (image %d slot %zu): %d", - fa_id, image_index, slot, rc); - goto out; - } - } - } - -#if MCUBOOT_SWAP_USING_SCRATCH - rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH, &BOOT_SCRATCH_AREA(state)); - assert(rc == 0); - - if (rc != 0) { - BOOT_LOG_ERR("Failed to open scratch flash area: %d", rc); - goto out; - } -#endif - -out: - if (rc != 0) { - boot_close_all_flash_areas(state); - } - - return rc; -} - -void -boot_close_all_flash_areas(struct boot_loader_state *state) -{ - uint32_t slot; - -#if MCUBOOT_SWAP_USING_SCRATCH - if (BOOT_SCRATCH_AREA(state) != NULL) { - flash_area_close(BOOT_SCRATCH_AREA(state)); - } -#endif - - IMAGES_ITER(BOOT_CURR_IMG(state)) { -#if BOOT_IMAGE_NUMBER > 1 - if (state->img_mask[BOOT_CURR_IMG(state)]) { - continue; - } -#endif - for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { - if (BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot) != NULL) { - flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot)); - } - } - } -} - #if defined(MCUBOOT_SWAP_USING_OFFSET) uint32_t boot_get_state_secondary_offset(struct boot_loader_state *state, const struct flash_area *fap) diff --git a/boot/espressif/CMakeLists.txt b/boot/espressif/CMakeLists.txt index 7195223c4..d7dbd7284 100644 --- a/boot/espressif/CMakeLists.txt +++ b/boot/espressif/CMakeLists.txt @@ -241,6 +241,7 @@ set(bootutil_srcs ${BOOTUTIL_DIR}/src/bootutil_img_security_cnt.c ${BOOTUTIL_DIR}/src/bootutil_misc.c ${BOOTUTIL_DIR}/src/bootutil_area.c + ${BOOTUTIL_DIR}/src/bootutil_loader.c ${BOOTUTIL_DIR}/src/bootutil_public.c ${BOOTUTIL_DIR}/src/caps.c ${BOOTUTIL_DIR}/src/encrypted.c diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 367299144..1d3472f82 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -115,6 +115,7 @@ zephyr_library_sources( ${BOOT_DIR}/bootutil/src/image_ed25519.c ${BOOT_DIR}/bootutil/src/bootutil_misc.c ${BOOT_DIR}/bootutil/src/bootutil_area.c + ${BOOT_DIR}/bootutil/src/bootutil_loader.c ${BOOT_DIR}/bootutil/src/fault_injection_hardening.c ) diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs index d9bd0c18f..5276fbeb7 100644 --- a/sim/mcuboot-sys/build.rs +++ b/sim/mcuboot-sys/build.rs @@ -493,6 +493,7 @@ fn main() { conf.file("../../boot/bootutil/src/caps.c"); conf.file("../../boot/bootutil/src/bootutil_misc.c"); conf.file("../../boot/bootutil/src/bootutil_area.c"); + conf.file("../../boot/bootutil/src/bootutil_loader.c"); conf.file("../../boot/bootutil/src/bootutil_public.c"); conf.file("../../boot/bootutil/src/tlv.c"); conf.file("../../boot/bootutil/src/fault_injection_hardening.c"); From 46f2d5c96dfa2c6ec7b966023e0a206eecda420e Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 9 Oct 2025 15:05:21 +0200 Subject: [PATCH 095/149] [nrf fromlist] boot: Add MCUboot manifest TLV Add a possibility to attach a basic manifest with expected digests to an image. Alter the image verification logic, so only digests specified by the manifest are allowed on the device. Upstream PR #: 2511 Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/include/bootutil/image.h | 1 + .../include/bootutil/mcuboot_manifest.h | 99 +++++++++++++++ boot/bootutil/src/bootutil_priv.h | 12 ++ boot/bootutil/src/image_validate.c | 118 +++++++++++++++++- boot/zephyr/Kconfig | 25 ++++ .../include/mcuboot_config/mcuboot_config.h | 8 ++ docs/design.md | 5 +- 7 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 boot/bootutil/include/bootutil/mcuboot_manifest.h diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h index 3d103f8da..63dbac696 100644 --- a/boot/bootutil/include/bootutil/image.h +++ b/boot/bootutil/include/bootutil/image.h @@ -134,6 +134,7 @@ extern "C" { #define IMAGE_TLV_COMP_DEC_SIZE 0x73 /* Compressed decrypted image size */ #define IMAGE_TLV_UUID_VID 0x74 /* Vendor unique identifier */ #define IMAGE_TLV_UUID_CID 0x75 /* Device class unique identifier */ +#define IMAGE_TLV_MANIFEST 0x76 /* Transaction manifest */ /* * vendor reserved TLVs at xxA0-xxFF, * where xx denotes the upper byte diff --git a/boot/bootutil/include/bootutil/mcuboot_manifest.h b/boot/bootutil/include/bootutil/mcuboot_manifest.h new file mode 100644 index 000000000..2f0100640 --- /dev/null +++ b/boot/bootutil/include/bootutil/mcuboot_manifest.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __MCUBOOT_MANIFEST_H__ +#define __MCUBOOT_MANIFEST_H__ + +/** + * @file mcuboot_manifest.h + * + * @note This file is only used when MCUBOOT_MANIFEST_UPDATES is enabled. + */ + +#include +#include "bootutil/bootutil.h" +#include "bootutil/crypto/sha.h" + +#ifndef __packed +#define __packed __attribute__((__packed__)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** Manifest structure for image updates. */ +struct mcuboot_manifest { + uint32_t format; + uint32_t image_count; + /* Skip a digest of the MCUBOOT_MANIFEST_IMAGE_NUMBER image. */ + uint8_t image_hash[MCUBOOT_IMAGE_NUMBER - 1][IMAGE_HASH_SIZE]; +} __packed; + +/** + * @brief Check if the specified manifest has the correct format. + * + * @param[in] manifest The reference to the manifest structure. + * + * @return true on success. + */ +static inline bool bootutil_verify_manifest(const struct mcuboot_manifest *manifest) +{ + if (manifest == NULL) { + return false; + } + + /* Currently only the simplest manifest format is supported */ + if (manifest->format != 0x1) { + return false; + } + + if (manifest->image_count != MCUBOOT_IMAGE_NUMBER - 1) { + return false; + } + + return true; +} + +/** + * @brief Get the image hash from the manifest. + * + * @param[in] manifest The reference to the manifest structure. + * @param[in] image_index The index of the image to get the hash for. + * Must be in range <0, MCUBOOT_IMAGE_NUMBER - 1>, but + * must not be equal to MCUBOOT_MANIFEST_IMAGE_NUMBER. + * + * @return true if hash matches with the manifest, false otherwise. + */ +static inline bool bootutil_verify_manifest_image_hash(const struct mcuboot_manifest *manifest, + const uint8_t *exp_hash, uint32_t image_index) +{ + if (!bootutil_verify_manifest(manifest)) { + return false; + } + + if (image_index >= MCUBOOT_IMAGE_NUMBER) { + return false; + } + + if (image_index < MCUBOOT_MANIFEST_IMAGE_NUMBER) { + if (memcmp(exp_hash, manifest->image_hash[image_index], IMAGE_HASH_SIZE) == 0) { + return true; + } + } else if (image_index > MCUBOOT_MANIFEST_IMAGE_NUMBER) { + if (memcmp(exp_hash, manifest->image_hash[image_index - 1], IMAGE_HASH_SIZE) == 0) { + return true; + } + } + + return false; +} + +#ifdef __cplusplus +} +#endif + +#endif /* __MCUBOOT_MANIFEST_H__ */ diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 14c56cd21..3b442c99a 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -44,6 +44,10 @@ #include "bootutil/enc_key.h" #endif +#ifdef MCUBOOT_MANIFEST_UPDATES +#include "bootutil/mcuboot_manifest.h" +#endif /* MCUBOOT_MANIFEST_UPDATES */ + #ifdef __cplusplus extern "C" { #endif @@ -271,6 +275,14 @@ struct boot_loader_state { #endif } slot_usage[BOOT_IMAGE_NUMBER]; #endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */ + +#if defined(MCUBOOT_MANIFEST_UPDATES) + struct mcuboot_manifest manifest[BOOT_NUM_SLOTS]; + bool manifest_valid[BOOT_NUM_SLOTS]; +#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET) + enum boot_slot matching_manifest[BOOT_IMAGE_NUMBER][BOOT_NUM_SLOTS]; +#endif +#endif }; struct boot_sector_buffer { diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 0639aac10..3c1c5ec7f 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -50,6 +50,10 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); #include "bootutil/mcuboot_uuid.h" #endif /* MCUBOOT_UUID_VID || MCUBOOT_UUID_CID */ +#ifdef MCUBOOT_MANIFEST_UPDATES +#include "bootutil/mcuboot_manifest.h" +#endif /* MCUBOOT_MANIFEST_UPDATES */ + #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -206,7 +210,7 @@ bootutil_img_validate(struct boot_loader_state *state, { #if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || \ (defined(EXPECTED_SIG_TLV) && defined(MCUBOOT_BUILTIN_KEY)) || \ - defined(MCUBOOT_HW_ROLLBACK_PROT) || \ + defined(MCUBOOT_HW_ROLLBACK_PROT) || defined(MCUBOOT_MANIFEST_UPDATES) || \ defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state)); #endif @@ -244,6 +248,11 @@ bootutil_img_validate(struct boot_loader_state *state, uint32_t img_security_cnt = 0; FIH_DECLARE(security_counter_valid, FIH_FAILURE); #endif +#ifdef MCUBOOT_MANIFEST_UPDATES + bool manifest_found = false; + bool manifest_valid = false; + uint8_t slot = (flash_area_get_id(fap) == FLASH_AREA_IMAGE_SECONDARY(image_index) ? 1 : 0); +#endif #ifdef MCUBOOT_UUID_VID struct image_uuid img_uuid_vid = {0x00}; FIH_DECLARE(uuid_vid_valid, FIH_FAILURE); @@ -356,6 +365,69 @@ bootutil_img_validate(struct boot_loader_state *state, goto out; } +#ifdef MCUBOOT_MANIFEST_UPDATES + if (image_index == MCUBOOT_MANIFEST_IMAGE_NUMBER) { + if (!state->manifest_valid[slot]) { + /* Manifest TLV must be processed before any of the image's hash TLV. */ + BOOT_LOG_ERR("bootutil_img_validate: image rejected, manifest not found before " + "image %d hash", image_index); + rc = -1; + goto out; + } + /* Manifest image does not have hash in the manifest. */ + image_hash_valid = 1; + break; + } +#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) || \ + defined(MCUBOOT_SWAP_USING_OFFSET) + state->matching_manifest[image_index][slot] = BOOT_SLOT_NONE; + /* Try to match with the primary manifest first. */ + if (state->manifest_valid[BOOT_SLOT_PRIMARY]) { + if (bootutil_verify_manifest_image_hash(&state->manifest[BOOT_SLOT_PRIMARY], hash, + image_index)) { + state->matching_manifest[image_index][slot] = BOOT_SLOT_PRIMARY; + } + } + + /* Try to match with the secondary manifest if not matched with the primary. */ + if(state->matching_manifest[image_index][slot] == BOOT_SLOT_NONE && + state->manifest_valid[BOOT_SLOT_SECONDARY]) { + if (bootutil_verify_manifest_image_hash(&state->manifest[BOOT_SLOT_SECONDARY], hash, + image_index)) { + state->matching_manifest[image_index][slot] = BOOT_SLOT_SECONDARY; + } + } + + /* No matching manifest found. */ + if (state->matching_manifest[image_index][slot] == BOOT_SLOT_NONE) { + BOOT_LOG_ERR( + "bootutil_img_validate: image rejected, no valid manifest for image %d slot %d", + image_index, slot); + rc = -1; + goto out; + } else { + BOOT_LOG_INF("bootutil_img_validate: image %d slot %d matches manifest in slot %d", + image_index, slot, state->matching_manifest[image_index][slot]); + } +#else /* MCUBOOT_SWAP_USING_SCRATCH || MCUBOOT_SWAP_USING_MOVE || MCUBOOT_SWAP_USING_OFFSET */ + /* Manifest image for a given slot must precede any of other images. */ + if (!state->manifest_valid[slot]) { + /* Manifest TLV must be processed before any of the image's hash TLV. */ + BOOT_LOG_ERR("bootutil_img_validate: image rejected, no valid manifest for slot %d", + slot); + rc = -1; + goto out; + } + + /* Any image, not described by the manifest is considered as invalid. */ + if (!bootutil_verify_manifest_image_hash(&state->manifest[slot], hash, image_index)) { + BOOT_LOG_ERR( + "bootutil_img_validate: image rejected, hash does not match manifest contents"); + FIH_SET(fih_rc, FIH_FAILURE); + goto out; + } +#endif /* MCUBOOT_SWAP_USING_SCRATCH || MCUBOOT_SWAP_USING_MOVE || MCUBOOT_SWAP_USING_OFFSET */ +#endif /* MCUBOOT_MANIFEST_UPDATES */ image_hash_valid = 1; break; } @@ -484,6 +556,43 @@ bootutil_img_validate(struct boot_loader_state *state, break; } #endif /* MCUBOOT_HW_ROLLBACK_PROT */ +#ifdef MCUBOOT_MANIFEST_UPDATES + case IMAGE_TLV_MANIFEST: + { + /* There can be only one manifest and must be a part of image with specific index. */ + if (manifest_found || image_index != MCUBOOT_MANIFEST_IMAGE_NUMBER || + len != sizeof(struct mcuboot_manifest)) { + BOOT_LOG_ERR( + "bootutil_img_validate: image %d slot %d rejected, unexpected manifest TLV", + image_index, slot); + rc = -1; + goto out; + } + + manifest_found = true; + + rc = LOAD_IMAGE_DATA(hdr, fap, off, &state->manifest[slot], + sizeof(struct mcuboot_manifest)); + if (rc) { + BOOT_LOG_ERR("bootutil_img_validate: slot %d rejected, unable to load manifest", + slot); + goto out; + } + + manifest_valid = bootutil_verify_manifest(&state->manifest[slot]); + if (!manifest_valid) { + BOOT_LOG_ERR("bootutil_img_validate: slot %d rejected, invalid manifest contents", + slot); + rc = -1; + goto out; + } + + /* The image's manifest has been successfully verified. */ + state->manifest_valid[slot] = true; + BOOT_LOG_INF("bootutil_img_validate: slot %d manifest verified", slot); + break; + } +#endif #ifdef MCUBOOT_UUID_VID case IMAGE_TLV_UUID_VID: { @@ -564,6 +673,13 @@ bootutil_img_validate(struct boot_loader_state *state, } #endif +#ifdef MCUBOOT_MANIFEST_UPDATES + if (image_index == MCUBOOT_MANIFEST_IMAGE_NUMBER && (!manifest_found || !manifest_valid)) { + BOOT_LOG_ERR("bootutil_img_validate: slot %d rejected, manifest missing or invalid", slot); + rc = -1; + goto out; + } +#endif #ifdef MCUBOOT_UUID_VID if (FIH_NOT_EQ(uuid_vid_valid, FIH_SUCCESS)) { rc = -1; diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index b57c17b6f..c0ec76709 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1072,6 +1072,31 @@ config MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_LIMITED endchoice +config MCUBOOT_MANIFEST_UPDATES + bool "Enable transactional updates" + select EXPERIMENTAL + help + If y, enables support for transactional updates using manifests. + This allows multiple images to be updated atomically. The manifest + is a separate TLV which contains a list of images to update and + their expected hash values. The manifest TLV is a part of an image + that is signed to prevent tampering. + The manifest must be transferred as part of the image with index 0. + It can be a dedicated image, or part of an existing image. + If the second option is selected, all updates must contain an update + for image 0. + +if MCUBOOT_MANIFEST_UPDATES + +config MCUBOOT_MANIFEST_IMAGE_NUMBER + int "Number of image that must include manifest" + default 0 + range 0 UPDATEABLE_IMAGE_NUMBER + help + Specifies the index of the image that must include the manifest. + +endif # MCUBOOT_MANIFEST_UPDATES + config MCUBOOT_UUID_VID bool "Expect vendor unique identifier in image's TLV" help diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index c12ff9028..4c192ca8e 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -235,6 +235,14 @@ #define MCUBOOT_HW_ROLLBACK_PROT_COUNTER_LIMITED #endif +#ifdef CONFIG_MCUBOOT_MANIFEST_UPDATES +#define MCUBOOT_MANIFEST_UPDATES + +#ifdef CONFIG_MCUBOOT_MANIFEST_IMAGE_NUMBER +#define MCUBOOT_MANIFEST_IMAGE_NUMBER CONFIG_MCUBOOT_MANIFEST_IMAGE_NUMBER +#endif /* CONFIG_MCUBOOT_MANIFEST_IMAGE_NUMBER */ +#endif /* CONFIG_MCUBOOT_MANIFEST_UPDATES */ + #ifdef CONFIG_MCUBOOT_UUID_VID #define MCUBOOT_UUID_VID #endif diff --git a/docs/design.md b/docs/design.md index 484066d60..ab532c0f4 100755 --- a/docs/design.md +++ b/docs/design.md @@ -150,8 +150,9 @@ struct image_tlv { * ... * 0xffa0 - 0xfffe */ -#define IMAGE_TLV_UUID_VID 0x80 /* Vendor unique identifier */ -#define IMAGE_TLV_UUID_CID 0x81 /* Device class unique identifier */ +#define IMAGE_TLV_UUID_VID 0x74 /* Vendor unique identifier */ +#define IMAGE_TLV_UUID_CID 0x75 /* Device class unique identifier */ +#define IMAGE_TLV_MANIFEST 0x76 /* Transaction manifest */ ``` Optional type-length-value records (TLVs) containing image metadata are placed From 672f30aee2c84dd27a436cab5b411a70d0afbe3c Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 9 Oct 2025 17:51:17 +0200 Subject: [PATCH 096/149] [nrf fromlist] imgtool: Add a possibility to attach manifest TLV Add a simple logic that allows to attach a manifest TLV to an image. Upstream PR #: 2511 Signed-off-by: Tomasz Chyrowicz --- scripts/imgtool/image.py | 86 ++++++++++++++++++++++++++++++++++++++-- scripts/imgtool/main.py | 9 +++-- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index 017307bab..4476b687e 100755 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -39,6 +39,7 @@ from cryptography.hazmat.primitives.kdf.hkdf import HKDF from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat from intelhex import IntelHex +from yaml import safe_load as yaml_safe_load from . import keys from . import version as versmod @@ -93,6 +94,7 @@ 'COMP_DEC_SIZE' : 0x73, 'UUID_VID': 0x74, 'UUID_CID': 0x75, + 'MANIFEST': 0x76, } TLV_SIZE = 4 @@ -271,6 +273,73 @@ def parse_uuid(namespace, value): return uuid_bytes +class Manifest: + def __init__(self, endian, path): + self.path = path + self.format = 1 + self.data = None + self.config = None + self.endian = endian + self.load() + + def load(self): + try: + with open(self.path) as f: + self.config = yaml_safe_load(f) + format = self.config.get('format', 0) + if isinstance(format, str) and format.isdigit(): + format = int(format) + if format != self.format: + raise click.UsageError(f"Unsupported manifest format: {format}") + + # Encode manifest format + e = STRUCT_ENDIAN_DICT[self.endian] + self.data = struct.pack(e + 'I', format) + + # Encode number of images/hashes + n_images = len(self.config.get('images', [])) + self.data += struct.pack(e + 'I', n_images) + + # Encode each image hash + exp_hash_len = None + for image in self.config.get('images', []): + if 'path' not in image and 'hash' not in image: + raise click.UsageError( + "Manifest image entry must contain either 'path' or 'hash'") + + # Encode hash, based on the signed image path + if 'path' in image: + (result, version, digest, _) = Image.verify(image['path'], None) + if result != VerifyResult.OK: + raise click.UsageError(f"Failed to verify image: {image['path']}") + + if exp_hash_len is None: + exp_hash_len = len(digest) + elif exp_hash_len != len(digest): + raise click.UsageError("All image hashes must have the same length") + self.data += struct.pack(e + f'{exp_hash_len}s', digest) + + # Encode RAW image hash + if 'hash' in image: + if exp_hash_len is None: + exp_hash_len = len(bytes.fromhex(image['hash'])) + elif exp_hash_len != len(bytes.fromhex(image['hash'])): + raise click.UsageError("All image hashes must have the same length") + self.data += struct.pack(e + f'{exp_hash_len}s', bytes.fromhex(image['hash'])) + + except FileNotFoundError: + raise click.UsageError(f"Manifest file {self.path} not found") from None + + def encode(self): + if self.data is None: + raise click.UsageError("Manifest data is empty") + return self.data + + def __len__(self): + return len(self.data) if self.data is not None else 0 + + def __repr__(self): + return f"" class Image: @@ -280,7 +349,7 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, overwrite_only=False, endian="little", load_addr=0, rom_fixed=None, erased_val=None, save_enctlv=False, security_counter=None, max_align=None, - non_bootable=False, vid=None, cid=None): + non_bootable=False, vid=None, cid=None, manifest=None): if load_addr and rom_fixed: raise click.UsageError("Can not set rom_fixed and load_addr at the same time") @@ -311,6 +380,7 @@ def __init__(self, version=None, header_size=IMAGE_HEADER_SIZE, self.non_bootable = non_bootable self.vid = vid self.cid = cid + self.manifest = Manifest(endian=endian, path=manifest) if manifest is not None else None if self.max_align == DEFAULT_MAX_ALIGN: self.boot_magic = bytes([ @@ -340,7 +410,7 @@ def __repr__(self): return "".format( + payloadlen=0x{:x}, vid={}, cid={}, manifest={}>".format( self.version, self.header_size, self.security_counter, @@ -354,7 +424,8 @@ def __repr__(self): self.__class__.__name__, len(self.payload), self.vid, - self.cid) + self.cid, + self.manifest) def load(self, path): """Load an image from a given file""" @@ -539,6 +610,11 @@ def create(self, key, public_key_format, enckey, dependencies=None, # = 4 + 16 = 20 Bytes protected_tlv_size += TLV_SIZE + 16 + if self.manifest is not None: + # Size of the MANIFEST TLV: header ('HH') + payload (len(manifest)) + # = 4 + len(manifest) Bytes + protected_tlv_size += TLV_SIZE + len(self.manifest.encode()) + if sw_type is not None: if len(sw_type) > MAX_SW_TYPE_LENGTH: msg = f"'{sw_type}' is too long ({len(sw_type)} characters) for sw_type. Its " \ @@ -654,6 +730,10 @@ def create(self, key, public_key_format, enckey, dependencies=None, payload = struct.pack(e + '16s', cid) prot_tlv.add('UUID_CID', payload) + if self.manifest is not None: + payload = self.manifest.encode() + prot_tlv.add('MANIFEST', payload) + if custom_tlvs is not None: for tag, value in custom_tlvs.items(): prot_tlv.add(tag, value) diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index c4abf06f1..a7567bad4 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -449,13 +449,15 @@ def convert(self, value, param, ctx): help='Unique vendor identifier, format: (|') @click.option('--cid', default=None, required=False, help='Unique image class identifier, format: (|)') +@click.option('--manifest', default=None, required=False, + help='Path to the update manifest file') def sign(key, public_key_format, align, version, pad_sig, header_size, pad_header, slot_size, pad, confirm, max_sectors, overwrite_only, endian, encrypt_keylen, encrypt, compression, infile, outfile, dependencies, load_addr, hex_addr, erased_val, save_enctlv, security_counter, boot_record, custom_tlv, rom_fixed, max_align, clear, fix_sig, fix_sig_pubkey, sig_out, user_sha, hmac_sha, is_pure, - vector_to_sign, non_bootable, vid, cid): + vector_to_sign, non_bootable, vid, cid, manifest): if confirm: # Confirmed but non-padded images don't make much sense, because @@ -468,7 +470,8 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, endian=endian, load_addr=load_addr, rom_fixed=rom_fixed, erased_val=erased_val, save_enctlv=save_enctlv, security_counter=security_counter, max_align=max_align, - non_bootable=non_bootable, vid=vid, cid=cid) + non_bootable=non_bootable, vid=vid, cid=cid, + manifest=manifest) compression_tlvs = {} img.load(infile) key = load_key(key) if key else None @@ -539,7 +542,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, load_addr=load_addr, rom_fixed=rom_fixed, erased_val=erased_val, save_enctlv=save_enctlv, security_counter=security_counter, max_align=max_align, - vid=vid, cid=cid) + vid=vid, cid=cid, manifest=manifest) compression_filters = [ {"id": lzma.FILTER_LZMA2, "preset": comp_default_preset, "dict_size": comp_default_dictsize, "lp": comp_default_lp, From 7ea3a09b231cb67d9233fb17f918b1bca26f8117 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Wed, 15 Oct 2025 17:54:12 +0200 Subject: [PATCH 097/149] [nrf fromlist] bootutil: Add manifest-based loader for Direct XIP Add a loader variant that is capable of booting images, based on a simple manifest. Upstream PR #: 2511 Signed-off-by: Tomasz Chyrowicz --- boot/bootutil/CMakeLists.txt | 1 + boot/bootutil/src/loader.c | 4 + boot/bootutil/src/loader_manifest_xip.c | 630 ++++++++++++++++++++++++ boot/zephyr/CMakeLists.txt | 20 + 4 files changed, 655 insertions(+) create mode 100644 boot/bootutil/src/loader_manifest_xip.c diff --git a/boot/bootutil/CMakeLists.txt b/boot/bootutil/CMakeLists.txt index b6abb7fff..6d74578d8 100644 --- a/boot/bootutil/CMakeLists.txt +++ b/boot/bootutil/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(bootutil src/image_rsa.c src/image_validate.c src/loader.c + src/loader_manifest_xip.c src/swap_misc.c src/swap_move.c src/swap_scratch.c diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 547fe6951..12276b03d 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -51,6 +51,8 @@ #include "bootutil/mcuboot_status.h" #include "bootutil_loader.h" +#ifndef MCUBOOT_MANIFEST_UPDATES + #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -2501,3 +2503,5 @@ uint32_t boot_get_state_secondary_offset(struct boot_loader_state *state, return 0; } #endif + +#endif /* !MCUBOOT_MANIFEST_UPDATES */ diff --git a/boot/bootutil/src/loader_manifest_xip.c b/boot/bootutil/src/loader_manifest_xip.c new file mode 100644 index 000000000..858fdb82b --- /dev/null +++ b/boot/bootutil/src/loader_manifest_xip.c @@ -0,0 +1,630 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2016-2020 Linaro LTD + * Copyright (c) 2016-2019 JUUL Labs + * Copyright (c) 2019-2023 Arm Limited + * Copyright (c) 2024-2025 Nordic Semiconductor ASA + * + * Original license: + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +/** + * This file provides an interface to the manifest-based boot loader. + * Functions defined in this file should only be called while the boot loader is + * running. + */ + +#include +#include +#include +#include +#include +#include "flash_map_backend/flash_map_backend.h" +#include "mcuboot_config/mcuboot_config.h" +#include "bootutil/bootutil.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/image.h" +#include "bootutil_priv.h" +#include "bootutil/bootutil_log.h" +#include "bootutil/security_cnt.h" +#include "bootutil/fault_injection_hardening.h" +#include "bootutil/boot_hooks.h" +#include "bootutil_loader.h" + +#if defined(MCUBOOT_MANIFEST_UPDATES) && defined(MCUBOOT_DIRECT_XIP) +#include "bootutil/mcuboot_manifest.h" + +#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DECOMPRESS_IMAGES) +#error "Image decompression is not supported when MCUBOOT_DIRECT_XIP is selected." +#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DECOMPRESS_IMAGES */ + +#ifdef MCUBOOT_ENC_IMAGES +#include "bootutil/enc_key.h" +#endif + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +static struct boot_loader_state boot_data; + +#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING) +static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0}; +#endif + +#if BOOT_MAX_ALIGN > 1024 +#define BUF_SZ BOOT_MAX_ALIGN +#else +#define BUF_SZ 1024 +#endif + +struct boot_loader_state *boot_get_loader_state(void) +{ + return &boot_data; +} + +#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING) +struct image_max_size *boot_get_image_max_sizes(void) +{ + return image_max_sizes; +} +#endif + +/** + * Fills rsp to indicate how booting should occur. + * + * @param state Boot loader status information. + * @param rsp boot_rsp struct to fill. + */ +static void +fill_rsp(struct boot_loader_state *state, struct boot_rsp *rsp) +{ + uint32_t active_slot; + + /* Always boot from the first image. */ + BOOT_CURR_IMG(state) = 0; + active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot; + + rsp->br_flash_dev_id = flash_area_get_device_id(BOOT_IMG_AREA(state, active_slot)); + rsp->br_image_off = boot_img_slot_off(state, active_slot); + rsp->br_hdr = boot_img_hdr(state, active_slot); +} + +#if defined(MCUBOOT_DIRECT_XIP) +/** + * Check if image in slot has been set with specific ROM address to run from + * and whether the slot starts at that address. + * + * @returns 0 if IMAGE_F_ROM_FIXED flag is not set; + * 0 if IMAGE_F_ROM_FIXED flag is set and ROM address specified in + * header matches the slot address; + * 1 if IMF_F_ROM_FIXED flag is set but ROM address specified in header + * does not match the slot address. + */ +static bool +boot_rom_address_check(struct boot_loader_state *state) +{ + uint32_t active_slot; + const struct image_header *hdr; + uint32_t f_off; + + active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot; + hdr = boot_img_hdr(state, active_slot); + f_off = boot_img_slot_off(state, active_slot); + + if (hdr->ih_flags & IMAGE_F_ROM_FIXED && hdr->ih_load_addr != f_off) { + BOOT_LOG_WRN("Image in %s slot at 0x%x has been built for offset 0x%x"\ + ", skipping", + active_slot == 0 ? "primary" : "secondary", f_off, + hdr->ih_load_addr); + + /* The image is not bootable from this slot. */ + return 1; + } + + return 0; +} +#endif + +/* + * Check that there is a valid image in a slot + * + * @returns + * FIH_SUCCESS if image was successfully validated + * FIH_NO_BOOTABLE_IMAGE if no bootloable image was found + * FIH_FAILURE on any errors + */ +static fih_ret +boot_validate_slot(struct boot_loader_state *state, int slot, + struct boot_status *bs, int expected_swap_type) +{ + const struct flash_area *fap; + struct image_header *hdr; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + BOOT_LOG_DBG("boot_validate_slot: slot %d, expected_swap_type %d", + slot, expected_swap_type); + (void)expected_swap_type; + + fap = BOOT_IMG_AREA(state, slot); + assert(fap != NULL); + + hdr = boot_img_hdr(state, slot); + if (boot_check_header_erased(state, slot) || (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) { + /* No bootable image in slot; continue booting from the primary slot. */ + fih_rc = FIH_NO_BOOTABLE_IMAGE; + goto out; + } + + if (!boot_check_header_valid(state, slot)) { + fih_rc = FIH_FAILURE; + } else { + BOOT_HOOK_CALL_FIH(boot_image_check_hook, FIH_BOOT_HOOK_REGULAR, + fih_rc, BOOT_CURR_IMG(state), slot); + if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) { + FIH_CALL(boot_check_image, fih_rc, state, bs, slot); + } + } + + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + if ((slot != BOOT_SLOT_PRIMARY) || ARE_SLOTS_EQUIVALENT()) { + boot_scramble_slot(fap, slot); + /* Image is invalid, erase it to prevent further unnecessary + * attempts to validate and boot it. + */ + } + +#if !defined(__BOOTSIM__) + BOOT_LOG_ERR("Image in the %s slot is not valid!", + (slot == BOOT_SLOT_PRIMARY) ? "primary" : "secondary"); +#endif + fih_rc = FIH_NO_BOOTABLE_IMAGE; + goto out; + } + +out: + FIH_RET(fih_rc); +} + +/** + * Opens all flash areas and checks which contain an image with a valid header. + * + * @param state Boot loader status information. + * + * @return 0 on success; nonzero on failure. + */ +static int +boot_get_slot_usage(struct boot_loader_state *state) +{ + uint32_t slot; + int rc; + + IMAGES_ITER(BOOT_CURR_IMG(state)) { + /* Attempt to read an image header from each slot. */ + rc = boot_read_image_headers(state, false, NULL); + if (rc != 0) { + BOOT_LOG_WRN("Failed reading image headers."); + return rc; + } + + /* Check headers in all slots */ + for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { + if (boot_check_header_valid(state, slot)) { + state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = true; + BOOT_LOG_IMAGE_INFO(slot, boot_img_hdr(state, slot)); + } else { + state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false; + BOOT_LOG_INF("Image %d %s slot: Image not found", + BOOT_CURR_IMG(state), + (slot == BOOT_SLOT_PRIMARY) + ? "Primary" : "Secondary"); + } + } + + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = BOOT_SLOT_NONE; + } + + return 0; +} + +/** + * Finds the slot containing the image with the highest version number for the + * current image. + * + * @param state Boot loader status information. + * + * @return BOOT_SLOT_NONE if no available slot found, number of + * the found slot otherwise. + */ +static uint32_t +find_slot_with_highest_version(struct boot_loader_state *state) +{ + uint32_t slot; + uint32_t candidate_slot = BOOT_SLOT_NONE; + int rc; + + for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { + if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot]) { + if (candidate_slot == BOOT_SLOT_NONE) { + candidate_slot = slot; + } else { + rc = boot_compare_version( + &boot_img_hdr(state, slot)->ih_ver, + &boot_img_hdr(state, candidate_slot)->ih_ver); + if (rc == 1) { + /* The version of the image being examined is greater than + * the version of the current candidate. + */ + candidate_slot = slot; + } + } + } + } + + return candidate_slot; +} + +#ifdef MCUBOOT_HAVE_LOGGING +/** + * Prints the state of the loaded images. + * + * @param state Boot loader status information. + */ +static void +print_loaded_images(struct boot_loader_state *state) +{ + uint32_t active_slot; + + IMAGES_ITER(BOOT_CURR_IMG(state)) { + active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot; + + BOOT_LOG_INF("Image %d loaded from the %s slot", + BOOT_CURR_IMG(state), + (active_slot == BOOT_SLOT_PRIMARY) ? + "primary" : "secondary"); + } +} +#endif + +#if (defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)) +/** + * Checks whether the active slot of the current image was previously selected + * to run. Erases the image if it was selected but its execution failed, + * otherwise marks it as selected if it has not been before. + * + * @param state Boot loader status information. + * + * @return 0 on success; nonzero on failure. + */ +static int +boot_select_or_erase(struct boot_loader_state *state) +{ + const struct flash_area *fap = NULL; + int rc; + uint32_t active_slot; + struct boot_swap_state* active_swap_state; + + active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot; + + fap = BOOT_IMG_AREA(state, active_slot); + assert(fap != NULL); + + active_swap_state = &(state->slot_usage[BOOT_CURR_IMG(state)].swap_state); + + memset(active_swap_state, 0, sizeof(struct boot_swap_state)); + rc = boot_read_swap_state(fap, active_swap_state); + assert(rc == 0); + + if (active_swap_state->magic != BOOT_MAGIC_GOOD) { + /* Image was not selected for test. Skip slot. */ + return -1; + } + + if (active_swap_state->copy_done == BOOT_FLAG_SET && + active_swap_state->image_ok != BOOT_FLAG_SET) { + /* + * A reboot happened without the image being confirmed at + * runtime or its trailer is corrupted/invalid. Erase the image + * to prevent it from being selected again on the next reboot. + */ + BOOT_LOG_DBG("Erasing faulty image in the %s slot.", + (active_slot == BOOT_SLOT_PRIMARY) ? "primary" : "secondary"); + rc = boot_scramble_region(fap, 0, flash_area_get_size(fap), false); + assert(rc == 0); + rc = -1; + } else { + if (active_swap_state->copy_done != BOOT_FLAG_SET) { + if (active_swap_state->copy_done == BOOT_FLAG_BAD) { + BOOT_LOG_DBG("The copy_done flag had an unexpected value. Its " + "value was neither 'set' nor 'unset', but 'bad'."); + } + /* + * Set the copy_done flag, indicating that the image has been + * selected to boot. It can be set in advance, before even + * validating the image, because in case the validation fails, the + * entire image slot will be erased (including the trailer). + */ + rc = boot_write_copy_done(fap); + if (rc != 0) { + BOOT_LOG_WRN("Failed to set copy_done flag of the image in " + "the %s slot.", (active_slot == BOOT_SLOT_PRIMARY) ? + "primary" : "secondary"); + rc = 0; + } + } + } + + return rc; +} +#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */ + +/** + * Tries to load and validate a single slot. + * + * @param state Boot loader status information. + * + * @return 0 on success; nonzero on failure. + */ +static fih_ret +boot_load_and_validate_current_image(struct boot_loader_state *state) +{ + int rc; + fih_ret fih_rc; + uint32_t active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot; + + if (active_slot == BOOT_SLOT_NONE) { + FIH_RET(FIH_FAILURE); + } + + BOOT_LOG_INF("Loading image %d from slot %d", BOOT_CURR_IMG(state), active_slot); + +#ifdef MCUBOOT_DIRECT_XIP + rc = boot_rom_address_check(state); + if (rc != 0) { + FIH_RET(FIH_FAILURE); + } +#endif /* MCUBOOT_DIRECT_XIP */ + +#if defined(MCUBOOT_DIRECT_XIP_REVERT) + /* The manifest binds images together. The act of validating the manifest + * image implies that the other images are also validated. + * Skip this step and ignore those flags for other images, so a sudden power + * loss after confirming some of the images does not result in partially + * confirmed state. + */ + if (BOOT_CURR_IMG(state) == MCUBOOT_MANIFEST_IMAGE_NUMBER) { + rc = boot_select_or_erase(state); + if (rc != 0) { + FIH_RET(FIH_FAILURE); + } + } +#endif /* MCUBOOT_DIRECT_XIP_REVERT */ + + FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL, 0); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + /* Image is invalid. */ + FIH_RET(FIH_FAILURE); + } + + FIH_RET(FIH_SUCCESS); +} + +/** + * Tries to load a slot for all the images with validation. + * + * @param state Boot loader status information. + * + * @return 0 on success; nonzero on failure. + */ +fih_ret +boot_load_and_validate_images(struct boot_loader_state *state) +{ + uint32_t active_slot; + int rc; + fih_ret fih_rc; + + while (true) { +#if (BOOT_IMAGE_NUMBER > 1) + BOOT_CURR_IMG(state) = MCUBOOT_MANIFEST_IMAGE_NUMBER; +#endif + rc = BOOT_HOOK_FIND_SLOT_CALL(boot_find_next_slot_hook, BOOT_HOOK_REGULAR, + state, BOOT_CURR_IMG(state), &active_slot); + if (rc == BOOT_HOOK_REGULAR) { + active_slot = find_slot_with_highest_version(state); + } + if (active_slot == BOOT_SLOT_NONE) { + BOOT_LOG_ERR("No more manifest slots available"); + FIH_RET(FIH_FAILURE); + } + + /* Save the number of the active manifest slot. */ + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot; + + FIH_CALL(boot_load_and_validate_current_image, fih_rc, state); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + state->slot_usage[MCUBOOT_MANIFEST_IMAGE_NUMBER].slot_available[active_slot] = false; + state->slot_usage[MCUBOOT_MANIFEST_IMAGE_NUMBER].active_slot = BOOT_SLOT_NONE; + BOOT_LOG_INF("No valid manifest in slot %d", active_slot); + continue; + } + + BOOT_LOG_INF("Try to validate images using manifest in slot %d", active_slot); + +#if BOOT_IMAGE_NUMBER > 1 + /* Go over all other images and try to load one */ + IMAGES_ITER(BOOT_CURR_IMG(state)) { + /* Skip the image with manifest - it's been already verified. */ + if (BOOT_CURR_IMG(state) == MCUBOOT_MANIFEST_IMAGE_NUMBER) { + continue; + } + + /* Check if there is a matching slot available. */ + if (!state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot]) { + /* Invalidate manifest */ + FIH_SET(fih_rc, FIH_FAILURE); + break; + } + + /* Save the number of the active slot. */ + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot; + + FIH_CALL(boot_load_and_validate_current_image, fih_rc, state); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false; + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = BOOT_SLOT_NONE; + /* Invalidate manifest */ + break; + } + } +#endif + + if (FIH_EQ(fih_rc, FIH_SUCCESS)) { + /* All images have been loaded and validated successfully. */ + break; + } + + BOOT_LOG_DBG("Manifest in slot %d is invalid", active_slot); + + /* Invalidate manifest */ + state->slot_usage[MCUBOOT_MANIFEST_IMAGE_NUMBER].slot_available[active_slot] = false; + state->slot_usage[MCUBOOT_MANIFEST_IMAGE_NUMBER].active_slot = BOOT_SLOT_NONE; + } + + FIH_RET(FIH_SUCCESS); +} + +/** + * Updates the security counter for the current image. + * + * @param state Boot loader status information. + * + * @return 0 on success; nonzero on failure. + */ +static int +boot_update_hw_rollback_protection(struct boot_loader_state *state) +{ +#ifdef MCUBOOT_HW_ROLLBACK_PROT + int rc; + + /* Update the stored security counter with the newer (active) image's + * security counter value. + */ +#if (defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)) + /* When the 'revert' mechanism is enabled in direct-xip or RAM load mode, + * the security counter can be increased only after reboot, if the image + * has been confirmed at runtime (the image_ok flag has been set). + * This way a 'revert' can be performed when it's necessary. + */ + if (state->slot_usage[BOOT_CURR_IMG(state)].swap_state.image_ok == BOOT_FLAG_SET) { +#endif + rc = boot_update_security_counter(state, + state->slot_usage[BOOT_CURR_IMG(state)].active_slot, + state->slot_usage[BOOT_CURR_IMG(state)].active_slot); + if (rc != 0) { + BOOT_LOG_ERR("Security counter update failed after image %d validation.", + BOOT_CURR_IMG(state)); + return rc; + } +#if (defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)) + } +#endif + + return 0; + +#else /* MCUBOOT_HW_ROLLBACK_PROT */ + (void) (state); + return 0; +#endif +} + +fih_ret +context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) +{ + int rc; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + rc = boot_open_all_flash_areas(state); + if (rc != 0) { + goto out; + } + + rc = boot_get_slot_usage(state); + if (rc != 0) { + goto close; + } + + FIH_CALL(boot_load_and_validate_images, fih_rc, state); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + FIH_SET(fih_rc, FIH_FAILURE); + goto close; + } + + IMAGES_ITER(BOOT_CURR_IMG(state)) { + rc = boot_update_hw_rollback_protection(state); + if (rc != 0) { + FIH_SET(fih_rc, FIH_FAILURE); + goto close; + } + + rc = boot_add_shared_data(state, + (uint8_t)state->slot_usage[BOOT_CURR_IMG(state)].active_slot); + if (rc != 0) { + FIH_SET(fih_rc, FIH_FAILURE); + goto close; + } + } + + /* All image loaded successfully. */ +#ifdef MCUBOOT_HAVE_LOGGING + print_loaded_images(state); +#endif + + fill_rsp(state, rsp); + +close: + boot_close_all_flash_areas(state); + +out: + if (rc != 0) { + FIH_SET(fih_rc, FIH_FAILURE); + } + + FIH_RET(fih_rc); +} + +/** + * Prepares the booting process. This function moves images around in flash as + * appropriate, and tells you what address to boot from. + * + * @param rsp On success, indicates how booting should occur. + * + * @return FIH_SUCCESS on success; nonzero on failure. + */ +fih_ret +boot_go(struct boot_rsp *rsp) +{ + FIH_DECLARE(fih_rc, FIH_FAILURE); + + boot_state_clear(NULL); + + FIH_CALL(context_boot_go, fih_rc, &boot_data, rsp); + FIH_RET(fih_rc); +} + +#endif /* MCUBOOT_MANIFEST_UPDATES && MCUBOOT_DIRECT_XIP */ diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 1d3472f82..1ce2ac211 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -168,6 +168,26 @@ elseif(CONFIG_BOOT_FIRMWARE_LOADER) ) endif() zephyr_library_include_directories(${BOOT_DIR}/bootutil/src) +elseif(CONFIG_MCUBOOT_MANIFEST_UPDATES) + zephyr_library_sources( + ${BOOT_DIR}/bootutil/src/loader_manifest_xip.c + ${BOOT_DIR}/bootutil/src/swap_misc.c + ${BOOT_DIR}/bootutil/src/caps.c + ) + + if(CONFIG_BOOT_SWAP_USING_MOVE) + zephyr_library_sources( + ${BOOT_DIR}/bootutil/src/swap_move.c + ) + elseif(CONFIG_BOOT_SWAP_USING_OFFSET) + zephyr_library_sources( + ${BOOT_DIR}/bootutil/src/swap_offset.c + ) + else() + zephyr_library_sources( + ${BOOT_DIR}/bootutil/src/swap_scratch.c + ) + endif() else() zephyr_library_sources( ${BOOT_DIR}/bootutil/src/loader.c From e9eada72f6c5a6fd5d19686a3adaebf135829a7a Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 4 Nov 2025 16:00:23 +0100 Subject: [PATCH 098/149] [nrf fromlist] doc: Add manifest conceptual description Add a short description about motivation behind manifest-based updates and the Direct XIP mode of operation if the manifests are enabled. Upstream PR #: 2511 Signed-off-by: Tomasz Chyrowicz --- docs/design.md | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/docs/design.md b/docs/design.md index ab532c0f4..d278dbeaf 100755 --- a/docs/design.md +++ b/docs/design.md @@ -4,6 +4,7 @@ - Copyright (c) 2017-2020 Linaro LTD - Copyright (c) 2017-2019 JUUL Labs - Copyright (c) 2019-2024 Arm Limited + - Copyright (c) 2025 Nordic Semiconductor ASA - Original license: @@ -987,6 +988,123 @@ strategy but there is no need for Scratch area. + Boot the loaded slot of image 0. +### [Multiple image boot using manifest](#multiple-image-boot-using-manifest) + + +Deployments that use multiple images typically require strict control over +versions of firmware components. +There is a dependency TLV that can be used to specify dependencies between +semantic versions of multiple components. However, since these only describe +a minimally compatible version of a counterpart component, there is no mechanism +to enforce a specific revision of the other image. +Therefore, the publisher must ensure that all combinations that satisfy the +dependencies are compatible with each other and are tested before deploying +a new version of the firmware bundle. +One way to simplify the process is to add dependencies to all parts that +enforce the latest revision of all other parts of the bundle. +This effectively enforces equality between the revisions of all parts. +This solution becomes even more problematic when using Direct-XIP mode - since +the bootloader typically only chain-loads the next stage, the next stage must +select and boot the correct slot of the next part of the firmware. +Although the dependencies ensure that the next part with a specific +version is present on the device, there is no guarantee in which slot it +was validated. +Again, the publisher may use different version numbers for the same firmware +created for different slots, but this raises the question of whether there is +a better way to manage dependencies between images. + +The bootloader manifest is an additional, protected TLV that serves as the sole +source of information about the compatibility and bootability of the multipart +firmware. The basic rules for all types of manifests are: + + * The manifest must be protected (directly or indirectly) by a cryptographic + signature. + * There must be exactly one selected image that can provide the manifest TLV. + * There must be only one manifest per slot. + * Processing of the manifest must validate the full functional set of firmware + components. + * If the manifest does not describe a part of the firmware, it must be + considered invalid. + * Each update candidate must provide a new manifest. + + +``` + +-------------------+ + +----------------->| Mainfest | + | +===================+ + | |+-----------------+| + | || format || + | |+-----------------+| + | || image count || + | |+-----------------+| + | +------------|| digest(Image 1) || + | | |+-----------------+| + | | || digest(Image 2) ||-------------+ + | | |+-----------------+| | + | | +-------------------+ | + | | | + +-----------------+ | | +-----------------+ +-----------------+ | + | Manifest image | | | | Image 1 | | Image 2 | | + +=================+ | | +=================+ +=================+ | + |+---------------+| | | |+---------------+| |+---------------+| | + || header || | | || header || || header || | + |+---------------+| | | |+---------------+| |+---------------+| | + || manifest TLV ||-+ | || firmware || || firmware || | + |+---------------+| | |+---------------+| |+---------------+| | + || digest TLV || +->|| digest TLV || || digest TLV ||<-+ + |+---------------+| |+---------------+| |+---------------+| + || signature TLV || || signature TLV || || signature TLV || + |+---------------+| |+---------------+| |+---------------+| + +-----------------+ +-----------------+ +-----------------+ +``` + +The manifest TLV has a format field that allows for the development of complex +boot logic in the future. The default manifest is structured as a list of +digests of firmware parts. + +The manifest is transferred as a protected TLV in a dedicated "Manifest image." +This image is updated using the same mechanisms as regular images. + +The manifest image may contain firmware - if so, this part of the firmware must +be updated with every firmware update. + +The bootloader's behavior changes once manifest-based updates +and booting are enabled. + +Boot process for Direct-XIP modes: + ++ Loop 1. Until all images are loaded and validated against the active manifest + 1. Subloop 1. Iterate over the manifest image slots + + Does any of the slots contain a manifest? + + Yes: + + Select the newer manifest. + + Copy it to the bootloader state. + + Validate the manifest image (integrity and security check). + + If validation fails mark the active manifest slot as + unavailable and try the other slot. + + No: Return with an error. + + 2. Subloop 2. Iterate over all images except manifest image + + Does the current image contain a valid header in the same slot + as the selected (active) manifest? + + Yes: Is the image valid (integrity and security check) and its + digest matches the manifest? + + Yes: Skip to the next image. + + No: + + Mark the active manifest slot as unavailable. + + Restart main loop. + + No: + + Mark the active manifest slot as unavailable. + + Restart main loop. + ++ Loop 2. Iterate over all images + + Increase the security counter if needed. + + Do the measured boot and the data sharing if needed. + ++ Boot the loaded slot of image 0. + +Manifest-based updates and booting for other modes are not yet implemented. + ## [Image swapping](#image-swapping) The bootloader swaps the contents of the two image slots for two reasons: From 0b380d837a09bcb4757eb2eaa9887dabfa7a5c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B8e?= Date: Wed, 12 Dec 2018 08:59:47 +0100 Subject: [PATCH 099/149] [nrf noup] treewide: add NCS partition manager support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partition Manager is an nRF Connect SDK component which uses yaml files to resolve flash partition placement with a holistic view of the device. This component's MCUboot portions began life as upstream mcuboot PR#430. This added support for being built as a sub image from the downstream Nordic patch set for a zephyr multi image build system (mcuboot 430 was combined with effor submitted to upstream zephyr as PR#13672, which was ultimately reworked after being rejected for mainline at the ELCE 2019 conference in Lyon). It has since evolved over time. This is the version that will go into NCS v1.3. It features: - page size aligned partitions for all partitions used by mcuboot. - image swaps without scratch partitions Add support for configurations where there exists two primary slots but only one secondary slot, which is shared. These two primary slots are the regular application and B1. B1 can be either S0 or S1 depending on the state of the device. Decide where an upgrade should be stored by looking at the vector table. Provide update candidates for both s0 and s1. These candidates must be signed with mcuboot after being signed by b0. Additional notes: - we make update.hex without trailer data This is needed for serial recovery to work using hex files. Prior to this the update.hex got TLV data at the end of the partition, which caused many blank pages to be included, which made it hard to use in a serial recovery scheme. Instead, make update.hex without TLV data at the end, and provide a new file test_update.hex which contains the TLV data, and can be directly flashed to test the upgrade procedure. - we use a function for signing the application as future-proofing for when other components must be signed as well - this includes an update to single image applications that enables support for partition manager; when single image DFU is used, a scratch partition is not needed. - In NCS, image 1 primary slot is the upgrade bank for mcuboot (IE S0 or S1 depending on the active slot). It is not required that this slot contains any valid data. - The nRF boards all have a single flash page size, and partition manager deals with the size of the update partitions and so on, so we must skip a boot_slots_compatible() check to avoid getting an error. - There is no need to verify the target when using partition manager. - We lock mcuboot using fprotect before jumping, to enable the secure boot property of the system. - Call fw_info_ext_api_provide() before booting if EXT_API_PROVIDE EXT_API is enabled. This is relevant only when the immutable bootloader has booted mcuboot. Signed-off-by: HÃ¥kon Øye Amundsen Signed-off-by: Øyvind Rønningstad Signed-off-by: Sebastian Bøe Signed-off-by: Sigvart Hovland Signed-off-by: Martí Bolívar Signed-off-by: Torsten Rasmussen Signed-off-by: Andrzej Głąbek Signed-off-by: Robert Lubos Signed-off-by: Andrzej Puzdrowski Signed-off-by: Emil Obalski Signed-off-by: Pawel Dunaj Signed-off-by: Ioannis Glaropoulos Signed-off-by: Johann Fischer Signed-off-by: Vidar Berg Signed-off-by: Draus, Sebastian Signed-off-by: Trond Einar Snekvik Signed-off-by: Jamie McCrae Signed-off-by: Joakim Andersson Signed-off-by: Georgios Vasilakis Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 9554013f013d5bc067b41d9ad470bc09c346eb71) (cherry picked from commit 89361bdec45690575952743ef65bc357977ddbb9) (cherry picked from commit 008144597fd759be49af8eed7dd837b1f07f68f0) --- boot/bootutil/src/bootutil_loader.c | 9 +++ boot/bootutil/src/loader.c | 88 +++++++++++++++++++++---- boot/bootutil/src/swap_move.c | 22 +++++++ boot/bootutil/src/swap_offset.c | 22 +++++++ boot/bootutil/src/swap_scratch.c | 22 +++++++ boot/zephyr/CMakeLists.txt | 7 ++ boot/zephyr/Kconfig | 2 + boot/zephyr/include/sysflash/sysflash.h | 48 ++++++++++++++ boot/zephyr/include/target.h | 4 ++ boot/zephyr/main.c | 45 +++++++++++++ boot/zephyr/pm.yml | 77 ++++++++++++++++++++++ ext/nrf/cc310_glue.h | 2 +- zephyr/module.yml | 3 +- 13 files changed, 335 insertions(+), 16 deletions(-) create mode 100644 boot/zephyr/pm.yml diff --git a/boot/bootutil/src/bootutil_loader.c b/boot/bootutil/src/bootutil_loader.c index e71137ec9..2052d4765 100644 --- a/boot/bootutil/src/bootutil_loader.c +++ b/boot/bootutil/src/bootutil_loader.c @@ -146,6 +146,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all, struc * * Failure to read any headers is a fatal error. */ +#ifdef PM_S1_ADDRESS + /* 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) { + continue; + } +#endif /* PM_S1_ADDRESS */ if (i > 0 && !require_all) { return 0; } else { diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 12276b03d..991a426c1 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -676,8 +676,20 @@ boot_validate_slot(struct boot_loader_state *state, int slot, uint32_t min_addr; uint32_t max_addr; - min_addr = flash_area_get_off(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); - max_addr = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)) + min_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) { + min_addr = PM_CPUNET_APP_ADDRESS; + max_addr = PM_CPUNET_APP_ADDRESS + PM_CPUNET_APP_SIZE; + } else +#endif + { + min_addr = flash_area_get_off(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); + max_addr = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)) + min_addr; + } /* MCUBOOT_CHECK_HEADER_LOAD_ADDRESS takes priority over MCUBOOT_VERIFY_IMG_ADDRESS */ #ifdef MCUBOOT_CHECK_HEADER_LOAD_ADDRESS @@ -734,6 +746,39 @@ boot_validated_swap_type(struct boot_loader_state *state, { int swap_type; FIH_DECLARE(fih_rc, FIH_FAILURE); +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other + * B1 slot S0 or S1) share the same secondary slot, we need to check + * whether the update candidate in the secondary slot is intended for + * image 0 or image 1 primary by looking at the address of the reset + * vector. Note that there are good reasons for not using img_num from + * the swap info. + */ + const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); + struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; + + if (hdr->ih_magic == IMAGE_MAGIC) { + const struct flash_area *primary_fa; + uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; + uint32_t *vtable = (uint32_t *)(vtable_addr); + uint32_t reset_addr = vtable[1]; + int rc = flash_area_open( + flash_area_id_from_multi_image_slot( + BOOT_CURR_IMG(state), + BOOT_SLOT_PRIMARY), + &primary_fa); + + if (rc != 0) { + return BOOT_SWAP_TYPE_FAIL; + } + /* Get start and end of primary slot for current image */ + 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 this image */ + return BOOT_SWAP_TYPE_NONE; + } + } +#endif swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -1903,15 +1948,25 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT - FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SLOT_PRIMARY, NULL, 0); - /* Check for all possible values is redundant in normal operation it - * is meant to prevent FI attack. +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. Image 1 primary is the currently + * executing MCUBoot image, and is therefore already validated by NSIB and + * does not need to also be validated by MCUBoot. */ - if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS) || - FIH_EQ(fih_rc, FIH_FAILURE) || - FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) { - FIH_SET(fih_rc, FIH_FAILURE); - goto out; + bool image_validated_by_nsib = BOOT_CURR_IMG(state) == 1; + if (!image_validated_by_nsib) +#endif + { + FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_SLOT_PRIMARY, NULL, 0); + /* Check for all possible values is redundant in normal operation it + * is meant to prevent FI attack. + */ + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS) || + FIH_EQ(fih_rc, FIH_FAILURE) || + FIH_EQ(fih_rc, FIH_NO_BOOTABLE_IMAGE)) { + FIH_SET(fih_rc, FIH_FAILURE); + goto out; + } } #else /* Even if we're not re-validating the primary slot, we could be booting @@ -1928,10 +1983,15 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } #endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */ - rc = boot_update_hw_rollback_protection(state); - if (rc != 0) { - FIH_SET(fih_rc, FIH_FAILURE); - goto out; +#ifdef PM_S1_ADDRESS + if (!image_validated_by_nsib) +#endif + { + rc = boot_update_hw_rollback_protection(state); + if (rc != 0) { + FIH_SET(fih_rc, FIH_FAILURE); + goto out; + } } rc = boot_add_shared_data(state, BOOT_SLOT_PRIMARY); diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index 88a117f59..a183ce8b0 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -236,6 +236,28 @@ boot_slots_compatible(struct boot_loader_state *state) size_t sector_sz_sec = 0; size_t i; +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. In this case, image 1 primary points to the other + * B1 slot (ie S0 or S1), and image 0 primary points to the app. + * With this configuration, image 0 and image 1 share the secondary slot. + * Hence, the primary slot of image 1 will be *smaller* than image 1's + * secondary slot. This is not allowed in upstream mcuboot, so we need + * this patch to allow it. Also, all of these checks are redundant when + * partition manager is in use, and since we have the same sector size + * in all of our flash. + */ +#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { + return 1; + } +#endif +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + return 1; + } +#endif +#endif + num_sectors_pri = boot_img_num_sectors(state, BOOT_SLOT_PRIMARY); num_sectors_sec = boot_img_num_sectors(state, BOOT_SLOT_SECONDARY); diff --git a/boot/bootutil/src/swap_offset.c b/boot/bootutil/src/swap_offset.c index eda68ab91..01cb29f93 100644 --- a/boot/bootutil/src/swap_offset.c +++ b/boot/bootutil/src/swap_offset.c @@ -310,6 +310,28 @@ int boot_slots_compatible(struct boot_loader_state *state) size_t sector_sz_sec = 0; size_t i; +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. In this case, image 1 primary points to the other + * B1 slot (ie S0 or S1), and image 0 primary points to the app. + * With this configuration, image 0 and image 1 share the secondary slot. + * Hence, the primary slot of image 1 will be *smaller* than image 1's + * secondary slot. This is not allowed in upstream mcuboot, so we need + * this patch to allow it. Also, all of these checks are redundant when + * partition manager is in use, and since we have the same sector size + * in all of our flash. + */ +#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { + return 1; + } +#endif +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + return 1; + } +#endif +#endif + num_sectors_pri = boot_img_num_sectors(state, BOOT_SLOT_PRIMARY); num_sectors_sec = boot_img_num_sectors(state, BOOT_SLOT_SECONDARY); diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c index 59b64ad43..2b0b20cf4 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -281,6 +281,28 @@ boot_slots_compatible(struct boot_loader_state *state) size_t i, j; int8_t smaller; +#ifdef PM_S1_ADDRESS + /* Patch needed for NCS. In this case, image 1 primary points to the other + * B1 slot (ie S0 or S1), and image 0 primary points to the app. + * With this configuration, image 0 and image 1 share the secondary slot. + * Hence, the primary slot of image 1 will be *smaller* than image 1's + * secondary slot. This is not allowed in upstream mcuboot, so we need + * this patch to allow it. Also, all of these checks are redundant when + * partition manager is in use, and since we have the same sector size + * in all of our flash. + */ +#if CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { + return 1; + } +#endif +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + return 1; + } +#endif +#endif + num_sectors_primary = boot_img_num_sectors(state, BOOT_SLOT_PRIMARY); num_sectors_secondary = boot_img_num_sectors(state, BOOT_SLOT_SECONDARY); if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) || diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 1ce2ac211..5ef3d671d 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -395,6 +395,13 @@ if(NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") endif() message("MCUBoot bootloader key file: ${KEY_FILE}") + set_property( + GLOBAL + PROPERTY + KEY_FILE + ${KEY_FILE} + ) + set(mcuboot_default_signature_files ${MCUBOOT_DIR}/root-ec-p256-pkcs8.pem ${MCUBOOT_DIR}/root-ec-p384.pem diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index c0ec76709..a954c4dd5 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -9,6 +9,8 @@ mainmenu "MCUboot configuration" comment "MCUboot-specific configuration options" +source "$(ZEPHYR_NRF_MODULE_DIR)/modules/mcuboot/boot/zephyr/Kconfig" + # Hidden option to mark a project as MCUboot config MCUBOOT default y diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index 16d222280..99cbf56b7 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -7,6 +7,52 @@ #ifndef __SYSFLASH_H__ #define __SYSFLASH_H__ +#if USE_PARTITION_MANAGER +#include +#include + +#ifndef CONFIG_SINGLE_APPLICATION_SLOT + +#if (MCUBOOT_IMAGE_NUMBER == 1) + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID + +#elif (MCUBOOT_IMAGE_NUMBER == 2) + +extern uint32_t _image_1_primary_slot_id[]; + +#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 ) +#endif +#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID + +#else /* CONFIG_SINGLE_APPLICATION_SLOT */ + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID +/* NOTE: Scratch parition is not used by single image DFU but some of + * functions in common files reference it, so the definitions has been + * provided to allow compilation of common units. + */ +#define FLASH_AREA_IMAGE_SCRATCH 0 + +#endif /* CONFIG_SINGLE_APPLICATION_SLOT */ + +#else + +#include #include #include #include @@ -65,4 +111,6 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #endif /* CONFIG_SINGLE_APPLICATION_SLOT */ +#endif /* USE_PARTITION_MANAGER */ + #endif /* __SYSFLASH_H__ */ diff --git a/boot/zephyr/include/target.h b/boot/zephyr/include/target.h index ea160752e..856686785 100644 --- a/boot/zephyr/include/target.h +++ b/boot/zephyr/include/target.h @@ -8,6 +8,8 @@ #ifndef H_TARGETS_TARGET_ #define H_TARGETS_TARGET_ +#ifndef USE_PARTITION_MANAGER + #if defined(MCUBOOT_TARGET_CONFIG) /* * Target-specific definitions are permitted in legacy cases that @@ -47,4 +49,6 @@ #error "Target support is incomplete; cannot build mcuboot." #endif +#endif /* ifndef USE_PARTITION_MANAGER */ + #endif /* H_TARGETS_TARGET_ */ diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 1494002e7..e9a4e20b0 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -76,6 +76,10 @@ #endif /* CONFIG_SOC_FAMILY_ESPRESSIF_ESP32 */ +#ifdef CONFIG_FW_INFO +#include +#endif + #ifdef CONFIG_MCUBOOT_SERIAL #include "boot_serial/boot_serial.h" #include "serial_adapter/serial_adapter.h" @@ -122,6 +126,11 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); * !defined(CONFIG_LOG_MODE_MINIMAL) */ +#if USE_PARTITION_MANAGER && CONFIG_FPROTECT +#include +#include +#endif + BOOT_LOG_MODULE_REGISTER(mcuboot); void os_heap_init(void); @@ -184,6 +193,19 @@ static void do_boot(struct boot_rsp *rsp) /* Disable the USB to prevent it from firing interrupts */ usb_disable(); #endif + +#if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED) + bool provided = fw_info_ext_api_provide(fw_info_find((uint32_t)vt), true); + +#ifdef PM_S0_ADDRESS + /* Only fail if the immutable bootloader is present. */ + if (!provided) { + BOOT_LOG_ERR("Failed to provide EXT_APIs\n"); + return; + } +#endif +#endif + #if CONFIG_MCUBOOT_CLEANUP_ARM_CORE cleanup_arm_interrupts(); /* Disable and acknowledge all interrupts */ @@ -674,7 +696,30 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND); +#if USE_PARTITION_MANAGER && CONFIG_FPROTECT + +#ifdef PM_S1_ADDRESS +/* MCUBoot is stored in either S0 or S1, protect both */ +#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_S0_ADDRESS) +#define PROTECT_ADDR PM_S0_ADDRESS +#else +/* There is only one instance of MCUBoot */ +#define PROTECT_SIZE (PM_MCUBOOT_PRIMARY_ADDRESS - PM_MCUBOOT_ADDRESS) +#define PROTECT_ADDR PM_MCUBOOT_ADDRESS +#endif + + rc = fprotect_area(PROTECT_ADDR, PROTECT_SIZE); + + if (rc != 0) { + BOOT_LOG_ERR("Protect mcuboot flash failed, cancel startup."); + while (1) + ; + } + +#endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */ + ZEPHYR_BOOT_LOG_STOP(); + do_boot(&rsp); mcuboot_status_change(MCUBOOT_STATUS_BOOT_FAILED); diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml new file mode 100644 index 000000000..5df9ae547 --- /dev/null +++ b/boot/zephyr/pm.yml @@ -0,0 +1,77 @@ +#include + +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 + # partition + span: [app] + +mcuboot_primary: + span: [mcuboot_pad, mcuboot_primary_app] + +# Partition for secondary slot is not created if building in single application +# slot configuration. +#if !defined(CONFIG_SINGLE_APPLICATION_SLOT) && !defined(CONFIG_BOOT_DIRECT_XIP) +mcuboot_secondary: + share_size: [mcuboot_primary] +#if defined(CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY) + region: external_flash + placement: + align: {start: 4} +#else + placement: + align: {start: CONFIG_FPROTECT_BLOCK_SIZE} + align_next: CONFIG_FPROTECT_BLOCK_SIZE # Ensure that the next partition does not interfere with this image + after: mcuboot_primary +#endif /* CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY */ + +#endif /* !defined(CONFIG_SINGLE_APPLICATION_SLOT) && !defined(CONFIG_BOOT_DIRECT_XIP) */ + +#if CONFIG_BOOT_DIRECT_XIP + +# Direct XIP is enabled, reserve area for metadata (padding) and name the +# partition so that its clear that it is not the secondary slot, but the direct +# XIP alternative. + +mcuboot_secondary_pad: + share_size: mcuboot_pad + placement: + after: mcuboot_primary + align: {start: CONFIG_FPROTECT_BLOCK_SIZE} + +mcuboot_secondary_app: + share_size: mcuboot_primary_app + placement: + after: mcuboot_secondary_pad + +mcuboot_secondary: + span: [mcuboot_secondary_pad, mcuboot_secondary_app] + +#endif /* CONFIG_BOOT_DIRECT_XIP */ + +#if CONFIG_BOOT_SWAP_USING_SCRATCH +mcuboot_scratch: + size: CONFIG_PM_PARTITION_SIZE_MCUBOOT_SCRATCH + placement: + after: app + align: {start: CONFIG_FPROTECT_BLOCK_SIZE} +#endif /* CONFIG_BOOT_SWAP_USING_SCRATCH */ + +# Padding placed before image to boot. This reserves space for the MCUboot image header +# and it ensures that the boot image gets linked with the correct address offset in flash. +mcuboot_pad: + # MCUboot pad must be placed before the primary application partition. + # The primary application partition includes the secure firmware if present. + size: CONFIG_PM_PARTITION_SIZE_MCUBOOT_PAD + placement: + before: [mcuboot_primary_app] +#ifdef CONFIG_FPROTECT + align: {start: CONFIG_FPROTECT_BLOCK_SIZE} +#endif diff --git a/ext/nrf/cc310_glue.h b/ext/nrf/cc310_glue.h index ed3ed5c00..22eb94911 100644 --- a/ext/nrf/cc310_glue.h +++ b/ext/nrf/cc310_glue.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include /* diff --git a/zephyr/module.yml b/zephyr/module.yml index 7a80d166f..65af58bb5 100644 --- a/zephyr/module.yml +++ b/zephyr/module.yml @@ -1,7 +1,8 @@ samples: - boot/zephyr build: - cmake: ./boot/bootutil/zephyr + cmake-ext: True + kconfig-ext: True sysbuild-cmake: boot/zephyr/sysbuild package-managers: pip: From c7e51f66094bdfb5bde48468fa299000e76d4cdb Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Thu, 27 Aug 2020 14:29:31 +0200 Subject: [PATCH 100/149] [nrf noup] boot: nrf53-specific customizations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add network core bootloader implementation Enables network core updates of nrf53 using MCUBoot by identifying images through their start addresses. Also implements the control and transfer using the PCD module. - Add support for multi image DFU using partition manager. - Add check for netcore addr if NSIB is enabled so netcore updates works - boot: zephyr: move thingy53_nrf5340_cpuapp.conf downstream Moved the board configuration for Thingy:53 Application Core to the nRF Connect SDK MCUboot downstream repository. The configuration file contains references to the Kconfig modules that are only available in the nRF Connect SDK. The current configuration is set up to work in the nRF Connect SDK environment and cannot be used upstream. - pm: enable ram flash partition using common flag This patch makes mcuboot_primary_1 ram-flash partition selectable using CONFIG_NRF53_MCUBOOT_PRIMARY_1_RAM_FLASH property. This is needed since CONFIG_NRF53_MULTI_IMAGE_UPDATE become not only configuration which requires that partition. - MCUBoot configures USB CDC by its own. There is no need for BOARD_SERIAL_BACKEND_CDC_ACM option to configure anything which is later overwritten anyway. Jira: NCSDK-18596 Signed-off-by: Andrzej Puzdrowski Signed-off-by: Emil Obalski Signed-off-by: HÃ¥kon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Jamie McCrae Signed-off-by: Johann Fischer Signed-off-by: Kamil Piszczek Signed-off-by: Ole Sæther Signed-off-by: Sigvart Hovland Signed-off-by: Simon Iversen Signed-off-by: Torsten Rasmussen Signed-off-by: Trond Einar Snekvik Signed-off-by: Mateusz Kapala Signed-off-by: Dominik Ermel Signed-off-by: Michal Kozikowski Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 3db6eca8c7968a1eb1cb11fda08f763004f8226d) (cherry picked from commit 2cdbcb02a960f625e7a067f37ab573a4ebaa03a7) (cherry picked from commit 7f1fb0c77a823c3824d5fa640f29c8bd28aaeeb5) --- boot/bootutil/src/loader.c | 80 ++++++++++++++----- .../boards/thingy53_nrf5340_cpuapp.conf | 74 ++++++++++++++++- boot/zephyr/include/sysflash/sysflash.h | 23 ++++++ boot/zephyr/main.c | 25 +++++- boot/zephyr/pm.yml | 13 +++ 5 files changed, 193 insertions(+), 22 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 991a426c1..e41fac32f 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -53,6 +53,10 @@ #ifndef MCUBOOT_MANIFEST_UPDATES +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) +#include +#endif + #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -746,7 +750,14 @@ boot_validated_swap_type(struct boot_loader_state *state, { int swap_type; FIH_DECLARE(fih_rc, FIH_FAILURE); -#ifdef PM_S1_ADDRESS + bool upgrade_valid = false; + +#if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) + const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); + struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; + uint32_t vtable_addr = 0; + uint32_t *vtable = 0; + uint32_t reset_addr = 0; /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other * B1 slot S0 or S1) share the same secondary slot, we need to check * whether the update candidate in the secondary slot is intended for @@ -754,31 +765,35 @@ boot_validated_swap_type(struct boot_loader_state *state, * vector. Note that there are good reasons for not using img_num from * the swap info. */ - const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); - struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; if (hdr->ih_magic == IMAGE_MAGIC) { - const struct flash_area *primary_fa; - uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; - uint32_t *vtable = (uint32_t *)(vtable_addr); - uint32_t reset_addr = vtable[1]; - int rc = flash_area_open( - flash_area_id_from_multi_image_slot( + vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; + vtable = (uint32_t *)(vtable_addr); + reset_addr = vtable[1]; +#ifdef PM_S1_ADDRESS +#ifdef PM_CPUNET_B0N_ADDRESS + if(reset_addr < PM_CPUNET_B0N_ADDRESS) +#endif + { + const struct flash_area *primary_fa; + int rc = flash_area_open(flash_area_id_from_multi_image_slot( BOOT_CURR_IMG(state), BOOT_SLOT_PRIMARY), &primary_fa); - if (rc != 0) { - return BOOT_SWAP_TYPE_FAIL; - } - /* Get start and end of primary slot for current image */ - 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 this image */ - return BOOT_SWAP_TYPE_NONE; + if (rc != 0) { + return BOOT_SWAP_TYPE_FAIL; + } + /* Get start and end of primary slot for current image */ + 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 this image */ + return BOOT_SWAP_TYPE_NONE; + } } +#endif /* PM_S1_ADDRESS */ } -#endif +#endif /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -792,7 +807,36 @@ boot_validated_swap_type(struct boot_loader_state *state, } else { swap_type = BOOT_SWAP_TYPE_FAIL; } + } else { + upgrade_valid = true; + } + +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) + /* If the update is valid, and it targets the network core: perform the + * update and indicate to the caller of this function that no update is + * available + */ + if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) { + uint32_t fw_size = hdr->ih_img_size; + + BOOT_LOG_INF("Starting network core update"); + int rc = pcd_network_core_update(vtable, fw_size); + + if (rc != 0) { + swap_type = BOOT_SWAP_TYPE_FAIL; + } else { + BOOT_LOG_INF("Done updating network core"); +#if defined(MCUBOOT_SWAP_USING_SCRATCH) || defined(MCUBOOT_SWAP_USING_MOVE) + /* swap_erase_trailer_sectors is undefined if upgrade only + * method is used. There is no need to erase sectors, because + * the image cannot be reverted. + */ + rc = swap_erase_trailer_sectors(state, secondary_fa); +#endif + swap_type = BOOT_SWAP_TYPE_NONE; + } } +#endif /* CONFIG_SOC_NRF5340_CPUAPP */ } return swap_type; diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index f2e42fd64..93be36738 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -1,3 +1,73 @@ -CONFIG_NORDIC_QSPI_NOR=n -CONFIG_SPI=n +CONFIG_SIZE_OPTIMIZATIONS=y + +CONFIG_SYSTEM_CLOCK_NO_WAIT=y +CONFIG_PM=n + +CONFIG_MAIN_STACK_SIZE=10240 +CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" + +CONFIG_BOOT_MAX_IMG_SECTORS=2048 +CONFIG_BOOT_SIGNATURE_TYPE_RSA=y + +# Flash +CONFIG_FLASH=y +CONFIG_BOOT_ERASE_PROGRESSIVELY=y +CONFIG_SOC_FLASH_NRF_EMULATE_ONE_BYTE_WRITE_ACCESS=y +CONFIG_FPROTECT=y + +# Serial +CONFIG_SERIAL=y +CONFIG_UART_LINE_CTRL=y + +# MCUBoot serial +CONFIG_GPIO=y +CONFIG_MCUBOOT_SERIAL=y +CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y +CONFIG_BOOT_SERIAL_CDC_ACM=y + +# Required by QSPI +CONFIG_NORDIC_QSPI_NOR=y +CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 +CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16 + +# Required by USB CONFIG_MULTITHREADING=y + +# USB +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n +CONFIG_USB_DEVICE_REMOTE_WAKEUP=n +CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor ASA" +CONFIG_USB_DEVICE_PRODUCT="Bootloader Thingy:53" +CONFIG_USB_DEVICE_VID=0x1915 +CONFIG_USB_DEVICE_PID=0x5300 +CONFIG_USB_CDC_ACM=y + +# Decrease memory footprint +CONFIG_CBPRINTF_NANO=y +CONFIG_TIMESLICING=n +CONFIG_BOOT_BANNER=n +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_UART_CONSOLE=n +CONFIG_USE_SEGGER_RTT=n +CONFIG_LOG=n +CONFIG_ERRNO=n +CONFIG_PRINTK=n +CONFIG_RESET_ON_FATAL_ERROR=n +CONFIG_SPI=n +CONFIG_I2C=n +CONFIG_UART_NRFX=n + +# The following configurations are required to support simultaneous multi image update +CONFIG_PCD_APP=y +CONFIG_UPDATEABLE_IMAGE_NUMBER=2 +CONFIG_BOOT_UPGRADE_ONLY=y +# The network core cannot access external flash directly. The flash simulator must be used to +# provide a memory region that is used to forward the new firmware to the network core. +CONFIG_FLASH_SIMULATOR=y +CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y +CONFIG_FLASH_SIMULATOR_STATS=n + +# Enable custom command to erase settings partition. +CONFIG_ENABLE_MGMT_PERUSER=y +CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE=y diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index 99cbf56b7..7112f9baa 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -20,6 +20,11 @@ #elif (MCUBOOT_IMAGE_NUMBER == 2) +/* If B0 is present then two bootloaders are present, and we must use + * a single secondary slot for both primary slots. + */ +#ifdef PM_B0_ADDRESS + extern uint32_t _image_1_primary_slot_id[]; #define FLASH_AREA_IMAGE_PRIMARY(x) \ @@ -35,6 +40,24 @@ extern uint32_t _image_1_primary_slot_id[]; (x == 1) ? \ PM_MCUBOOT_SECONDARY_ID: \ 255 ) +#else + +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) + +#endif /* PM_B0_ADDRESS */ + #endif #define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index e9a4e20b0..b41a9c4d4 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -98,8 +98,26 @@ const struct boot_uart_funcs boot_funcs = { #include #endif -#if defined(CONFIG_LOG) && !defined(CONFIG_LOG_MODE_IMMEDIATE) && \ - !defined(CONFIG_LOG_MODE_MINIMAL) +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) +#include +#endif + +/* CONFIG_LOG_MINIMAL is the legacy Kconfig property, + * replaced by CONFIG_LOG_MODE_MINIMAL. + */ +#if (defined(CONFIG_LOG_MODE_MINIMAL) || defined(CONFIG_LOG_MINIMAL)) +#define ZEPHYR_LOG_MODE_MINIMAL 1 +#endif + +/* CONFIG_LOG_IMMEDIATE is the legacy Kconfig property, + * replaced by CONFIG_LOG_MODE_IMMEDIATE. + */ +#if (defined(CONFIG_LOG_MODE_IMMEDIATE) || defined(CONFIG_LOG_IMMEDIATE)) +#define ZEPHYR_LOG_MODE_IMMEDIATE 1 +#endif + +#if defined(CONFIG_LOG) && !defined(ZEPHYR_LOG_MODE_IMMEDIATE) && \ + !defined(ZEPHYR_LOG_MODE_MINIMAL) #ifdef CONFIG_LOG_PROCESS_THREAD #warning "The log internal thread for log processing can't transfer the log"\ "well for MCUBoot." @@ -716,6 +734,9 @@ int main(void) ; } +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) + pcd_lock_ram(); +#endif #endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */ ZEPHYR_BOOT_LOG_STOP(); diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml index 5df9ae547..13ffc44aa 100644 --- a/boot/zephyr/pm.yml +++ b/boot/zephyr/pm.yml @@ -75,3 +75,16 @@ mcuboot_pad: #ifdef CONFIG_FPROTECT align: {start: CONFIG_FPROTECT_BLOCK_SIZE} #endif + +#if (CONFIG_NRF53_MCUBOOT_PRIMARY_1_RAM_FLASH) +mcuboot_primary_1: + region: ram_flash + size: CONFIG_NRF53_RAM_FLASH_SIZE +#endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ + +#if (CONFIG_NRF53_MULTI_IMAGE_UPDATE) +mcuboot_secondary_1: + region: external_flash + size: CONFIG_NRF53_RAM_FLASH_SIZE + +#endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ From 1799f152809206049e7863ffbd103eaa2b2ba47b Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 27 Feb 2020 12:48:56 +0100 Subject: [PATCH 101/149] [nrf noup] zephyr: clean peripherals state before boot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do some cleanup of nRF peripherals. This is necessary since Zephyr doesn't have any driver deinitialization functionality, and we'd like to leave peripherals in a more predictable state before booting the Zephyr image. This should be re-worked when the zephyr driver model allows us to deinitialize devices cleanly before jumping to the chain-loaded image. Signed-off-by: Andrzej Puzdrowski Signed-off-by: Robert Lubos Signed-off-by: Torsten Rasmussen Signed-off-by: Øyvind Rønningstad Signed-off-by: Martí Bolívar Signed-off-by: HÃ¥kon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Johann Fischer Signed-off-by: Trond Einar Snekvik Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 0f2061be7ecee80c2b2c6772efc719415e89b880) (cherry picked from commit d6a003b8ebce039fb9bff4e8571cc59f159aa4a4) --- boot/zephyr/CMakeLists.txt | 6 +++ boot/zephyr/include/nrf_cleanup.h | 19 +++++++ boot/zephyr/main.c | 8 ++- boot/zephyr/nrf_cleanup.c | 83 +++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 boot/zephyr/include/nrf_cleanup.h create mode 100644 boot/zephyr/nrf_cleanup.c diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 5ef3d671d..78486cdff 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -775,3 +775,9 @@ if(SYSBUILD) set(mcuboot_image_footer_size ${required_size} CACHE INTERNAL "Estimated MCUboot image trailer size" FORCE) set(mcuboot_image_upgrade_footer_size ${required_upgrade_size} CACHE INTERNAL "Estimated MCUboot update image trailer size" FORCE) endif() + +if(CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL) +zephyr_library_sources( + ${BOOT_DIR}/zephyr/nrf_cleanup.c +) +endif() diff --git a/boot/zephyr/include/nrf_cleanup.h b/boot/zephyr/include/nrf_cleanup.h new file mode 100644 index 000000000..6b04cedfe --- /dev/null +++ b/boot/zephyr/include/nrf_cleanup.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef H_NRF_CLEANUP_ +#define H_NRF_CLEANUP_ + +/** + * Perform cleanup on some peripheral resources used by MCUBoot prior chainload + * the application. + * + * This function disables all RTC instances and UARTE instances. + * It Disables their interrupts signals as well. + */ +void nrf_cleanup_peripheral(void); + +#endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index b41a9c4d4..2f39bbabe 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -149,6 +149,10 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); #include #endif +#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL +#include +#endif + BOOT_LOG_MODULE_REGISTER(mcuboot); void os_heap_init(void); @@ -223,7 +227,9 @@ static void do_boot(struct boot_rsp *rsp) } #endif #endif - +#if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL + nrf_cleanup_peripheral(); +#endif #if CONFIG_MCUBOOT_CLEANUP_ARM_CORE cleanup_arm_interrupts(); /* Disable and acknowledge all interrupts */ diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c new file mode 100644 index 000000000..5bab26b24 --- /dev/null +++ b/boot/zephyr/nrf_cleanup.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#if defined(NRF_UARTE0) || defined(NRF_UARTE1) + #include +#endif +#if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) + #include +#endif +#if defined(NRF_PPI) + #include +#endif +#if defined(NRF_DPPIC) + #include +#endif + +#include + +#define NRF_UARTE_SUBSCRIBE_CONF_OFFS offsetof(NRF_UARTE_Type, SUBSCRIBE_STARTRX) +#define NRF_UARTE_SUBSCRIBE_CONF_SIZE (offsetof(NRF_UARTE_Type, EVENTS_CTS) -\ + NRF_UARTE_SUBSCRIBE_CONF_OFFS) + +#define NRF_UARTE_PUBLISH_CONF_OFFS offsetof(NRF_UARTE_Type, PUBLISH_CTS) +#define NRF_UARTE_PUBLISH_CONF_SIZE (offsetof(NRF_UARTE_Type, SHORTS) -\ + NRF_UARTE_PUBLISH_CONF_OFFS) + +#if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) +static inline void nrf_cleanup_rtc(NRF_RTC_Type * rtc_reg) +{ + nrf_rtc_task_trigger(rtc_reg, NRF_RTC_TASK_STOP); + nrf_rtc_event_disable(rtc_reg, 0xFFFFFFFF); + nrf_rtc_int_disable(rtc_reg, 0xFFFFFFFF); +} +#endif + +static void nrf_cleanup_clock(void) +{ + nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); +} + +void nrf_cleanup_peripheral(void) +{ +#if defined(NRF_RTC0) + nrf_cleanup_rtc(NRF_RTC0); +#endif +#if defined(NRF_RTC1) + nrf_cleanup_rtc(NRF_RTC1); +#endif +#if defined(NRF_RTC2) + nrf_cleanup_rtc(NRF_RTC2); +#endif +#if defined(NRF_UARTE0) + nrf_uarte_disable(NRF_UARTE0); + nrf_uarte_int_disable(NRF_UARTE0, 0xFFFFFFFF); +#if defined(NRF_DPPIC) + /* Clear all SUBSCRIBE configurations. */ + memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); + /* Clear all PUBLISH configurations. */ + memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); +#endif +#endif +#if defined(NRF_UARTE1) + nrf_uarte_disable(NRF_UARTE1); + nrf_uarte_int_disable(NRF_UARTE1, 0xFFFFFFFF); +#if defined(NRF_DPPIC) + /* Clear all SUBSCRIBE configurations. */ + memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); + /* Clear all PUBLISH configurations. */ + memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); +#endif +#endif +#if defined(NRF_PPI) + nrf_ppi_channels_disable_all(NRF_PPI); +#endif +#if defined(NRF_DPPIC) + nrf_dppi_channels_disable_all(NRF_DPPIC); +#endif + nrf_cleanup_clock(); +} From 43fe5e7d9afcb96a75b0a9d7bf93532196a9ac36 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Fri, 6 Jan 2023 12:24:48 +0100 Subject: [PATCH 102/149] [nrf noup] zephyr: Clean up non-secure RAM if enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To ensure that MCUBoot does not leak keys or other material through memory to non-secure side we clear the memory before jumping to the next image. Signed-off-by: Sigvart Hovland Signed-off-by: Dominik Ermel Signed-off-by: Ole Sæther (cherry picked from commit c9f632d1ddd6774e750577a83b562f5b739249fc) (cherry picked from commit 92da561256d98db5ca2cf07078469d9681c1d4de) --- boot/zephyr/include/nrf_cleanup.h | 5 +++ boot/zephyr/nrf_cleanup.c | 70 ++++++++++++++++++++++--------- 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/boot/zephyr/include/nrf_cleanup.h b/boot/zephyr/include/nrf_cleanup.h index 6b04cedfe..9e87e13f5 100644 --- a/boot/zephyr/include/nrf_cleanup.h +++ b/boot/zephyr/include/nrf_cleanup.h @@ -16,4 +16,9 @@ */ void nrf_cleanup_peripheral(void); +/** + * Perform cleanup of non-secure RAM that may have been used by MCUBoot. + */ +void nrf_cleanup_ns_ram(void); + #endif diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index 5bab26b24..c1cc1c290 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -5,9 +5,8 @@ */ #include -#if defined(NRF_UARTE0) || defined(NRF_UARTE1) - #include -#endif +#include +#include #if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) #include #endif @@ -20,6 +19,15 @@ #include +#if USE_PARTITION_MANAGER +#include +#endif + +#if defined(NRF_UARTE0) || defined(NRF_UARTE1) || defined(NRF_UARTE20) || \ + defined(NRF_UARTE30) +#define NRF_UARTE_CLEANUP +#endif + #define NRF_UARTE_SUBSCRIBE_CONF_OFFS offsetof(NRF_UARTE_Type, SUBSCRIBE_STARTRX) #define NRF_UARTE_SUBSCRIBE_CONF_SIZE (offsetof(NRF_UARTE_Type, EVENTS_CTS) -\ NRF_UARTE_SUBSCRIBE_CONF_OFFS) @@ -37,6 +45,23 @@ static inline void nrf_cleanup_rtc(NRF_RTC_Type * rtc_reg) } #endif +#if defined(NRF_UARTE_CLEANUP) +static NRF_UARTE_Type *nrf_uarte_to_clean[] = { +#if defined(NRF_UARTE0) + NRF_UARTE0, +#endif +#if defined(NRF_UARTE1) + NRF_UARTE1, +#endif +#if defined(NRF_UARTE20) + NRF_UARTE20, +#endif +#if defined(NRF_UARTE30) + NRF_UARTE30, +#endif +}; +#endif + static void nrf_cleanup_clock(void) { nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); @@ -53,26 +78,31 @@ void nrf_cleanup_peripheral(void) #if defined(NRF_RTC2) nrf_cleanup_rtc(NRF_RTC2); #endif -#if defined(NRF_UARTE0) - nrf_uarte_disable(NRF_UARTE0); - nrf_uarte_int_disable(NRF_UARTE0, 0xFFFFFFFF); -#if defined(NRF_DPPIC) - /* Clear all SUBSCRIBE configurations. */ - memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); - /* Clear all PUBLISH configurations. */ - memset((uint8_t *)NRF_UARTE0 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); -#endif -#endif -#if defined(NRF_UARTE1) - nrf_uarte_disable(NRF_UARTE1); - nrf_uarte_int_disable(NRF_UARTE1, 0xFFFFFFFF); + +#if defined(NRF_UARTE_CLEANUP) + for (int i = 0; i < sizeof(nrf_uarte_to_clean) / sizeof(nrf_uarte_to_clean[0]); ++i) { + NRF_UARTE_Type *current = nrf_uarte_to_clean[i]; + + nrfy_uarte_int_disable(current, 0xFFFFFFFF); + nrfy_uarte_int_uninit(current); + nrfy_uarte_task_trigger(current, NRF_UARTE_TASK_STOPRX); + + nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_RXSTARTED); + nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_ENDRX); + nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_RXTO); + nrfy_uarte_disable(current); + #if defined(NRF_DPPIC) - /* Clear all SUBSCRIBE configurations. */ - memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, NRF_UARTE_SUBSCRIBE_CONF_SIZE); - /* Clear all PUBLISH configurations. */ - memset((uint8_t *)NRF_UARTE1 + NRF_UARTE_PUBLISH_CONF_OFFS, 0, NRF_UARTE_PUBLISH_CONF_SIZE); + /* Clear all SUBSCRIBE configurations. */ + memset((uint8_t *)current + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, + NRF_UARTE_SUBSCRIBE_CONF_SIZE); + /* Clear all PUBLISH configurations. */ + memset((uint8_t *)current + NRF_UARTE_PUBLISH_CONF_OFFS, 0, + NRF_UARTE_PUBLISH_CONF_SIZE); #endif + } #endif + #if defined(NRF_PPI) nrf_ppi_channels_disable_all(NRF_PPI); #endif From 61be32f6fe15122363d27b512490186c46be648b Mon Sep 17 00:00:00 2001 From: Christian Taedcke Date: Thu, 10 Feb 2022 15:37:49 +0100 Subject: [PATCH 103/149] [nrf noup] loader: Fix reading reset addr to support ext flash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When mcuboot_secondary is on external flash, the image header cannot dircetly be accessed via secondary_fa->fa_off. Instead the provided function boot_img_hdr() is used now. Additionally a similar issue is present when trying to read the address of the reset handler. For this flash_area_read() is used now. With this patch is possible to have the update partiton mcuboot_secondary on external flash and update a updatable bootloader (mcuboot) in s0 and/or s1. Signed-off-by: Christian Taedcke Signed-off-by: Ole Sæther Signed-off-by: Sigvart Hovland Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit c1cf5e424057fea8a317bccd88dff62888453ccf) (cherry picked from commit f239be93f8ac5b71ea65140a30207b8923ffe606) --- boot/bootutil/src/loader.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index e41fac32f..9554f5365 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -754,10 +754,9 @@ boot_validated_swap_type(struct boot_loader_state *state, #if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); - struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; - uint32_t vtable_addr = 0; - uint32_t *vtable = 0; + struct image_header *hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY); uint32_t reset_addr = 0; + int rc = 0; /* Patch needed for NCS. Since image 0 (the app) and image 1 (the other * B1 slot S0 or S1) share the same secondary slot, we need to check * whether the update candidate in the secondary slot is intended for @@ -767,20 +766,22 @@ boot_validated_swap_type(struct boot_loader_state *state, */ if (hdr->ih_magic == IMAGE_MAGIC) { - vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; - vtable = (uint32_t *)(vtable_addr); - reset_addr = vtable[1]; + rc = flash_area_read(secondary_fa, hdr->ih_hdr_size + + sizeof(uint32_t), &reset_addr, + sizeof(reset_addr)); + if (rc != 0) { + return BOOT_SWAP_TYPE_FAIL; + } #ifdef PM_S1_ADDRESS #ifdef PM_CPUNET_B0N_ADDRESS if(reset_addr < PM_CPUNET_B0N_ADDRESS) #endif { const struct flash_area *primary_fa; - int rc = flash_area_open(flash_area_id_from_multi_image_slot( + rc = flash_area_open(flash_area_id_from_multi_image_slot( BOOT_CURR_IMG(state), BOOT_SLOT_PRIMARY), &primary_fa); - if (rc != 0) { return BOOT_SWAP_TYPE_FAIL; } @@ -811,16 +812,19 @@ boot_validated_swap_type(struct boot_loader_state *state, upgrade_valid = true; } -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) \ + && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) /* If the update is valid, and it targets the network core: perform the * update and indicate to the caller of this function that no update is * available */ if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) { + struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; + uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; + uint32_t *net_core_fw_addr = (uint32_t *)(vtable_addr); uint32_t fw_size = hdr->ih_img_size; - BOOT_LOG_INF("Starting network core update"); - int rc = pcd_network_core_update(vtable, fw_size); + rc = pcd_network_core_update(net_core_fw_addr, fw_size); if (rc != 0) { swap_type = BOOT_SWAP_TYPE_FAIL; From 2b78d901c3e5c76eb88f95b48c2c4df2a4c78045 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 22 Sep 2023 21:31:08 +0000 Subject: [PATCH 104/149] [nrf noup] loader: Do not check reset vector for XIP image The XIP image, 2, does not have reset vector. Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 1e991723c85e8ef8d6df432f196ec75c89caf78c) (cherry picked from commit 1ec17e963cb21d6978792e2aaf504838f20b52d8) (cherry picked from commit 99de74982aaef827e0fb0e8179f2f74d02230d8a) --- boot/bootutil/src/loader.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 9554f5365..bac003905 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -674,6 +674,16 @@ boot_validate_slot(struct boot_loader_state *state, int slot, * overwriting an application written to the incorrect slot. * This feature is only supported by ARM platforms. */ +#if MCUBOOT_IMAGE_NUMBER >= 3 + /* Currently the MCUboot can be configured for up to 3 image, where image number 2 is + * designated for XIP, where it is the second part of image stored in slots of image + * 0. This part of image is not bootable, as the XIP setup is done by the app in + * image 0 slot, and it does not carry the reset vector. + */ + if (fap == state->imgs[2][BOOT_SLOT_SECONDARY].area) { + goto out; + } +#endif if (fap == BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY)) { struct image_header *secondary_hdr = boot_img_hdr(state, slot); uint32_t internal_img_addr = 0; /* either the reset handler addres or the image beginning addres */ From 0f3b981338aff524c8fea81384b6a467df95dbdd Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 18 Sep 2023 13:47:00 +0100 Subject: [PATCH 105/149] [nrf noup] zephyr: Add RAM flash configuration to cache for sysbuild Puts the flash simulation configurtion into cache variables that can be used by other applications and CMake code to know specifics on the simulated flash details Signed-off-by: Jamie McCrae (cherry picked from commit c8d8f5a48cf1f17bad6cbc41dfd83a5f584ab005) (cherry picked from commit 6512a0366e3d68a3a59fbc3ccd943e85dc98ae2a) --- boot/zephyr/CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 78486cdff..50ee78547 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -781,3 +781,14 @@ zephyr_library_sources( ${BOOT_DIR}/zephyr/nrf_cleanup.c ) endif() + +if(SYSBUILD AND CONFIG_PCD_APP) + # Sysbuild requires details of the RAM flash device are stored to the cache of MCUboot so + # that they can be read when running partition manager + dt_nodelabel(ram_flash_dev NODELABEL flash_sim0) + dt_reg_addr(ram_flash_addr PATH ${ram_flash_dev}) + dt_reg_size(ram_flash_size PATH ${ram_flash_dev}) + + set(RAM_FLASH_ADDR "${ram_flash_addr}" CACHE STRING "" FORCE) + set(RAM_FLASH_SIZE "${ram_flash_size}" CACHE STRING "" FORCE) +endif() From 9dcb162c9bd53a35689675865c3e549ed5aa0061 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Tue, 17 Oct 2023 11:28:09 +0200 Subject: [PATCH 106/149] [nrf noup] zephyr: Boot even if EXT_ABI is not provided This removes the `return;` to ensure that the application is booted even if EXT_ABI is not provided to the application because it does not include `FW_INFO`. Added a bit more description to the error messages when FW_INFO is not found and EXT_ABI is not able to be provided to the next image. Ref. NCSDK-24132 Signed-off-by: Sigvart Hovland (cherry picked from commit d07555bf0439aeec7c15609c46a85a06fa9be807) (cherry picked from commit 0f20d8ef9909c6c508024d9ea04bcfaaf4929dc5) --- boot/zephyr/main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 2f39bbabe..ba8ad43c0 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -217,13 +217,16 @@ static void do_boot(struct boot_rsp *rsp) #endif #if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED) - bool provided = fw_info_ext_api_provide(fw_info_find((uint32_t)vt), true); + const struct fw_info *firmware_info = fw_info_find((uint32_t) vt); + bool provided = fw_info_ext_api_provide(firmware_info, true); #ifdef PM_S0_ADDRESS /* Only fail if the immutable bootloader is present. */ if (!provided) { - BOOT_LOG_ERR("Failed to provide EXT_APIs\n"); - return; + if (firmware_info == NULL) { + BOOT_LOG_WRN("Unable to find firmware info structure in %p", vt); + } + BOOT_LOG_ERR("Failed to provide EXT_APIs to %p", vt); } #endif #endif From 25ae80d835346ea878144816ff4aa447603e3905 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Wed, 27 Sep 2023 15:18:04 +0200 Subject: [PATCH 107/149] =?UTF-8?q?[nrf=20noup]=C2=A0loader:=20Add=20firmw?= =?UTF-8?q?are=20version=20check=20downgrade=20prevention?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For nRF53, the only existing version number metadata is stored in the `firmware_info` structure in the network core. This utilizes PCD to read out the version number and compares it against the version number found in the secondary slot for the network core. Ref. NCSDK-21379 Signed-off-by: Sigvart Hovland Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 42e8551d6bdcb50388ab7aac51d44aa12cf8ef55) (cherry picked from commit 420ac794db054e9a3bae31c6627d5b08920de0ed) (cherry picked from commit d1c8f64803b71430c49329cbf6171a76c545ff6d) --- boot/bootutil/src/loader.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index bac003905..f8ef11470 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -55,6 +55,10 @@ #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) #include +#ifdef CONFIG_PCD_READ_NETCORE_APP_VERSION +#include +int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); +#endif #endif #ifdef MCUBOOT_ENC_IMAGES @@ -626,9 +630,21 @@ boot_validate_slot(struct boot_loader_state *state, int slot, int rc; /* Check if version of secondary slot is sufficient */ - rc = boot_compare_version( + +#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) { + rc = pcd_version_cmp_net(fap, boot_img_hdr(state, BOOT_SLOT_SECONDARY)); + } else { + rc = boot_compare_version( &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); + } +#else + rc = boot_compare_version( + &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, + &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); +#endif if (rc < 0 && !boot_check_header_erased(state, BOOT_SLOT_PRIMARY)) { BOOT_LOG_ERR("insufficient version in secondary slot"); boot_scramble_slot(fap, slot); From 99c2c4c56af17118600c5536ef5d91c66bc28bad Mon Sep 17 00:00:00 2001 From: Nikodem Kastelik Date: Mon, 9 Oct 2023 09:55:57 +0200 Subject: [PATCH 108/149] [nrf noup] boards: thingy53: disable GPIO ISR support Change disables GPIO interrupt support in Zephyr GPIO driver, which is not obligatory for MCUboot. This is needed to reduce memory footprint. Signed-off-by: Nikodem Kastelik (cherry picked from commit 937e0f6d566c43d7b2445bd74b586ef28fb64aff) (cherry picked from commit 2c695f49eec83510b9d3df473b20089497491185) --- boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index 93be36738..d68509786 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -21,6 +21,7 @@ CONFIG_UART_LINE_CTRL=y # MCUBoot serial CONFIG_GPIO=y +CONFIG_GPIO_NRFX_INTERRUPT=n CONFIG_MCUBOOT_SERIAL=y CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y CONFIG_BOOT_SERIAL_CDC_ACM=y From 8b0df1598c2e1309a907995a16b9228386bd6852 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 31 Aug 2023 08:58:31 +0100 Subject: [PATCH 109/149] [nrf noup] loader: Fix missing PCD define check Fixes a missing PCD define check, an image might have the network core partition layout set but if PCD support is not enabled then it should not assume that PCD support is part of mcuboot. Signed-off-by: Jamie McCrae (cherry picked from commit 1ca64e93ce9f7484e9033989ff7dbfcacab0864b) (cherry picked from commit a23ae31a24f2f9f0bfda39386aa2cf8c364c135f) --- boot/bootutil/src/loader.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index f8ef11470..717558b0c 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -839,7 +839,7 @@ boot_validated_swap_type(struct boot_loader_state *state, } #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) \ - && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) + && !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) && defined(CONFIG_PCD_APP) /* If the update is valid, and it targets the network core: perform the * update and indicate to the caller of this function that no update is * available @@ -866,7 +866,8 @@ boot_validated_swap_type(struct boot_loader_state *state, swap_type = BOOT_SWAP_TYPE_NONE; } } -#endif /* CONFIG_SOC_NRF5340_CPUAPP */ +#endif /* CONFIG_SOC_NRF5340_CPUAPP && PM_CPUNET_B0N_ADDRESS && + !CONFIG_NRF53_MULTI_IMAGE_UPDATE && CONFIG_PCD_APP */ } return swap_type; From c6ebd735efb78b636b87dac128d7b7f5ded28875 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Wed, 31 May 2023 14:41:13 +0200 Subject: [PATCH 110/149] [nrf noup] boot: Add support for NSIB and multi-image This adds support for using both NSIB and the multi-image configuration in MCUboot. Before this was not possible due to upgradable bootloader support through NSIB was using the `UPDATEABLE_IMAGE_NUMBER` configuration to update the updateable bootloader. In this commit we change from using `FLASH_AREA_IMAGE_PRIMARY` to get the flash area ID to using the bootloader state where we set the flash area ID of the free updatable bootloader slot if the image is intended for this slot. Ref. NCSDK-19223 Ref. NCSDK-23305 Signed-off-by: Sigvart Hovland Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 75073fd88eca232c350c9a0af3c859815cb1ca4e) (cherry picked from commit 5cb4e7420b182677f120d302e71e3bd8c75f6646) --- boot/bootutil/src/loader.c | 33 ++++++++++++++++++++++--- boot/zephyr/include/sysflash/sysflash.h | 19 ++++++++++++-- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 717558b0c..9b5c015e0 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -714,6 +714,11 @@ boot_validate_slot(struct boot_loader_state *state, int slot, if (BOOT_CURR_IMG(state) == 1) { 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) { + min_addr = PM_S0_ADDRESS; + max_addr = pri_fa->fa_off + pri_fa->fa_size; +#endif } else #endif { @@ -811,10 +816,30 @@ boot_validated_swap_type(struct boot_loader_state *state, if (rc != 0) { return BOOT_SWAP_TYPE_FAIL; } - /* Get start and end of primary slot for current image */ - 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 this image */ + /* 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; + + /* NSIB upgrade slot */ + rc = flash_area_open((uint32_t)_image_1_primary_slot_id, &nsib_fa); + + 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; + } +#else + return BOOT_SWAP_TYPE_NONE; +#endif + + } else if (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; } } diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index 7112f9baa..f1ef4100e 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -23,9 +23,24 @@ /* If B0 is present then two bootloaders are present, and we must use * a single secondary slot for both primary slots. */ -#ifdef PM_B0_ADDRESS - +#if defined(PM_B0_ADDRESS) extern uint32_t _image_1_primary_slot_id[]; +#endif +#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) +#elif defined(PM_B0_ADDRESS) #define FLASH_AREA_IMAGE_PRIMARY(x) \ ((x == 0) ? \ From fffd071d47e3bfb3ff62737db015089cce611c5c Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 10 Aug 2023 17:32:48 +0000 Subject: [PATCH 111/149] [nrf noup] sysflash: Move partition manager definitions to pm_sysflash.h Making sysflash.h and pm_sysflash.h more readable. Signed-off-by: Dominik Ermel (cherry picked from commit bc86df639008e27e8296b9253079944c689eacad) (cherry picked from commit 2c2c2e559f4ae27ca4d3de06815b0e649405b27d) --- boot/zephyr/include/sysflash/pm_sysflash.h | 92 ++++++++++++++++++++++ boot/zephyr/include/sysflash/sysflash.h | 90 ++------------------- 2 files changed, 97 insertions(+), 85 deletions(-) create mode 100644 boot/zephyr/include/sysflash/pm_sysflash.h diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h new file mode 100644 index 000000000..377291e8b --- /dev/null +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef __PM_SYSFLASH_H__ +#define __PM_SYSFLASH_H__ +/* Blocking the __SYSFLASH_H__ */ +#define __SYSFLASH_H__ + +#include +#include + +#ifndef CONFIG_SINGLE_APPLICATION_SLOT + +#if (MCUBOOT_IMAGE_NUMBER == 1) + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID + +#elif (MCUBOOT_IMAGE_NUMBER == 2) + +/* If B0 is present then two bootloaders are present, and we must use + * a single secondary slot for both primary slots. + */ +#if defined(PM_B0_ADDRESS) +extern uint32_t _image_1_primary_slot_id[]; +#endif +#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) +#elif defined(PM_B0_ADDRESS) + +#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 + +#define FLASH_AREA_IMAGE_PRIMARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_PRIMARY_ID : \ + (x == 1) ? \ + PM_MCUBOOT_PRIMARY_1_ID : \ + 255 ) + +#define FLASH_AREA_IMAGE_SECONDARY(x) \ + ((x == 0) ? \ + PM_MCUBOOT_SECONDARY_ID: \ + (x == 1) ? \ + PM_MCUBOOT_SECONDARY_1_ID: \ + 255 ) + +#endif /* PM_B0_ADDRESS */ + +#endif +#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID + +#else /* CONFIG_SINGLE_APPLICATION_SLOT */ + +#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID +#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID +/* NOTE: Scratch parition is not used by single image DFU but some of + * functions in common files reference it, so the definitions has been + * provided to allow compilation of common units. + */ +#define FLASH_AREA_IMAGE_SCRATCH 0 + +#endif /* CONFIG_SINGLE_APPLICATION_SLOT */ + +#endif /* __PM_SYSFLASH_H__ */ diff --git a/boot/zephyr/include/sysflash/sysflash.h b/boot/zephyr/include/sysflash/sysflash.h index f1ef4100e..3c3638d7f 100644 --- a/boot/zephyr/include/sysflash/sysflash.h +++ b/boot/zephyr/include/sysflash/sysflash.h @@ -4,93 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef __SYSFLASH_H__ -#define __SYSFLASH_H__ - #if USE_PARTITION_MANAGER -#include -#include - -#ifndef CONFIG_SINGLE_APPLICATION_SLOT - -#if (MCUBOOT_IMAGE_NUMBER == 1) - -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID - -#elif (MCUBOOT_IMAGE_NUMBER == 2) - -/* If B0 is present then two bootloaders are present, and we must use - * a single secondary slot for both primary slots. - */ -#if defined(PM_B0_ADDRESS) -extern uint32_t _image_1_primary_slot_id[]; -#endif -#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) - -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) -#elif defined(PM_B0_ADDRESS) - -#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 - -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) - -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) - -#endif /* PM_B0_ADDRESS */ - +/* Blocking the rest of the file */ +#define __SYSFLASH_H__ +#include #endif -#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID - -#else /* CONFIG_SINGLE_APPLICATION_SLOT */ - -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_PRIMARY_ID -/* NOTE: Scratch parition is not used by single image DFU but some of - * functions in common files reference it, so the definitions has been - * provided to allow compilation of common units. - */ -#define FLASH_AREA_IMAGE_SCRATCH 0 -#endif /* CONFIG_SINGLE_APPLICATION_SLOT */ - -#else +#ifndef __SYSFLASH_H__ +#define __SYSFLASH_H__ -#include #include #include #include @@ -149,6 +71,4 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #endif /* CONFIG_SINGLE_APPLICATION_SLOT */ -#endif /* USE_PARTITION_MANAGER */ - #endif /* __SYSFLASH_H__ */ From d48508c73770213e38042caf1ad561c51d506286 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 11 Aug 2023 12:29:13 +0000 Subject: [PATCH 112/149] [nrf noup] sysflash: Add support for three images The commit modifies pm_sysflash.h to add support for three application images. Ref. NCSDK-19223 Signed-off-by: Dominik Ermel Signed-off-by: Sigvart Hovland (cherry picked from commit 3b3298de5dae0055bf95c2bf62a7f45a8c36b950) (cherry picked from commit 7025efda58de8c60794c1622bb76338ad0342eac) --- boot/zephyr/include/sysflash/pm_sysflash.h | 82 ++++++++++++---------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h index 377291e8b..db60ddd03 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -11,37 +11,19 @@ #include #include +#include #ifndef CONFIG_SINGLE_APPLICATION_SLOT -#if (MCUBOOT_IMAGE_NUMBER == 1) - -#define FLASH_AREA_IMAGE_PRIMARY(x) PM_MCUBOOT_PRIMARY_ID -#define FLASH_AREA_IMAGE_SECONDARY(x) PM_MCUBOOT_SECONDARY_ID - -#elif (MCUBOOT_IMAGE_NUMBER == 2) - +#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. */ -#if defined(PM_B0_ADDRESS) extern uint32_t _image_1_primary_slot_id[]; -#endif -#if defined(PM_B0_ADDRESS) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) +#endif /* (MCUBOOT_IMAGE_NUMBER == 2 && defined(PM_B0_ADDRESS) */ -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) -#elif 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) ? \ @@ -56,26 +38,52 @@ extern uint32_t _image_1_primary_slot_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 + +#if (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, \ + FLASH_AREA_IMAGE_1_SLOTS +#elif (MCUBOOT_IMAGE_NUMBER == 3) +#define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS, \ + FLASH_AREA_IMAGE_1_SLOTS, \ + FLASH_AREA_IMAGE_2_SLOTS #else +#error Unsupported number of images +#endif -#define FLASH_AREA_IMAGE_PRIMARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_PRIMARY_ID : \ - (x == 1) ? \ - PM_MCUBOOT_PRIMARY_1_ID : \ - 255 ) +static inline uint32_t __flash_area_ids_for_slot(int img, int slot) +{ + static const int all_slots[] = { + ALL_AVAILABLE_SLOTS + }; + return all_slots[img * 2 + slot]; +}; -#define FLASH_AREA_IMAGE_SECONDARY(x) \ - ((x == 0) ? \ - PM_MCUBOOT_SECONDARY_ID: \ - (x == 1) ? \ - PM_MCUBOOT_SECONDARY_1_ID: \ - 255 ) +#undef FLASH_AREA_IMAGE_0_SLOTS +#undef FLASH_AREA_IMAGE_1_SLOTS +#undef FLASH_AREA_IMAGE_2_SLOTS +#undef ALL_AVAILABLE_SLOTS -#endif /* PM_B0_ADDRESS */ +#define FLASH_AREA_IMAGE_PRIMARY(x) __flash_area_ids_for_slot(x, 0) +#define FLASH_AREA_IMAGE_SECONDARY(x) __flash_area_ids_for_slot(x, 1) +#if !defined(CONFIG_BOOT_SWAP_USING_MOVE) +#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID #endif -#define FLASH_AREA_IMAGE_SCRATCH PM_MCUBOOT_SCRATCH_ID + +#endif /* MCUBOOT_IMAGE_NUMBER == 2) && defined(PM_B0_ADDRESS) && \ + * !defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) + */ #else /* CONFIG_SINGLE_APPLICATION_SLOT */ From a074d6ff706e18cddf6fcc00ece9a4a0ccb24ca0 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 15 Feb 2024 16:47:25 +0100 Subject: [PATCH 113/149] [nrf noup] loader: introduced cleanup of unusable secondary slot Added procedure which clean-up content of all the secondary slot which contains valid header but couldn't be assigned to any of supported primary images. This behavior is needed when configuration allows to use one secondary slot for collecting image for multiple primary slots. Signed-off-by: Andrzej Puzdrowski Signed-off-by: Tomasz Chyrowicz (cherry picked from commit bd97f58190446c2a6e6a6e1a273b38a0ae848273) (cherry picked from commit 1e13c43c8faa7eff93ebd0ef85bf7d6bf7595000) --- boot/bootutil/src/loader.c | 90 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 9b5c015e0..f89128678 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -766,6 +766,87 @@ boot_validate_slot(struct boot_loader_state *state, int slot, FIH_RET(fih_rc); } +#if defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ +(defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP)) + +#define SEC_SLOT_VIRGIN 0 +#define SEC_SLOT_TOUCHED 1 +#define SEC_SLOT_ASSIGNED 2 + +#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 + * mocking two logical secondary + */ +#define SEC_SLOT_PHYSICAL_CNT 1 +#else +#define SEC_SLOT_PHYSICAL_CNT MCUBOOT_IMAGE_NUMBER +#endif + +static uint8_t sec_slot_assignmnet[SEC_SLOT_PHYSICAL_CNT] = {0}; + +static inline void sec_slot_touch(struct boot_loader_state *state) +{ + 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; + } +} + +static inline void sec_slot_mark_assigned(struct boot_loader_state *state) +{ + uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); + + sec_slot_assignmnet[idx] = SEC_SLOT_ASSIGNED; +} + +/** + * Cleanu 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. + * + * This function is supposed to be called after boot_validated_swap_type() + * iterates over all the images in context_boot_go(). + */ +static void sec_slot_cleanup_if_unusable(void) +{ + uint8_t idx; + + for (idx = 0; idx < SEC_SLOT_PHYSICAL_CNT; idx++) { + if (SEC_SLOT_TOUCHED == sec_slot_assignmnet[idx]) { + const struct flash_area *secondary_fa; + int rc; + + rc = flash_area_open(flash_area_id_from_multi_image_slot(idx, BOOT_SLOT_SECONDARY), + &secondary_fa); + 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); + } + } + + if (rc) { + BOOT_LOG_ERR("Can not cleanup secondary slot of %d. image.", idx); + } + } + } +} +#else +static inline void sec_slot_touch(struct boot_loader_state *state) +{ +} +static inline void sec_slot_mark_assigned(struct boot_loader_state *state) +{ +} +static inline void sec_slot_cleanup_if_unusable(void) +{ +} +#endif /* defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ + defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) */ + #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) /** * Determines which swap operation to perform, if any. If it is determined @@ -803,6 +884,9 @@ boot_validated_swap_type(struct boot_loader_state *state, if (rc != 0) { return BOOT_SWAP_TYPE_FAIL; } + + sec_slot_touch(state); + #ifdef PM_S1_ADDRESS #ifdef PM_CPUNET_B0N_ADDRESS if(reset_addr < PM_CPUNET_B0N_ADDRESS) @@ -836,6 +920,7 @@ boot_validated_swap_type(struct boot_loader_state *state, } #else return BOOT_SWAP_TYPE_NONE; + #endif } else if (reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { @@ -844,7 +929,9 @@ boot_validated_swap_type(struct boot_loader_state *state, } } #endif /* PM_S1_ADDRESS */ + sec_slot_mark_assigned(state); } + #endif /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); @@ -1910,6 +1997,9 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } } + /* cleanup secondary slots which were recognized unusable*/ + sec_slot_cleanup_if_unusable(); + #if (BOOT_IMAGE_NUMBER > 1) if (has_upgrade) { /* Iterate over all the images and verify whether the image dependencies From 264c3711538bbb6b73b21b509a0c70cc19142938 Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Fri, 17 May 2024 18:25:07 +0200 Subject: [PATCH 114/149] [nrf noup] loader: remove cleanup for direct xip mode Move ifdefs just to not add code for cleanup unusable slot when direct xip mode is enabled to avoid warnings. Signed-off-by: Grzegorz Chwierut (cherry picked from commit 271e50509bfb6d9625f25b4b6f8ccd991799e93e) (cherry picked from commit 210289dfff728925f2e56ffaacfea95aec49d575) --- boot/bootutil/src/loader.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index f89128678..1fb24808e 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -766,6 +766,8 @@ boot_validate_slot(struct boot_loader_state *state, int slot, FIH_RET(fih_rc); } +#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) + #if defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ (defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP)) @@ -847,7 +849,6 @@ static inline void sec_slot_cleanup_if_unusable(void) #endif /* defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) */ -#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) /** * Determines which swap operation to perform, if any. If it is determined * that a swap operation is required, the image in the secondary slot is checked From 5f4682db5069eaa5e42a9553fddb751f0fad4d3b Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Mon, 27 May 2024 13:59:49 +0200 Subject: [PATCH 115/149] [nrf noup] boot/zephyr: fix fw_info search By the upstream patch the vt get now the pointer to the copy of the arm_vector instead of original. This patch fixes address of the firmware which is to be taken by the fw_info_find. Signed-off-by: Andrzej Puzdrowski (cherry picked from commit 8949a6a34d4522447069a6630866f136132e3ac3) (cherry picked from commit b054302ac43ccf433f887ff441e28fcfa01a20a2) --- boot/zephyr/main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index ba8ad43c0..f05a0dfb4 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -217,7 +217,14 @@ static void do_boot(struct boot_rsp *rsp) #endif #if defined(CONFIG_FW_INFO) && !defined(CONFIG_EXT_API_PROVIDE_EXT_API_UNUSED) - const struct fw_info *firmware_info = fw_info_find((uint32_t) vt); + uintptr_t fw_start_addr; + + rc = flash_device_base(rsp->br_flash_dev_id, &fw_start_addr); + assert(rc == 0); + + fw_start_addr += rsp->br_image_off + rsp->br_hdr->ih_hdr_size; + + const struct fw_info *firmware_info = fw_info_find(fw_start_addr); bool provided = fw_info_ext_api_provide(firmware_info, true); #ifdef PM_S0_ADDRESS From 304f4fbea8a0b21574964ea1c19deb4b5e0cc6a2 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 13 Jun 2024 16:34:55 +0200 Subject: [PATCH 116/149] [nrf noup] boot/../loader: skip downgrade prevention for s1/s0 This patch introduces skip on checking downgrade for s1/s0 upgrade image (chain-loaded by NSIB). which is used for upgrade MCUboot instance itself. Reason is that sdk-mcuboot has not access to semantic version of its own image. I also shouldn't touch HW counter used for hardware downgrade prevention for the application image (which was the case). HW counters for s0/s1 image are owned by NSIB because its role is to prevnt dongrades of s0/s1 MCUboot. Signed-off-by: Andrzej Puzdrowski Signed-off-by: Tomasz Chyrowicz (cherry picked from commit bf143850d06f24d83c51bc904034e3ccdf22290c) (cherry picked from commit 6ccfff81eb5f6d2573e8147f0a14ec80afddade8) --- boot/bootutil/include/bootutil/security_cnt.h | 9 +++ boot/bootutil/src/bootutil_loader.c | 7 ++ boot/bootutil/src/image_validate.c | 20 ++++++ boot/bootutil/src/loader.c | 65 +++++++++++++++++++ 4 files changed, 101 insertions(+) diff --git a/boot/bootutil/include/bootutil/security_cnt.h b/boot/bootutil/include/bootutil/security_cnt.h index 228ada8dc..ff3a7371c 100644 --- a/boot/bootutil/include/bootutil/security_cnt.h +++ b/boot/bootutil/include/bootutil/security_cnt.h @@ -39,6 +39,15 @@ extern "C" { */ fih_ret boot_nv_security_counter_init(void); +/** + * Checks if the specified image should have a security counter present on it or not + * + * @param image_index Index of the image to check (from 0). + * + * @return FIH_SUCCESS if security counter should be present; FIH_FAILURE if otherwise + */ +fih_ret boot_nv_image_should_have_security_counter(uint32_t image_index); + /** * Reads the stored value of a given image's security counter. * diff --git a/boot/bootutil/src/bootutil_loader.c b/boot/bootutil/src/bootutil_loader.c index 2052d4765..13c591cf5 100644 --- a/boot/bootutil/src/bootutil_loader.c +++ b/boot/bootutil/src/bootutil_loader.c @@ -262,6 +262,13 @@ boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_ const struct flash_area *fap = NULL; uint32_t img_security_cnt; int rc; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + FIH_CALL(boot_nv_image_should_have_security_counter, fih_rc, BOOT_CURR_IMG(state)); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + /* No security counter update needed. */ + return 0; + } fap = BOOT_IMG_AREA(state, slot); assert(fap != NULL); diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 3c1c5ec7f..da8194e99 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -247,6 +247,15 @@ bootutil_img_validate(struct boot_loader_state *state, fih_int security_cnt = fih_int_encode(INT_MAX); uint32_t img_security_cnt = 0; FIH_DECLARE(security_counter_valid, FIH_FAILURE); + FIH_DECLARE(security_counter_should_be_present, FIH_FAILURE); + + FIH_CALL(boot_nv_image_should_have_security_counter, security_counter_should_be_present, + image_index); + if (FIH_NOT_EQ(security_counter_should_be_present, FIH_SUCCESS) && + FIH_NOT_EQ(security_counter_should_be_present, FIH_FAILURE)) { + rc = -1; + goto out; + } #endif #ifdef MCUBOOT_MANIFEST_UPDATES bool manifest_found = false; @@ -519,6 +528,10 @@ bootutil_img_validate(struct boot_loader_state *state, goto out; } + if (FIH_EQ(security_counter_should_be_present, FIH_FAILURE)) { + goto skip_security_counter_read; + } + FIH_CALL(boot_nv_security_counter_get, fih_rc, image_index, &security_cnt); if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { @@ -553,6 +566,7 @@ bootutil_img_validate(struct boot_loader_state *state, /* The image's security counter has been successfully verified. */ security_counter_valid = fih_rc; +skip_security_counter_read: break; } #endif /* MCUBOOT_HW_ROLLBACK_PROT */ @@ -667,10 +681,16 @@ bootutil_img_validate(struct boot_loader_state *state, FIH_SET(fih_rc, valid_signature); #endif #ifdef MCUBOOT_HW_ROLLBACK_PROT + if (FIH_EQ(security_counter_should_be_present, FIH_FAILURE)) { + goto skip_security_counter_check; + } + if (FIH_NOT_EQ(security_counter_valid, FIH_SUCCESS)) { rc = -1; goto out; } + +skip_security_counter_check: #endif #ifdef MCUBOOT_MANIFEST_UPDATES diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 1fb24808e..c46a3659c 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -74,6 +74,9 @@ int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); BOOT_LOG_MODULE_DECLARE(mcuboot); static struct boot_loader_state boot_data; +#ifdef PM_S1_ADDRESS +static bool owner_nsib[BOOT_IMAGE_NUMBER] = {false}; +#endif #if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_DATA_SHARING) static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0}; @@ -766,6 +769,40 @@ boot_validate_slot(struct boot_loader_state *state, int slot, FIH_RET(fih_rc); } +#ifdef MCUBOOT_HW_ROLLBACK_PROT +/** + * Checks if the specified image should have a security counter present on it or not + * + * @param image_index Index of the image to check. + * + * @return true if security counter should be present; false if otherwise + */ +fih_ret boot_nv_image_should_have_security_counter(uint32_t image_index) +{ +#if defined(PM_S1_ADDRESS) + if (owner_nsib[image_index]) { + /* + * Downgrade prevention on S0/S1 image is managed by NSIB, which is a software (not + * hardware) check + */ + return FIH_FAILURE; + } +#endif + +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 + if (image_index == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { + /* + * Downgrade prevention on network core image is managed by NSIB which is a software (not + * hardware) check + */ + return FIH_FAILURE; + } +#endif + + return FIH_SUCCESS; +} +#endif /* MCUBOOT_HW_ROLLBACK_PROT */ + #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) #if defined(CONFIG_MCUBOOT_CLEANUP_UNUSABLE_SECONDARY) &&\ @@ -864,6 +901,9 @@ boot_validated_swap_type(struct boot_loader_state *state, int swap_type; FIH_DECLARE(fih_rc, FIH_FAILURE); bool upgrade_valid = false; +#if defined(PM_S1_ADDRESS) + owner_nsib[BOOT_CURR_IMG(state)] = false; +#endif #if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SLOT_SECONDARY); @@ -918,6 +958,7 @@ boot_validated_swap_type(struct boot_loader_state *state, && 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; } #else return BOOT_SWAP_TYPE_NONE; @@ -928,6 +969,10 @@ boot_validated_swap_type(struct boot_loader_state *state, /* The image in the secondary slot is not intended for any */ return BOOT_SWAP_TYPE_NONE; } + + if ((primary_fa->fa_off == PM_S0_ADDRESS) || (primary_fa->fa_off == PM_S1_ADDRESS)) { + owner_nsib[BOOT_CURR_IMG(state)] = true; + } } #endif /* PM_S1_ADDRESS */ sec_slot_mark_assigned(state); @@ -1891,6 +1936,26 @@ check_downgrade_prevention(struct boot_loader_state *state) uint32_t security_counter[2]; int rc; +#if defined(PM_S1_ADDRESS) + if (owner_nsib[BOOT_CURR_IMG(state)]) { + /* + * Downgrade prevention on S0/S1 image is managed by NSIB which is a software (not + * hardware) check + */ + return 0; + } +#endif + +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { + /* + * Downgrade prevention on network core image is managed by NSIB which is a software (not + * hardware) check + */ + return 0; + } +#endif + if (MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER) { /* If there was security no counter in slot 0, allow swap */ rc = bootutil_get_img_security_cnt(state, BOOT_SLOT_PRIMARY, From 18b8778100615a6488ace48fece53e99ca7a0fad Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Tue, 18 Jun 2024 17:35:41 +0200 Subject: [PATCH 117/149] [nrf noup] boot/../loader: reboot after updating s0/s1 As this is MCUboot updating itself, it should reboot the device so NSIB will chainload the update MCUboot Signed-off-by: Andrzej Puzdrowski (cherry picked from commit 674adc7d3f6508c9bfeb5f8af93ac489f93d25ce) (cherry picked from commit 7e0d80253cf5396ae5bf5f86a8735b3d7532a90f) --- boot/bootutil/src/loader.c | 10 ++++++++++ boot/zephyr/Kconfig | 1 + 2 files changed, 11 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index c46a3659c..149d80940 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -53,6 +53,10 @@ #ifndef MCUBOOT_MANIFEST_UPDATES +#ifdef __ZEPHYR__ +#include +#endif + #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) #include #ifdef CONFIG_PCD_READ_NETCORE_APP_VERSION @@ -2136,6 +2140,12 @@ 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: diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index a954c4dd5..4c0024b1e 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -18,6 +18,7 @@ config MCUBOOT select MPU_ALLOW_FLASH_WRITE if ARM_MPU select USE_DT_CODE_PARTITION if HAS_FLASH_LOAD_OFFSET select MCUBOOT_BOOTUTIL_LIB + select REBOOT if SECURE_BOOT config BOOT_USE_MBEDTLS bool From 8d6462ab3dd884e9ad16f354c4a6b9604dc80639 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 29 Aug 2024 12:41:37 +0100 Subject: [PATCH 118/149] [nrf noup] bootutil: loader: Fix netcore address checking Fixes an issues with wrongly checking the network core reset address Signed-off-by: Jamie McCrae (cherry picked from commit 1f364bf2105226a6a12eb51ef25bce2a7fe1219b) (cherry picked from commit 919ecf064763a75085bd35f9e5066756f03fb053) --- boot/bootutil/src/loader.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 149d80940..baa097a72 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -934,7 +934,7 @@ boot_validated_swap_type(struct boot_loader_state *state, #ifdef PM_S1_ADDRESS #ifdef PM_CPUNET_B0N_ADDRESS - if(reset_addr < PM_CPUNET_B0N_ADDRESS) + if(!(reset_addr >= PM_CPUNET_APP_ADDRESS && reset_addr < PM_CPUNET_APP_END_ADDRESS)) #endif { const struct flash_area *primary_fa; @@ -1006,7 +1006,8 @@ boot_validated_swap_type(struct boot_loader_state *state, * update and indicate to the caller of this function that no update is * available */ - if (upgrade_valid && reset_addr > PM_CPUNET_B0N_ADDRESS) { + if (upgrade_valid && reset_addr >= PM_CPUNET_APP_ADDRESS && + reset_addr < PM_CPUNET_APP_END_ADDRESS) { struct image_header *hdr = (struct image_header *)secondary_fa->fa_off; uint32_t vtable_addr = (uint32_t)hdr + hdr->ih_hdr_size; uint32_t *net_core_fw_addr = (uint32_t *)(vtable_addr); From d83b270d27c40cae1b84ad25b84d4accb82d5be8 Mon Sep 17 00:00:00 2001 From: Markus Lassila Date: Fri, 30 Aug 2024 13:10:05 +0300 Subject: [PATCH 119/149] [nrf noup] boot: zephyr: Do not lock PCD region with TF-M Previously PCD memory was locked as read-only, non-secure in MCUboot. Given that TF-M also needs write to PCD to communicate with b0n, the memory is left unlocked and locked to read-only, non-secure in TF-M. Signed-off-by: Markus Lassila (cherry picked from commit 599a1b9b55e61e17e1f9f95e1d8b136d0d5a3751) (cherry picked from commit 2e29ea662c45ef1bc07dbf36315abe3a35a7eec0) --- boot/zephyr/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index f05a0dfb4..8b39963a9 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -751,7 +751,11 @@ int main(void) } #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) - pcd_lock_ram(); +#if defined(PM_TFM_SECURE_ADDRESS) + pcd_lock_ram(false); +#else + pcd_lock_ram(true); +#endif #endif #endif /* USE_PARTITION_MANAGER && CONFIG_FPROTECT */ From 5c06e3d8fab67861e3373edd839032b51dea5042 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 10 Sep 2024 13:41:30 +0100 Subject: [PATCH 120/149] [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 Adds support for getting the maximum allowable image size for NSIB Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 352b2a4a9cdd531cb3a1401f100e7d82e7434958) (cherry picked from commit 8a76fc264125264aca061c138548cd199a33ae8d) --- boot/bootutil/src/bootutil_loader.c | 6 +- boot/bootutil/src/bootutil_misc.c | 12 ++ boot/bootutil/src/loader.c | 175 +++++++++++++-------- 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 | 69 ++++---- 7 files changed, 240 insertions(+), 106 deletions(-) create mode 100644 boot/bootutil/src/swap_nsib.c diff --git a/boot/bootutil/src/bootutil_loader.c b/boot/bootutil/src/bootutil_loader.c index 13c591cf5..0cc543944 100644 --- a/boot/bootutil/src/bootutil_loader.c +++ b/boot/bootutil/src/bootutil_loader.c @@ -146,15 +146,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all, struc * * 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 { diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 7c8d04012..fa95e6133 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -331,6 +331,18 @@ boot_write_enc_keys(const struct flash_area *fap, const struct boot_status *bs) uint32_t bootutil_max_image_size(struct boot_loader_state *state, const struct flash_area *fap) { +#if defined(CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + /* NSIB is a direct upgrade without any status or trailer, get the full size of the + * primary slot. + */ + const struct flash_area *fap_nsib = BOOT_IMG_AREA(state, 0); + assert(fap_nsib != NULL); + + return flash_area_get_size(fap_nsib); + } +#endif /* CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 */ + #if defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \ defined(MCUBOOT_FIRMWARE_LOADER) || \ defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index baa097a72..ae276674f 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -640,7 +640,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_SLOT_SECONDARY)); } else { rc = boot_compare_version( @@ -712,25 +712,45 @@ boot_validate_slot(struct boot_loader_state *state, int slot, uint32_t internal_img_addr = 0; /* either the reset handler addres or the image beginning addres */ uint32_t min_addr; uint32_t max_addr; + bool check_addresses = false; #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) { min_addr = flash_area_get_off(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); max_addr = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)) + min_addr; + +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + min_addr = MIN(min_addr, PM_S0_ADDRESS); + max_addr = MAX(max_addr, (PM_S0_ADDRESS + PM_S0_SIZE)); +#else + min_addr = MIN(min_addr, PM_S1_ADDRESS); + max_addr = MAX(max_addr, (PM_S1_ADDRESS + PM_S1_SIZE)); +#endif +#endif + check_addresses = true; } /* MCUBOOT_CHECK_HEADER_LOAD_ADDRESS takes priority over MCUBOOT_VERIFY_IMG_ADDRESS */ @@ -751,7 +771,8 @@ boot_validate_slot(struct boot_loader_state *state, int slot, BOOT_LOG_DBG("Image %d expected load address 0x%x", BOOT_CURR_IMG(state), internal_img_addr); BOOT_LOG_DBG("Check 0x%x is within [min_addr, max_addr] = [0x%x, 0x%x)", internal_img_addr, min_addr, max_addr); - if (internal_img_addr < min_addr || internal_img_addr >= max_addr) { + + if (check_addresses == true && (internal_img_addr < min_addr || internal_img_addr >= max_addr)) { BOOT_LOG_ERR("Binary in secondary slot of image %d is not designated for the primary slot", BOOT_CURR_IMG(state)); BOOT_LOG_ERR("Erasing image from secondary slot"); @@ -816,36 +837,54 @@ fih_ret boot_nv_image_should_have_security_counter(uint32_t image_index) #define SEC_SLOT_TOUCHED 1 #define SEC_SLOT_ASSIGNED 2 -#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 - * mocking two logical secondary - */ -#define SEC_SLOT_PHYSICAL_CNT 1 +static uint8_t sec_slot_assignment[MCUBOOT_IMAGE_NUMBER] = {0}; + +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 +static inline void sec_slot_untouch(struct boot_loader_state *state) +{ + sec_slot_assignment[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] = SEC_SLOT_VIRGIN; + sec_slot_assignment[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] = SEC_SLOT_VIRGIN; +} #else -#define SEC_SLOT_PHYSICAL_CNT MCUBOOT_IMAGE_NUMBER +static inline void sec_slot_untouch(struct boot_loader_state *state) +{ +} #endif -static uint8_t sec_slot_assignmnet[SEC_SLOT_PHYSICAL_CNT] = {0}; - static inline void sec_slot_touch(struct boot_loader_state *state) { - uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + if (sec_slot_assignment[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] == SEC_SLOT_VIRGIN) { + sec_slot_assignment[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] = SEC_SLOT_TOUCHED; + } + } else if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { + if (sec_slot_assignment[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] == SEC_SLOT_VIRGIN) { + sec_slot_assignment[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] = SEC_SLOT_TOUCHED; + } + } +#endif - if (SEC_SLOT_VIRGIN == sec_slot_assignmnet[idx]) { - sec_slot_assignmnet[idx] = SEC_SLOT_TOUCHED; + if (sec_slot_assignment[BOOT_CURR_IMG(state)] == SEC_SLOT_VIRGIN) { + sec_slot_assignment[BOOT_CURR_IMG(state)] = SEC_SLOT_TOUCHED; } } static inline void sec_slot_mark_assigned(struct boot_loader_state *state) { - uint8_t idx = (SEC_SLOT_PHYSICAL_CNT == 1) ? 0 : BOOT_CURR_IMG(state); +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + sec_slot_assignment[CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER] = SEC_SLOT_ASSIGNED; + } else if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { + sec_slot_assignment[CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER] = SEC_SLOT_ASSIGNED; + } +#endif - sec_slot_assignmnet[idx] = SEC_SLOT_ASSIGNED; + sec_slot_assignment[BOOT_CURR_IMG(state)] = SEC_SLOT_ASSIGNED; } /** - * 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. @@ -857,8 +896,8 @@ static void sec_slot_cleanup_if_unusable(void) { uint8_t idx; - for (idx = 0; idx < SEC_SLOT_PHYSICAL_CNT; idx++) { - if (SEC_SLOT_TOUCHED == sec_slot_assignmnet[idx]) { + for (idx = 0; idx < MCUBOOT_IMAGE_NUMBER; idx++) { + if (SEC_SLOT_TOUCHED == sec_slot_assignment[idx]) { const struct flash_area *secondary_fa; int rc; @@ -866,18 +905,16 @@ static void sec_slot_cleanup_if_unusable(void) &secondary_fa); 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); - } } - if (rc) { - BOOT_LOG_ERR("Can not cleanup secondary slot of %d. image.", idx); - } + BOOT_LOG_ERR("Erase secondary: img %d: %d", idx, rc); } } } #else +static inline void sec_slot_untouch(struct boot_loader_state *state) +{ +} static inline void sec_slot_touch(struct boot_loader_state *state) { } @@ -909,7 +946,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_SLOT_SECONDARY); struct image_header *hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY); uint32_t reset_addr = 0; @@ -946,30 +983,31 @@ boot_validated_swap_type(struct boot_loader_state *state, return BOOT_SWAP_TYPE_FAIL; } /* 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; - - /* NSIB upgrade slot */ - rc = flash_area_open((uint32_t)_image_1_primary_slot_id, &nsib_fa); - - 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; - } +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + if (reset_addr >= PM_S0_ADDRESS && reset_addr <= (PM_S0_ADDRESS + PM_S0_SIZE)) { #else - return BOOT_SWAP_TYPE_NONE; - + 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; + } - } else if (reset_addr > (primary_fa->fa_off + primary_fa->fa_size)) { + 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 + } else if (reset_addr >= PM_S0_ADDRESS && reset_addr <= (PM_S0_ADDRESS + PM_S0_SIZE)) { +#endif + /* NSIB upgrade but for the wrong slot, must be erased */ + BOOT_LOG_ERR("Image in slot is for wrong s0/s1 image"); + flash_area_erase(secondary_fa, 0, secondary_fa->fa_size); + sec_slot_untouch(state); + BOOT_LOG_ERR("Cleaned-up secondary slot of image %d", BOOT_CURR_IMG(state)); + 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; } @@ -982,7 +1020,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)) { @@ -1497,7 +1535,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; @@ -2141,12 +2194,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: @@ -2214,13 +2261,17 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) */ } -#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT #ifdef PM_S1_ADDRESS /* Patch needed for NCS. Image 1 primary is the currently * 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; +#endif + +#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT +#ifdef PM_S1_ADDRESS 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..f8d6e8a88 --- /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_SLOT_SECONDARY, 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, false); + assert(rc == 0); + + rc = boot_copy_region(state, fap_sec, fap_pri, 0, 0, fap_pri->fa_size); + assert(rc == 0); + + rc = swap_scramble_trailer_sectors(state, fap_sec); + assert(rc == 0); + + rc = boot_scramble_region(fap_sec, 0, MIN((fap_pri->fa_size + sector_sz), fap_sec->fa_size), false); + 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 b564ea99e..90e0b3742 100644 --- a/boot/bootutil/src/swap_priv.h +++ b/boot/bootutil/src/swap_priv.h @@ -130,4 +130,12 @@ bool swap_write_block_size_check(struct boot_loader_state *state); */ 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 50ee78547..e9f4cebee 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -214,6 +214,12 @@ else() ) endif() endif() + + 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..42f25182e 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -15,48 +15,36 @@ #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 +#else +#define MCUBOOT_S0_S1_SLOTS +#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 +53,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 +61,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 +72,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 8e866896273bc123986ed23418b24e6de15b0b84 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 15 Oct 2024 11:31:20 +0100 Subject: [PATCH 121/149] [nrf noup] boot: bootutil: loader: Add s0/s1 checking of MCUboot image Adds a check that will also check the s0/s1 package version of the currently running MCUboot against a MCUboot update image to ensure that an older version of MCUboot isn't loaded to the opposite slot Signed-off-by: Jamie McCrae Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 9c834622b023e321350fca2aedb15a8a9570c63a) (cherry picked from commit d5f373adeb1c296c8d312ca8484f5f73414d7f48) (cherry picked from commit 4aba01c40bc3983d3d341b802b1769670b6f9d43) --- boot/bootutil/src/loader.c | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index ae276674f..e4b6e968a 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -90,6 +90,34 @@ static struct image_max_size image_max_sizes[BOOT_IMAGE_NUMBER] = {0}; #warning MCUBOOT_CHECK_HEADER_LOAD_ADDRESS takes precedence over MCUBOOT_VERIFY_IMG_ADDRESS #endif +#if (!defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)) || \ +defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) +#if !defined(__BOOTSIM__) +/* Used for holding static buffers in multiple functions to work around issues + * in older versions of gcc (e.g. 4.8.4) + */ +struct sector_buffer_t { + boot_sector_t primary[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS]; + boot_sector_t secondary[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS]; +#if MCUBOOT_SWAP_USING_SCRATCH + boot_sector_t scratch[BOOT_MAX_IMG_SECTORS]; +#endif +}; + +#endif +#endif + +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 && defined(MCUBOOT_OVERWRITE_ONLY) && \ + defined(MCUBOOT_DOWNGRADE_PREVENTION) +/* s0/s1 package version of the current MCUboot image */ +static const struct image_version mcuboot_s0_s1_image_version = { + .iv_major = CONFIG_MCUBOOT_MCUBOOT_S0_S1_VERSION_MAJOR, + .iv_minor = CONFIG_MCUBOOT_MCUBOOT_S0_S1_VERSION_MINOR, + .iv_revision = CONFIG_MCUBOOT_MCUBOOT_S0_S1_VERSION_REVISION, + .iv_build_num = CONFIG_MCUBOOT_MCUBOOT_S0_S1_VERSION_BUILD_NUMBER, +}; +#endif + /* Valid only for ARM Cortext M */ #define RESET_OFFSET (2 * sizeof(uint32_t)) @@ -646,11 +674,45 @@ boot_validate_slot(struct boot_loader_state *state, int slot, rc = boot_compare_version( &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (rc >= 0 && BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + /* Also check the new version of MCUboot against that of the current s0/s1 MCUboot + * trailer version to prevent downgrades + */ + int version_check; + + version_check = boot_compare_version( + &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, + &mcuboot_s0_s1_image_version); + + /* Only update rc if the currently running version is newer */ + if (version_check < rc) { + rc = version_check; + } + } +#endif } #else rc = boot_compare_version( &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, &boot_img_hdr(state, BOOT_SLOT_PRIMARY)->ih_ver); +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (rc >= 0 && BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { + /* Also check the new version of MCUboot against that of the current s0/s1 MCUboot + * trailer version to prevent downgrades + */ + int version_check; + + version_check = boot_compare_version( + &boot_img_hdr(state, BOOT_SLOT_SECONDARY)->ih_ver, + &mcuboot_s0_s1_image_version); + + /* Only update rc if the currently running version is newer */ + if (version_check < rc) { + rc = version_check; + } + } +#endif #endif if (rc < 0 && !boot_check_header_erased(state, BOOT_SLOT_PRIMARY)) { BOOT_LOG_ERR("insufficient version in secondary slot"); From ee17caa19cf2b23ad1cb55fc6ef50b056183a488 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 5 Dec 2024 10:20:19 +0000 Subject: [PATCH 122/149] [nrf noup] boot: Remove child/parent references Removes stray child/parent references Signed-off-by: Jamie McCrae (cherry picked from commit 9e2bba9806b33af0d52e1f62774de55a48d2538d) (cherry picked from commit eb8734740049d42334fadafd312347204c60c351) --- boot/bootutil/src/swap_priv.h | 2 +- boot/zephyr/pm.yml | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/boot/bootutil/src/swap_priv.h b/boot/bootutil/src/swap_priv.h index 90e0b3742..10473a9cc 100644 --- a/boot/bootutil/src/swap_priv.h +++ b/boot/bootutil/src/swap_priv.h @@ -131,7 +131,7 @@ bool swap_write_block_size_check(struct boot_loader_state *state); 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)) +CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 /** * Performs an NSIB update */ diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml index 13ffc44aa..ab8f6d1c3 100644 --- a/boot/zephyr/pm.yml +++ b/boot/zephyr/pm.yml @@ -4,9 +4,7 @@ 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 3471d3efef4671544021ff178c54d10ac2d6d21b Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 15 Jan 2025 15:09:55 +0000 Subject: [PATCH 123/149] [nrf noup] sysflash: Add missing _FLASH_0_ID definitions MCUboot uses SOC_FLASH_0_ID and SPI_FLASH_0_ID to distinguish between internal and external boot device. These IDs are provided by sysflash.h, but the pm_sysflash.h overrides entire file, and was lacking that definitions. Signed-off-by: Dominik Ermel (cherry picked from commit 60dcc0d468fde468f36637a5603204a8ea972b9b) (cherry picked from commit dbbf3fd5ed430df4c573bab4870ad6bbc044c960) --- boot/zephyr/include/sysflash/pm_sysflash.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h index 42f25182e..0cb16292f 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -84,4 +84,12 @@ static inline uint32_t __flash_area_ids_for_slot(int img, int slot) #endif /* CONFIG_SINGLE_APPLICATION_SLOT */ +#ifndef SOC_FLASH_0_ID +#define SOC_FLASH_0_ID 0 +#endif + +#ifndef SPI_FLASH_0_ID +#define SPI_FLASH_0_ID 1 +#endif + #endif /* __PM_SYSFLASH_H__ */ From 46d3758f77f37c4ff269d44e222f360e35ef2db3 Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk Date: Fri, 24 Jan 2025 08:59:31 +0100 Subject: [PATCH 124/149] [nrf noup] boot: zephyr: boards: Disabled NCS boot banner for thingy 53 Disabled NCS BOOT BANNER to save some flash, as Thingy:53 stopped to fit in the mcuboot partition. The boot banner is not used anyway, as logs are disabled. Signed-off-by: Kamil Kasperczyk (cherry picked from commit fd3ccd378677d6cd27df57dcb774698fa5adbdd9) (cherry picked from commit 19e8300332439b8d71e4aada5b90db4625ae6910) --- boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index d68509786..bbef18460 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -47,6 +47,7 @@ CONFIG_USB_CDC_ACM=y CONFIG_CBPRINTF_NANO=y CONFIG_TIMESLICING=n CONFIG_BOOT_BANNER=n +CONFIG_NCS_BOOT_BANNER=n CONFIG_CONSOLE=n CONFIG_CONSOLE_HANDLER=n CONFIG_UART_CONSOLE=n From 7e6db20d1e96db33fc0d34a0ad3bae3d02a6aa51 Mon Sep 17 00:00:00 2001 From: Sigurd Hellesvik Date: Thu, 6 Feb 2025 08:47:39 +0100 Subject: [PATCH 125/149] [nrf noup] partition_manager: Add support for internal flash netcore DFU Adds check to region of mcuboot_secondary_1 to put it in external flash only if CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY is set. This should allow for DFU from internal flash on the nRF5340 with dynamic partitioning. Also fixing a typo. Signed-off-by: Sigurd Hellesvik (cherry picked from commit 1f1b7be6c9500a53f9e55fe30a6b22898d5d478f) (cherry picked from commit 4185e97573e4ab34e501cf8dc7904d09e5c67507) --- boot/zephyr/pm.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/pm.yml b/boot/zephyr/pm.yml index ab8f6d1c3..eec62473c 100644 --- a/boot/zephyr/pm.yml +++ b/boot/zephyr/pm.yml @@ -78,11 +78,17 @@ mcuboot_pad: mcuboot_primary_1: region: ram_flash size: CONFIG_NRF53_RAM_FLASH_SIZE -#endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ +#endif /* CONFIG_NRF53_MCUBOOT_PRIMARY_1_RAM_FLASH */ #if (CONFIG_NRF53_MULTI_IMAGE_UPDATE) mcuboot_secondary_1: +#if defined(CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY) region: external_flash +#else + placement: + align: {start: CONFIG_FPROTECT_BLOCK_SIZE} + after: mcuboot_secondary +#endif size: CONFIG_NRF53_RAM_FLASH_SIZE #endif /* CONFIG_NRF53_MULTI_IMAGE_UPDATE */ From 9448d4b7959b17951850f8acdda8cb3bbea20611 Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Fri, 28 Mar 2025 17:46:28 +0100 Subject: [PATCH 126/149] [nrf noup] boot/zephyr: nrf54h20dk cleanup adaptations This commit removes NRF_CLOCK cleanup for this board build - for Lillium, there is no clock peripheral access from the app domain. Signed-off-by: Michal Kozikowski (cherry picked from commit 31766fcae89baee588d1ac49802ce5b1fd7b544d) (cherry picked from commit a5e4aeb25130206c786632e593f28a0625c39d4e) --- boot/zephyr/nrf_cleanup.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index c1cc1c290..c4f7426ee 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -4,7 +4,9 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ +#if !defined(CONFIG_SOC_SERIES_NRF54HX) #include +#endif #include #include #if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) @@ -62,10 +64,12 @@ static NRF_UARTE_Type *nrf_uarte_to_clean[] = { }; #endif +#if !defined(CONFIG_SOC_SERIES_NRF54HX) static void nrf_cleanup_clock(void) { nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); } +#endif void nrf_cleanup_peripheral(void) { @@ -109,5 +113,8 @@ void nrf_cleanup_peripheral(void) #if defined(NRF_DPPIC) nrf_dppi_channels_disable_all(NRF_DPPIC); #endif + +#if !defined(CONFIG_SOC_SERIES_NRF54HX) nrf_cleanup_clock(); +#endif } From a9a32d2951a1366b35bfc36aebf3fea0cfd952fd Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Tue, 5 Mar 2024 18:44:13 +0100 Subject: [PATCH 127/149] [nrf noup] boot/zephyr/nrf_cleanup: cleanup uarte pins Added procedure which does configure UARTE pins to the default states. This allows to reduce power consumption if pin is floating. clean-up UARTE only if its driver was enabled Signed-off-by: Andrzej Puzdrowski (cherry picked from commit fac7ac4990fe9f28348bfb3e0e52ac4bf51c757a) (cherry picked from commit a9918fab45fb9fd0a0ee705ffbc20037152696f6) --- boot/zephyr/nrf_cleanup.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index c4f7426ee..5958cf1e1 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -9,6 +9,7 @@ #endif #include #include +#include #if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) #include #endif @@ -96,6 +97,21 @@ void nrf_cleanup_peripheral(void) nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_RXTO); nrfy_uarte_disable(current); + uint32_t pin[4]; + + pin[0] = nrfy_uarte_tx_pin_get(current); + pin[1] = nrfy_uarte_rx_pin_get(current); + pin[2] = nrfy_uarte_rts_pin_get(current); + pin[3] = nrfy_uarte_cts_pin_get(current); + + nrfy_uarte_pins_disconnect(current); + + for (int j = 0; j < 4; j++) { + if (pin[j] != NRF_UARTE_PSEL_DISCONNECTED) { + nrfy_gpio_cfg_default(pin[j]); + } + } + #if defined(NRF_DPPIC) /* Clear all SUBSCRIBE configurations. */ memset((uint8_t *)current + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, From e45283bd0ac3fc6c2407acaf7e912fa41100830e Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Fri, 11 Apr 2025 12:55:00 +0200 Subject: [PATCH 128/149] [nrf noup] nrf_cleanup: nRF54l: disable cleanup on UARTE pins Compile out code which does cleanup on UARTE pins as this cause issues on for some applications. ref.: NCSDK-33039 Signed-off-by: Andrzej Puzdrowski (cherry picked from commit 5f6e119a726d9f17b3f65139540db838f2286bde) (cherry picked from commit 5b586d4920f22e1eb28e661694a7d322e749500d) --- boot/zephyr/nrf_cleanup.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index 5958cf1e1..d9cd751c3 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -97,6 +97,12 @@ void nrf_cleanup_peripheral(void) nrfy_uarte_event_clear(current, NRF_UARTE_EVENT_RXTO); nrfy_uarte_disable(current); +#ifndef CONFIG_SOC_SERIES_NRF54LX + /* Disconnect pins UARTE pins + * causes issues on nRF54l SoCs, + * could be enabled once fix to NCSDK-33039 will be implemented. + */ + uint32_t pin[4]; pin[0] = nrfy_uarte_tx_pin_get(current); @@ -111,6 +117,7 @@ void nrf_cleanup_peripheral(void) nrfy_gpio_cfg_default(pin[j]); } } +#endif #if defined(NRF_DPPIC) /* Clear all SUBSCRIBE configurations. */ From 2059cdf6abef78a0ff22b9367aecaa9617f154af Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Mon, 28 Apr 2025 14:17:35 +0200 Subject: [PATCH 129/149] [nrf noup] nrf_cleanup: nRF54h: fix missing peripheral cleanup This commit adds cleanup for GRTC and UARTE peripherals. ref: NCSDK-32966 Signed-off-by: Artur Hadasz (cherry picked from commit b6c992e20c51fd77c1761450aaae118fee3f097d) (cherry picked from commit 4509cebd992d40f7636a518cc7af3e67562b31b0) --- boot/zephyr/nrf_cleanup.c | 49 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index d9cd751c3..c1e5a178e 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ -#if !defined(CONFIG_SOC_SERIES_NRF54HX) +#if defined(CONFIG_NRFX_CLOCK) #include #endif #include @@ -13,6 +13,9 @@ #if defined(NRF_RTC0) || defined(NRF_RTC1) || defined(NRF_RTC2) #include #endif +#if defined(CONFIG_NRF_GRTC_TIMER) + #include +#endif #if defined(NRF_PPI) #include #endif @@ -48,6 +51,39 @@ static inline void nrf_cleanup_rtc(NRF_RTC_Type * rtc_reg) } #endif +#if defined(CONFIG_NRF_GRTC_TIMER) + +/** + * This function is temporary and should be removed once nrfx_grtc_uninit + * no longer resets the counter - see NRFX-8487. + */ +static inline void nrfx_grtc_uninit_no_counter_reset(void) +{ + uint32_t ch_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; + +#if NRF_GRTC_HAS_RTCOUNTER + uint32_t grtc_all_int_mask = (NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK | + GRTC_NON_SYSCOMPARE_INT_MASK); +#else + uint32_t grtc_all_int_mask = NRFX_GRTC_CONFIG_ALLOWED_CC_CHANNELS_MASK; +#endif + + nrfy_grtc_int_disable(NRF_GRTC, grtc_all_int_mask); + + for (uint8_t chan = 0; ch_mask; chan++, ch_mask >>= 1) + { + nrfx_grtc_syscounter_cc_disable(chan); + nrfx_grtc_channel_free(chan); + } + nrfy_grtc_int_uninit(NRF_GRTC); +} + +static inline void nrf_cleanup_grtc(void) +{ + nrfx_grtc_uninit_no_counter_reset(); +} +#endif + #if defined(NRF_UARTE_CLEANUP) static NRF_UARTE_Type *nrf_uarte_to_clean[] = { #if defined(NRF_UARTE0) @@ -62,10 +98,13 @@ static NRF_UARTE_Type *nrf_uarte_to_clean[] = { #if defined(NRF_UARTE30) NRF_UARTE30, #endif +#if defined(NRF_UARTE136) + NRF_UARTE136, +#endif }; #endif -#if !defined(CONFIG_SOC_SERIES_NRF54HX) +#if defined(CONFIG_NRFX_CLOCK) static void nrf_cleanup_clock(void) { nrf_clock_int_disable(NRF_CLOCK, 0xFFFFFFFF); @@ -84,6 +123,10 @@ void nrf_cleanup_peripheral(void) nrf_cleanup_rtc(NRF_RTC2); #endif +#if defined(CONFIG_NRF_GRTC_TIMER) + nrf_cleanup_grtc(); +#endif + #if defined(NRF_UARTE_CLEANUP) for (int i = 0; i < sizeof(nrf_uarte_to_clean) / sizeof(nrf_uarte_to_clean[0]); ++i) { NRF_UARTE_Type *current = nrf_uarte_to_clean[i]; @@ -137,7 +180,7 @@ void nrf_cleanup_peripheral(void) nrf_dppi_channels_disable_all(NRF_DPPIC); #endif -#if !defined(CONFIG_SOC_SERIES_NRF54HX) +#if defined(CONFIG_NRFX_CLOCK) nrf_cleanup_clock(); #endif } From 217e9b04c1664d8cb95ca2a624ca2104fbbd1e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Szczygie=C5=82?= Date: Tue, 8 Jul 2025 09:05:18 +0200 Subject: [PATCH 130/149] [nrf noup] boot: Add retry for image verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Intended mainly for direct-xip mode. Allows to control: - number of image validation attempts performed before considering the image invalid - time before next attempt is made Signed-off-by: Adam SzczygieÅ‚ Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 25346815646625708b3269c46fe45089885da551) (cherry picked from commit a9e70e43fa548c86bec946dc06210b8a2ba2b860) (cherry picked from commit d29c5a5bee2f14560e0d5f2be9f2045ef206aaa4) --- boot/bootutil/src/bootutil_loader.c | 36 +++++++++++++++++++++++++++-- boot/zephyr/Kconfig | 17 ++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/bootutil_loader.c b/boot/bootutil/src/bootutil_loader.c index 0cc543944..829e3833a 100644 --- a/boot/bootutil/src/bootutil_loader.c +++ b/boot/bootutil/src/bootutil_loader.c @@ -47,6 +47,10 @@ #endif #include "bootutil/bootutil_log.h" +#if defined(CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) +#include +#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ + BOOT_LOG_MODULE_DECLARE(mcuboot); bool @@ -199,8 +203,36 @@ boot_check_image(struct boot_loader_state *state, struct boot_status *bs, int sl } #endif - FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, - NULL, 0, NULL); + for (int i = 1; i <= CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT; i++ ) { +#if CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + BOOT_LOG_DBG("Image validation attempt %d/%d", i, CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT); +#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ + + FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, + NULL, 0, NULL); + if (FIH_EQ(fih_rc, FIH_SUCCESS)) { +#if CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + BOOT_LOG_DBG("Image validation attempt %d/%d success", i, CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT); +#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ + break; + } else { +#if CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + BOOT_LOG_WRN("Image validation attempt %d/%d failure: %d", + i, + CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT, fih_rc); +#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ + + if (i < CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT) { +#if defined(CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) +#if CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + BOOT_LOG_DBG("Waiting %d ms before next attempt", + CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS); +#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 */ + k_busy_wait(CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS * 1000); +#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ + } + } + } FIH_RET(fih_rc); } diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 4c0024b1e..2fdc13262 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1369,4 +1369,21 @@ config MCUBOOT_VERIFY_IMG_ADDRESS also be useful when BOOT_DIRECT_XIP is enabled, to ensure that the image linked at the correct address is loaded. +config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT + int "Number of image validation attempts" + default 1 + help + Number of image validation attempts performed before an image is considered invalid. + A wait is done between each attempt to allow for recovery from a temporary disruption. + This can prevent erasing an image when initial validation fails. + Wait time is controlled by MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS. + +config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS + int "Time between image validation attempts" + depends on NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + default 5000 + help + Time between image validation attempts, in milliseconds. + Allows for recovery from transient bit flips or similar situations. + source "Kconfig.zephyr" From bd8a6ab5b54e596c8178157063df395d2bf2121c Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Tue, 5 Aug 2025 15:55:31 +0200 Subject: [PATCH 131/149] [nrf noup] boot: zephyr: Disable self RWX Disables read write and execute on mcuboots NVM at the end of execution. Signed-off-by: Mateusz Michalek (cherry picked from commit 285fd59f4386a0317e476da5484f67b906073296) (cherry picked from commit 211da1bf19b4dc5b8078ffbc143f02caca88bb9f) --- boot/zephyr/Kconfig | 13 +++ boot/zephyr/main.c | 197 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 167 insertions(+), 43 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 2fdc13262..6d334abce 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -436,6 +436,19 @@ config MCUBOOT_CLEANUP_RAM help Sets contents of memory to 0 before jumping to application. +config NCS_MCUBOOT_DISABLE_SELF_RWX_SUPPORTED + bool + default y if SOC_NRF54L15_CPUAPP || SOC_NRF54L10_CPUAPP || SOC_NRF54L05_CPUAPP + default y if SOC_NRF54LV10A_ENGA_CPUAPP + default y if SOC_NRF54LM20A_ENGA_CPUAPP + +config NCS_MCUBOOT_DISABLE_SELF_RWX + bool "Disable read and execution on self NVM" + depends on NCS_MCUBOOT_DISABLE_SELF_RWX_SUPPORTED && !FPROTECT + help + Sets RRAMC's region no.4 protection before jumping to application. + It disables reads writes and execution memory area which holds MCUBOOT. + config MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP bool "Infinite loop after RAM cleanup" depends on MCUBOOT_CLEANUP_RAM diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 8b39963a9..8a423eb4c 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -144,15 +144,76 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); * !defined(CONFIG_LOG_MODE_MINIMAL) */ +#if USE_PARTITION_MANAGER +#include +#endif + #if USE_PARTITION_MANAGER && CONFIG_FPROTECT #include -#include #endif #if CONFIG_MCUBOOT_NRF_CLEANUP_PERIPHERAL #include #endif +#include +#define CLEANUP_RAM_GAP_START ((int)__ramfunc_region_start) +#define CLEANUP_RAM_GAP_SIZE ((int) (__ramfunc_end - __ramfunc_region_start)) + +#if defined(CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX) +/* Disabling R_X has to be done while running from RAM for obvious reasons. + * Moreover as a last step before jumping to application it must work even after + * RAM has been cleared, therefore these operations are performed while executing from RAM. + * RAM cleanup ommits portion of the memory where code lives. + */ +#include + +#define RRAMC_REGION_RWX_LSB 0 +#define RRAMC_REGION_RWX_WIDTH 3 + +#define RRAMC_REGION_NUMBER 4 +#define NRF_RRAM_REGION_SIZE_UNIT 0x400 +#define NRF_RRAM_REGION_ADDRESS_RESOLUTION 0x400 + +#if defined(CONFIG_SOC_NRF54L15_CPUAPP) || defined(CONFIG_SOC_NRF54L05_CPUAPP) || \ + defined(CONFIG_SOC_NRF54L10_CPUAPP) +#define MAX_PROTECTED_REGION_SIZE (31 * 1024) +#elif defined(CONFIG_SOC_NRF54LV10A_ENGA_CPUAPP) || defined(CONFIG_SOC_NRF54LM20A_ENGA_CPUAPP) +#define MAX_PROTECTED_REGION_SIZE (127 * 1024) +#elif defined(CONFIG_SOC_NRF54LS05B_ENGA_CPUAPP) +#define MAX_PROTECTED_REGION_SIZE (1023 * 1024) +#endif + +#define RRAMC_REGION_CONFIG NRF_RRAMC->REGION[RRAMC_REGION_NUMBER].CONFIG +#define RRAMC_REGION_CONFIG_H (((uint32_t)(&(RRAMC_REGION_CONFIG))) >> 16) +#define RRAMC_REGION_CONFIG_L (((uint32_t)(&(RRAMC_REGION_CONFIG))) & 0x0000fffful) + +#define RRAMC_REGION_ADDRESS NRF_RRAMC->REGION[RRAMC_REGION_NUMBER].ADDRESS +#define RRAMC_REGION_ADDRESS_H (((uint32_t)(&(RRAMC_REGION_ADDRESS))) >> 16) +#define RRAMC_REGION_ADDRESS_L (((uint32_t)(&(RRAMC_REGION_ADDRESS))) & 0x0000fffful) + +#if (CONFIG_NCS_IS_VARIANT_IMAGE) +#define PROTECTED_REGION_START PM_S1_IMAGE_ADDRESS +#define PROTECTED_REGION_SIZE PM_S1_IMAGE_SIZE +#else +#define PROTECTED_REGION_START PM_MCUBOOT_ADDRESS +#define PROTECTED_REGION_SIZE PM_MCUBOOT_SIZE +#endif + +BUILD_ASSERT((PROTECTED_REGION_START % NRF_RRAM_REGION_ADDRESS_RESOLUTION) == 0, + "Start of protected region is not aligned - not possible to protect"); + +BUILD_ASSERT((PROTECTED_REGION_SIZE % NRF_RRAM_REGION_SIZE_UNIT) == 0, + "Size of protected region is not aligned - not possible to protect"); + +BUILD_ASSERT(PROTECTED_REGION_SIZE <= MAX_PROTECTED_REGION_SIZE, + "Size of protected region is too big for protection"); + +#define PROTECTED_REGION_START_H ((PROTECTED_REGION_START) >> 16) +#define PROTECTED_REGION_START_L ((PROTECTED_REGION_START) & 0x0000fffful) + +#endif /* CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX */ + BOOT_LOG_MODULE_REGISTER(mcuboot); void os_heap_init(void); @@ -179,6 +240,97 @@ struct arm_vector_table { #endif }; +static void __ramfunc jump_in(uint32_t reset) +{ + __asm__ volatile ( + /* reset -> r0 */ + " mov r0, %0\n" +#ifdef CONFIG_MCUBOOT_CLEANUP_RAM + /* Base to write -> r1 */ + " mov r1, %1\n" + /* Size to write -> r2 */ + " mov r2, %2\n" + /* Value to write -> r3 */ + " movw r3, %5\n" + /* gap start */ + " mov r4, %3\n" + /* gap size */ + " mov r5, %4\n" + "clear:\n" + " subs r6, r4, r1\n" + " cbnz r6, skip_gap\n" + " add r1, r5\n" + "skip_gap:\n" + " str r3, [r1]\n" + " add r1, r1, #1\n" + " sub r2, r2, #1\n" + " cbz r2, clear_end\n" + " b clear\n" + "clear_end:\n" + " dsb\n" +#ifdef CONFIG_MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP + " b clear_end\n" +#endif /* CONFIG_MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP */ +#endif /* CONFIG_MCUBOOT_CLEANUP_RAM */ + +#ifdef CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX + ".thumb_func\n" + "region_disable_rwx:\n" + " movw r1, %6\n" + " movt r1, %7\n" + " ldr r2, [r1]\n" + /* Size of the region should be set at this point + * by NSIB's DISABLE_NEXT_W. + * If not, the region has not been configured yet. + * Set the size and address to the partition size and address. + */ + " ands r4, r2, %12\n" + " cbnz r4, clear_rwx\n" + /* Set the size of the protected region */ + " movt r2, %8\n" + /* Set the address of the protected region */ + " movw r5, %13\n" + " movt r5, %14\n" + " movw r6, %15\n" + " movt r6, %16\n" + " str r6, [r5]\n" + " dsb\n" + "clear_rwx:\n" + " bfc r2, %9, %10\n" + /* Disallow further modifications */ + " orr r2, %11\n" + " str r2, [r1]\n" + " dsb\n" + /* Next assembly line is important for current function */ + + #endif /* CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX */ + + /* Jump to reset vector of an app */ + " bx r0\n" + : + : "r" (reset), + "r" (CONFIG_SRAM_BASE_ADDRESS), + "i" (CONFIG_SRAM_SIZE * 1024), + "r" (CLEANUP_RAM_GAP_START), + "r" (CLEANUP_RAM_GAP_SIZE), + "i" (0) +#ifdef CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX + , "i" (RRAMC_REGION_CONFIG_L), + "i" (RRAMC_REGION_CONFIG_H), + "i" ((PROTECTED_REGION_SIZE) / (NRF_RRAM_REGION_SIZE_UNIT)), + "i" (RRAMC_REGION_RWX_LSB), + "i" (RRAMC_REGION_RWX_WIDTH), + "i" (RRAMC_REGION_CONFIG_LOCK_Msk), + "i" (RRAMC_REGION_CONFIG_SIZE_Msk), + "i" (RRAMC_REGION_ADDRESS_L), + "i" (RRAMC_REGION_ADDRESS_H), + "i" (PROTECTED_REGION_START_L), + "i" (PROTECTED_REGION_START_H) +#endif /* CONFIG_NCS_MCUBOOT_DISABLE_SELF_RWX */ + : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "memory" + ); +} + static void do_boot(struct boot_rsp *rsp) { /* vt is static as it shall not land on the stack, @@ -310,48 +462,7 @@ static void do_boot(struct boot_rsp *rsp) #endif /* CONFIG_CPU_CORTEX_M */ #endif -#if CONFIG_MCUBOOT_CLEANUP_RAM - __asm__ volatile ( - /* vt->reset -> r0 */ - " mov r0, %0\n" - /* base to write -> r1 */ - " mov r1, %1\n" - /* size to write -> r2 */ - " mov r2, %2\n" - /* value to write -> r3 */ - " mov r3, %3\n" - "clear:\n" - " str r3, [r1]\n" - " add r1, r1, #4\n" - " sub r2, r2, #4\n" - " cbz r2, out\n" - " b clear\n" - "out:\n" - " dsb\n" -#if CONFIG_MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP - " b out\n" -#endif /*CONFIG_MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP */ - /* jump to reset vector of an app */ - " bx r0\n" - : - : "r" (vt->reset), "i" (CONFIG_SRAM_BASE_ADDRESS), - "i" (CONFIG_SRAM_SIZE * 1024), "i" (0) - : "r0", "r1", "r2", "r3", "memory" - ); -#else - -#ifdef CONFIG_CPU_CORTEX_M - ((void (*)(void))vt->reset)(); -#else - /* Some ARM CPUs like the Cortex-R5 can run in thumb mode but reset into ARM - * mode (depending on a CPU signal configurations). To do the switch into ARM - * mode, if needed, an explicit branch with exchange instruction set - * instruction is needed - */ - __asm__("bx %0\n" : : "r" (&vt->reset)); -#endif - -#endif + jump_in(vt->reset); } #elif defined(CONFIG_XTENSA) || defined(CONFIG_RISCV) From 257552098617f42cf37f5a946843e2a3523b6316 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Mon, 28 Jul 2025 12:46:20 +0200 Subject: [PATCH 132/149] [nrf noup] bootloader: Add bootloader requests Add a capability inside the Zephyr bootloader to handle memory-based bootloader requests to: - Boot recovery firmware - Boot firmware loader - Confirm an image - Set the slot preference Ref: NCSDK-34429 Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 09ce751132d4a7b48ec110c3f8ea2e6256601731) (cherry picked from commit cc558efbb2e06ef1a195a3a0e3e83ecd182c8946) --- boot/bootutil/include/bootutil/boot_request.h | 106 ++++++ boot/bootutil/src/bootutil_public.c | 95 ++++- boot/bootutil/zephyr/CMakeLists.txt | 5 + .../zephyr/src/boot_request_retention.c | 346 ++++++++++++++++++ boot/zephyr/Kconfig | 15 + boot/zephyr/Kconfig.firmware_loader | 6 + boot/zephyr/Kconfig.serial_recovery | 6 + boot/zephyr/firmware_loader.c | 9 + boot/zephyr/main.c | 53 +++ 9 files changed, 636 insertions(+), 5 deletions(-) create mode 100644 boot/bootutil/include/bootutil/boot_request.h create mode 100644 boot/bootutil/zephyr/src/boot_request_retention.c diff --git a/boot/bootutil/include/bootutil/boot_request.h b/boot/bootutil/include/bootutil/boot_request.h new file mode 100644 index 000000000..c92a91d4e --- /dev/null +++ b/boot/bootutil/include/bootutil/boot_request.h @@ -0,0 +1,106 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Nordic Semiconductor ASA + */ + +#ifndef __BOOT_REQUEST_H__ +#define __BOOT_REQUEST_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/** Special value, indicating that there is no preferred slot. */ +#define BOOT_REQUEST_NO_PREFERRED_SLOT UINT32_MAX + +/** + * @brief Request a bootloader to confirm the specified slot of an image. + * + * @param[in] image Image number. + * @param[in] slot Slot number. + * + * @return 0 if requested, negative error code otherwise. + */ +int boot_request_confirm_slot(uint8_t image, enum boot_slot slot); + +/** + * @brief Request a bootloader to boot the specified slot of an image. + * + * @param[in] image Image number. + * @param[in] slot Slot number. + * + * @return 0 if requested, negative error code otherwise. + */ +int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot); + +/** + * @brief Request a bootloader to boot recovery image. + * + * @return 0 if requested, negative error code otherwise. + */ +int boot_request_enter_recovery(void); + +/** + * @brief Request a bootloader to boot firmware loader image. + * + * @return 0 if requested, negative error code otherwise. + */ +int boot_request_enter_firmware_loader(void); + +/** + * @brief Check if there is a request to confirm the specified slot of an image. + * + * @param[in] image Image number. + * @param[in] slot Slot number. + * + * @return true if requested, false otherwise. + */ +bool boot_request_check_confirmed_slot(uint8_t image, enum boot_slot slot); + +/** + * @brief Find if there is a request to boot certain slot of the specified image. + * + * @param[in] image Image number. + * + * @return slot number if requested, BOOT_SLOT_NONE otherwise. + */ +enum boot_slot boot_request_get_preferred_slot(uint8_t image); + +/** + * @brief Check if there is a request to boot recovery image. + * + * @return true if requested, false otherwise. + */ +bool boot_request_detect_recovery(void); + +/** + * @brief Check if there is a request to boot firmware loader image. + * + * @return true if requested, false otherwise. + */ +bool boot_request_detect_firmware_loader(void); + +/** + * @brief Initialize boot requests module. + * + * @return 0 if successful, negative error code otherwise. + */ +int boot_request_init(void); + +/** + * @brief Clear/drop all requests. + * + * @return 0 if successful, negative error code otherwise. + */ +int boot_request_clear(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __BOOT_REQUEST_H__ */ diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index 5071b561a..f54dd6151 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -51,6 +51,11 @@ #include "bootutil_priv.h" #include "bootutil_misc.h" +#if defined(CONFIG_NRF_MCUBOOT_BOOT_REQUEST) && !defined(CONFIG_MCUBOOT) +#include +#define SEND_BOOT_REQUEST +#endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST && !CONFIG_MCUBOOT */ + #ifdef CONFIG_MCUBOOT BOOT_LOG_MODULE_DECLARE(mcuboot); #else @@ -503,16 +508,56 @@ boot_write_copy_done(const struct flash_area *fap) return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET); } -#ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP +#ifdef SEND_BOOT_REQUEST +static int +send_boot_request(uint8_t magic, uint8_t image_ok, bool confirm, int image_id, + enum boot_slot slot_id) +{ + int rc = BOOT_EBADIMAGE; + + /* Handle write-protected active image. */ + if ((magic == BOOT_MAGIC_GOOD) || (magic == BOOT_MAGIC_UNSET)) { + if (confirm) { + BOOT_LOG_DBG("Confirm image: %d, %d", image_id, slot_id); + if ((image_ok != BOOT_FLAG_SET) || (magic != BOOT_MAGIC_GOOD)) { + rc = boot_request_confirm_slot(image_id, slot_id); + } else { + rc = 0; + } + } else { +#ifdef CONFIG_NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE + BOOT_LOG_DBG("Set image preference: %d, %d", image_id, slot_id); + rc = boot_request_set_preferred_slot(image_id, slot_id); +#else + rc = 0; +#endif /* CONFIG_NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE */ + } + if (rc != 0) { + rc = BOOT_EBADIMAGE; + } + } + + return rc; +} +#endif /* SEND_BOOT_REQUEST */ -static int flash_area_to_image(const struct flash_area *fa) +#if defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) +static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) { + int id = flash_area_get_id(fa); #if BOOT_IMAGE_NUMBER > 1 uint8_t i = 0; - int id = flash_area_get_id(fa); while (i < BOOT_IMAGE_NUMBER) { - if (FLASH_AREA_IMAGE_PRIMARY(i) == id || (FLASH_AREA_IMAGE_SECONDARY(i) == id)) { + if (FLASH_AREA_IMAGE_PRIMARY(i) == id) { + if (slot != NULL) { + *slot = 0; + } + return i; + } else if (FLASH_AREA_IMAGE_SECONDARY(i) == id) { + if (slot != NULL) { + *slot = 1; + } return i; } @@ -523,15 +568,31 @@ static int flash_area_to_image(const struct flash_area *fa) *slot = UINT32_MAX; #else (void)fa; + if (slot != NULL) { + if (FLASH_AREA_IMAGE_PRIMARY(0) == id) { + *slot = 0; + } else if (FLASH_AREA_IMAGE_SECONDARY(0) == id) { + *slot = 1; + } else { + *slot = UINT32_MAX; + } + } #endif return 0; } +#endif /* defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) */ +#ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP int boot_set_next(const struct flash_area *fa, bool active, bool confirm) { struct boot_swap_state slot_state; int rc; + int image_id; + uint32_t slot_id; + + BOOT_LOG_DBG("boot_set_next: fa %p active == %d, confirm == %d", + fa, (int)active, (int)confirm); if (active) { confirm = true; @@ -542,6 +603,16 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) return rc; } + image_id = flash_area_to_image_slot(fa, &slot_id); + +#ifdef SEND_BOOT_REQUEST + rc = send_boot_request(slot_state.magic, slot_state.image_ok, confirm, + image_id, slot_id); + if ((rc != 0) || active) { + return rc; + } +#endif + switch (slot_state.magic) { case BOOT_MAGIC_GOOD: /* If non-active then swap already scheduled, else confirm needed.*/ @@ -572,7 +643,7 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) } else { swap_type = BOOT_SWAP_TYPE_TEST; } - rc = boot_write_swap_info(fa, swap_type, flash_area_to_image(fa)); + rc = boot_write_swap_info(fa, swap_type, image_id); } } break; @@ -600,6 +671,10 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) { struct boot_swap_state slot_state; int rc; +#ifdef SEND_BOOT_REQUEST + int image_id; + uint32_t slot_id; +#endif BOOT_LOG_DBG("boot_set_next: fa %p active == %d, confirm == %d", fa, (int)active, (int)confirm); @@ -618,6 +693,16 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) return rc; } +#ifdef SEND_BOOT_REQUEST + image_id = flash_area_to_image_slot(fa, &slot_id); + + rc = send_boot_request(slot_state.magic, slot_state.image_ok, confirm, + image_id, slot_id); + if ((rc != 0) || active) { + return rc; + } +#endif + switch (slot_state.magic) { case BOOT_MAGIC_UNSET: /* Magic is needed for MCUboot to even consider booting an image */ diff --git a/boot/bootutil/zephyr/CMakeLists.txt b/boot/bootutil/zephyr/CMakeLists.txt index 44f78f395..111cf4f1d 100644 --- a/boot/bootutil/zephyr/CMakeLists.txt +++ b/boot/bootutil/zephyr/CMakeLists.txt @@ -16,6 +16,11 @@ zephyr_library_named(mcuboot_util) zephyr_library_sources( ../src/bootutil_public.c ) +if(CONFIG_NRF_MCUBOOT_BOOT_REQUEST) + zephyr_library_sources_ifdef(CONFIG_NRF_MCUBOOT_BOOT_REQUEST_IMPL_RETENTION + src/boot_request_retention.c + ) +endif() # Sensitivity to the TEST_BOOT_IMAGE_ACCESS_HOOKS define is implemented for # allowing the test-build with the hooks feature enabled. diff --git a/boot/bootutil/zephyr/src/boot_request_retention.c b/boot/bootutil/zephyr/src/boot_request_retention.c new file mode 100644 index 000000000..e7fc393a0 --- /dev/null +++ b/boot/bootutil/zephyr/src/boot_request_retention.c @@ -0,0 +1,346 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Nordic Semiconductor ASA + */ +#include + +#include "bootutil/bootutil_log.h" +#include + +/** Special value of image number, indicating a request to the bootloader. */ +#define BOOT_REQUEST_IMG_BOOTLOADER 0xFF + +/** Additional memory used by the retention subsystem (2B - prefix, 4B - CRC).*/ +#define BOOT_REQUEST_ENTRY_METADATA_SIZE (2 + 4) + +BOOT_LOG_MODULE_REGISTER(bootloader_request); + +static const struct device *bootloader_request_dev = + DEVICE_DT_GET(DT_CHOSEN(nrf_bootloader_request)); + +enum boot_request_type { + /** Invalid request. */ + BOOT_REQUEST_INVALID = 0, + + /** Request a change in the bootloader boot mode. + * + * @details Use @p boot_request_mode as argument. + * @p BOOT_REQUEST_IMG_BOOTLOADER as image number. + * + * @note Used to trigger recovery through i.e. retention sybsystem. + */ + BOOT_REQUEST_BOOT_MODE = 1, + + /** Select the preferred image to be selected during boot or update. + * + * @details Use @p boot_request_slot_t as argument. + * + * @note Used in the Direct XIP mode. + */ + BOOT_REQUEST_IMG_PREFERENCE = 2, + + /** Request a confirmation of an image. + * + * @details Use @p boot_request_slot_t as argument. + * + * @note Used if the code cannot modify the image trailer directly. + */ + BOOT_REQUEST_IMG_CONFIRM = 3, +}; + +/* Entries inside the boot request shared memory. */ +enum boot_request_entry { + BOOT_REQUEST_ENTRY_BOOT_MODE = 0, + BOOT_REQUEST_ENTRY_IMAGE_0_PREFERENCE = 1, + BOOT_REQUEST_ENTRY_IMAGE_0_CONFIRM = 2, + BOOT_REQUEST_ENTRY_IMAGE_1_PREFERENCE = 3, + BOOT_REQUEST_ENTRY_IMAGE_1_CONFIRM = 4, + BOOT_REQUEST_ENTRY_MAX = 5, +}; + +/* Assert that all requests will fit within the retention area. */ +BUILD_ASSERT((BOOT_REQUEST_ENTRY_METADATA_SIZE + BOOT_REQUEST_ENTRY_MAX * sizeof(uint8_t)) < + DT_REG_SIZE_BY_IDX(DT_CHOSEN(nrf_bootloader_request), 0), + "nrf,bootloader-request area is too small for bootloader request struct"); + +enum boot_request_slot { + /** Unsupported value. */ + BOOT_REQUEST_SLOT_INVALID = 0, + /** Primary slot. */ + BOOT_REQUEST_SLOT_PRIMARY = 1, + /** Secondary slot. */ + BOOT_REQUEST_SLOT_SECONDARY = 2, +}; + +/** Alias type for the image and number. */ +typedef uint8_t boot_request_slot_t; + +enum boot_request_mode { + /** Execute a regular boot logic. */ + BOOT_REQUEST_MODE_REGULAR = 0, + /** Execute the recovery boot logic. */ + BOOT_REQUEST_MODE_RECOVERY = 1, + /** Execute the firmware loader logic. */ + BOOT_REQUEST_MODE_FIRMWARE_LOADER = 2, + /** Unsupported value. */ + BOOT_REQUEST_MODE_INVALID = 0xFF, +}; + +/** Alias type for the image number. */ +typedef uint8_t boot_request_img_t; + +/** + * @brief Find an entry for a given request. + * + * @param[in] type Type of request. + * @param[in] image Image number. Use @p BOOT_REQUEST_IMG_BOOTLOADER for generic requests. + * @param[out] entry Entry to use. + * + * @return 0 on success; nonzero on failure. + */ +static int boot_request_entry_find(enum boot_request_type type, boot_request_img_t image, + size_t *entry) +{ + if (entry == NULL) { + return -EINVAL; + } + + switch (type) { + case BOOT_REQUEST_BOOT_MODE: + *entry = BOOT_REQUEST_ENTRY_BOOT_MODE; + break; + case BOOT_REQUEST_IMG_PREFERENCE: + switch (image) { + case 0: + *entry = BOOT_REQUEST_ENTRY_IMAGE_0_PREFERENCE; + break; + case 1: + *entry = BOOT_REQUEST_ENTRY_IMAGE_1_PREFERENCE; + break; + default: + return -EINVAL; + } + break; + case BOOT_REQUEST_IMG_CONFIRM: + switch (image) { + case 0: + *entry = BOOT_REQUEST_ENTRY_IMAGE_0_CONFIRM; + break; + case 1: + *entry = BOOT_REQUEST_ENTRY_IMAGE_1_CONFIRM; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +int boot_request_init(void) +{ + if (!device_is_ready(bootloader_request_dev)) { + return -EIO; + } + + return 0; +} + +int boot_request_clear(void) +{ + return retention_clear(bootloader_request_dev); +} + +int boot_request_confirm_slot(uint8_t image, enum boot_slot slot) +{ + uint8_t value = BOOT_REQUEST_SLOT_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry); + if (ret != 0) { + return ret; + } + + switch (slot) { + case BOOT_SLOT_PRIMARY: + value = BOOT_REQUEST_SLOT_PRIMARY; + break; + case BOOT_SLOT_SECONDARY: + value = BOOT_REQUEST_SLOT_SECONDARY; + break; + default: + return -EINVAL; + } + + return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); +} + +bool boot_request_check_confirmed_slot(uint8_t image, enum boot_slot slot) +{ + uint8_t value = BOOT_REQUEST_SLOT_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_IMG_CONFIRM, image, &req_entry); + if (ret != 0) { + return false; + } + + ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); + if (ret != 0) { + return false; + } + + switch (value) { + case BOOT_REQUEST_SLOT_PRIMARY: + return (slot == BOOT_SLOT_PRIMARY); + case BOOT_REQUEST_SLOT_SECONDARY: + return (slot == BOOT_SLOT_SECONDARY); + default: + break; + } + + return false; +} + +int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot) +{ + uint8_t value = BOOT_REQUEST_SLOT_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry); + if (ret != 0) { + return ret; + } + + switch (slot) { + case BOOT_SLOT_PRIMARY: + value = BOOT_REQUEST_SLOT_PRIMARY; + break; + case BOOT_SLOT_SECONDARY: + value = BOOT_REQUEST_SLOT_SECONDARY; + break; + default: + return -EINVAL; + } + + return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); +} + +#ifdef CONFIG_FIND_NEXT_SLOT_HOOKS +enum boot_slot boot_request_get_preferred_slot(uint8_t image) +{ + uint8_t value = BOOT_REQUEST_SLOT_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_IMG_PREFERENCE, image, &req_entry); + if (ret != 0) { + return BOOT_SLOT_NONE; + } + + ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); + if (ret != 0) { + return BOOT_SLOT_NONE; + } + + switch (value) { + case BOOT_REQUEST_SLOT_PRIMARY: + return BOOT_SLOT_PRIMARY; + case BOOT_REQUEST_SLOT_SECONDARY: + return BOOT_SLOT_SECONDARY; + default: + break; + } + + return BOOT_SLOT_NONE; +} +#endif /* CONFIG_FIND_NEXT_SLOT_HOOKS */ + +int boot_request_enter_recovery(void) +{ + uint8_t value = BOOT_REQUEST_MODE_RECOVERY; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, + &req_entry); + if (ret != 0) { + return ret; + } + + return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); +} + +#ifdef CONFIG_NRF_BOOT_SERIAL_BOOT_REQ +bool boot_request_detect_recovery(void) +{ + uint8_t value = BOOT_REQUEST_MODE_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, + &req_entry); + if (ret != 0) { + return false; + } + + ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); + if ((ret == 0) && (value == BOOT_REQUEST_MODE_RECOVERY)) { + return true; + } + + return false; +} +#endif /* CONFIG_NRF_BOOT_SERIAL_BOOT_REQ */ + +int boot_request_enter_firmware_loader(void) +{ + uint8_t value = BOOT_REQUEST_MODE_FIRMWARE_LOADER; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, + &req_entry); + if (ret != 0) { + return ret; + } + + return retention_write(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); +} + +#ifdef CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ +bool boot_request_detect_firmware_loader(void) +{ + uint8_t value = BOOT_REQUEST_MODE_INVALID; + size_t req_entry; + int ret; + + ret = boot_request_entry_find(BOOT_REQUEST_BOOT_MODE, BOOT_REQUEST_IMG_BOOTLOADER, + &req_entry); + if (ret != 0) { + return false; + } + + ret = retention_read(bootloader_request_dev, req_entry * sizeof(value), (void *)&value, + sizeof(value)); + if ((ret == 0) && (value == BOOT_REQUEST_MODE_FIRMWARE_LOADER)) { + return true; + } + + return false; +} +#endif /* CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ */ diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 6d334abce..39ce565c8 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1361,6 +1361,10 @@ config MCUBOOT_CHECK_HEADER_LOAD_ADDRESS When not selected reset vector, read from image, is used for the same purpose. +config NRF_MCUBOOT_BOOT_REQUEST + bool + imply FIND_NEXT_SLOT_HOOKS if BOOT_DIRECT_XIP || BOOT_RAM_LOAD + config MCUBOOT_VERIFY_IMG_ADDRESS bool "Verify reset address of image in secondary slot [DEPRECATED]" select DEPRECATED @@ -1399,4 +1403,15 @@ config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS Time between image validation attempts, in milliseconds. Allows for recovery from transient bit flips or similar situations. +config NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE + bool "Set boot preference if a slot is marked for test" + help + This option allows to verify boot preference requests through issuing + the image test. + Using this option is not recommended in production systems, because + it will boot any newly transferred image, even if it has a lower + version than the current one. + The rollback protection (using security counters) will still be + effective. + source "Kconfig.zephyr" diff --git a/boot/zephyr/Kconfig.firmware_loader b/boot/zephyr/Kconfig.firmware_loader index 036da98eb..376dc06f7 100644 --- a/boot/zephyr/Kconfig.firmware_loader +++ b/boot/zephyr/Kconfig.firmware_loader @@ -42,6 +42,12 @@ config BOOT_FIRMWARE_LOADER_PIN_RESET Checks if the module reset was caused by the reset pin and will remain in bootloader firmware loader mode if it was. +config NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ + bool "Check boot mode via bootloader request" + depends on NRF_MCUBOOT_BOOT_REQUEST + help + Allows for entering firmware loader mode by using bootloader rquests. + endmenu endif diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery index 0bffe6131..c57e48197 100644 --- a/boot/zephyr/Kconfig.serial_recovery +++ b/boot/zephyr/Kconfig.serial_recovery @@ -192,6 +192,12 @@ config BOOT_SERIAL_PIN_RESET Checks if the module reset was caused by the reset pin and will remain in bootloader serial recovery mode if it was. +config NRF_BOOT_SERIAL_BOOT_REQ + bool "Check boot mode via bootloader request subsystem" + depends on NRF_MCUBOOT_BOOT_REQUEST + help + Allows for entering serial recovery mode by using bootloader requests. + endmenu config BOOT_SERIAL_IMG_GRP_HASH diff --git a/boot/zephyr/firmware_loader.c b/boot/zephyr/firmware_loader.c index 18070bc25..217336755 100644 --- a/boot/zephyr/firmware_loader.c +++ b/boot/zephyr/firmware_loader.c @@ -17,6 +17,9 @@ #include "io/io.h" #include "mcuboot_config/mcuboot_config.h" +#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST +#include +#endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST */ BOOT_LOG_MODULE_DECLARE(mcuboot); @@ -183,6 +186,12 @@ boot_go(struct boot_rsp *rsp) } #endif +#ifdef CONFIG_NRF_BOOT_FIRMWARE_LOADER_BOOT_REQ + if (boot_request_detect_firmware_loader()) { + boot_firmware_loader = true; + } +#endif + /* Check if firmware loader button is pressed. TODO: check all entrance methods */ if (boot_firmware_loader == true) { FIH_CALL(validate_image_slot, fih_rc, FLASH_AREA_IMAGE_SECONDARY(0), rsp); diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 8a423eb4c..93e00060a 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -47,6 +47,12 @@ #include "bootutil/fault_injection_hardening.h" #include "bootutil/mcuboot_status.h" #include "flash_map_backend/flash_map_backend.h" +#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST +#include + +/** Number of image slots. */ +#define BOOT_REQUEST_NUM_SLOTS 2 +#endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST */ #if defined(CONFIG_MCUBOOT_UUID_VID) || defined(CONFIG_MCUBOOT_UUID_CID) #include "bootutil/mcuboot_uuid.h" @@ -661,6 +667,37 @@ static void boot_serial_enter() } #endif +static int boot_prevalidate(void) +{ +#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST + uint8_t image_index; + enum boot_slot slot; + uint32_t area_id; + const struct flash_area *fap; + int rc = boot_request_init(); + + if (rc != 0) { + return rc; + } + + for (image_index = 0; image_index < BOOT_IMAGE_NUMBER; ++image_index) { + for (slot = BOOT_SLOT_PRIMARY; slot < BOOT_SLOT_COUNT; slot++) { + if (boot_request_check_confirmed_slot(image_index, slot)) { + BOOT_LOG_DBG("Confirm image: %d slot: %d due to bootloader request.", + image_index, slot); + + area_id = flash_area_id_from_multi_image_slot(image_index, slot); + rc = flash_area_open(area_id, &fap); + if (rc == 0) { + rc = boot_set_next(fap, true, true); + } + } + } + } +#endif + return 0; +} + int main(void) { struct boot_rsp rsp; @@ -700,6 +737,11 @@ int main(void) } #endif /* CONFIG_MCUBOOT_UUID_VID || CONFIG_MCUBOOT_UUID_CID */ + rc = boot_prevalidate(); + if (rc) { + BOOT_LOG_ERR("Failed to prevalidate the state: %d", rc); + } + #ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO BOOT_LOG_DBG("Checking GPIO for serial recovery"); if (io_detect_pin() && @@ -715,6 +757,13 @@ int main(void) } #endif +#ifdef CONFIG_NRF_BOOT_SERIAL_BOOT_REQ + if (boot_request_detect_recovery()) { + BOOT_LOG_DBG("Staying in serial recovery"); + boot_serial_enter(); + } +#endif + #if defined(CONFIG_BOOT_USB_DFU_GPIO) BOOT_LOG_DBG("Checking GPIO for USB DFU request"); if (io_detect_pin()) { @@ -775,6 +824,10 @@ int main(void) } BOOT_LOG_DBG("Left boot_go with success == %d", FIH_EQ(fih_rc, FIH_SUCCESS) ? 1 : 0); +#ifdef CONFIG_NRF_MCUBOOT_BOOT_REQUEST + (void)boot_request_clear(); +#endif + #ifdef CONFIG_BOOT_SERIAL_BOOT_MODE if (io_detect_boot_mode()) { /* Boot mode to stay in bootloader, clear status and enter serial From ff0d213e772e4225b8904ec4ef4c5d02c563a829 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 22 Aug 2024 14:17:46 +0100 Subject: [PATCH 133/149] [nrf noup] zephyr: Add support for compressed image updates Adds support for LZMA-compressed firmware updates which also supports encrypted images and supports more than 1 updateable image Signed-off-by: Jamie McCrae Signed-off-by: Michal Kozikowski Signed-off-by: Dominik Ermel Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 27758d7c440e5fbd284bd4e9b75e3e634562a718) (cherry picked from commit ce9d1d6bf1b26663195752ad137a315c1172c6cb) (cherry picked from commit 90b22796b1a6f08705c79ddf5884f3a83a2563a0) --- boot/bootutil/src/bootutil_loader.c | 13 +- boot/bootutil/src/bootutil_misc.c | 80 +- boot/bootutil/src/image_validate.c | 223 ++- boot/bootutil/src/loader.c | 19 + boot/zephyr/CMakeLists.txt | 6 + boot/zephyr/Kconfig | 9 +- boot/zephyr/decompression.c | 1505 +++++++++++++++++ .../include/compression/decompression.h | 103 ++ 8 files changed, 1932 insertions(+), 26 deletions(-) create mode 100644 boot/zephyr/decompression.c create mode 100644 boot/zephyr/include/compression/decompression.h diff --git a/boot/bootutil/src/bootutil_loader.c b/boot/bootutil/src/bootutil_loader.c index 829e3833a..7a0e3a1f2 100644 --- a/boot/bootutil/src/bootutil_loader.c +++ b/boot/bootutil/src/bootutil_loader.c @@ -51,6 +51,11 @@ #include #endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include +#endif + BOOT_LOG_MODULE_DECLARE(mcuboot); bool @@ -120,10 +125,10 @@ boot_check_header_valid(struct boot_loader_state *state, int slot) return false; } #else - if ((hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1) && - (hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) - { - return false; + if (MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), hdr)) { + if (!boot_is_compressed_header_valid(hdr, fap, state)) { + return false; + } } #endif diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index fa95e6133..648432381 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -47,8 +47,9 @@ #include "swap_priv.h" #endif -#if defined(MCUBOOT_SERIAL_IMG_GRP_SLOT_INFO) || defined(MCUBOOT_SWAP_USING_SCRATCH) -#include "swap_priv.h" +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include #endif BOOT_LOG_MODULE_DECLARE(mcuboot); @@ -386,35 +387,76 @@ boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size) fap = BOOT_IMG_AREA(state, slot); assert(fap != NULL); - off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); +#ifdef MCUBOOT_DECOMPRESS_IMAGES + if (MUST_DECOMPRESS(fap, BOOT_CURR_IMG(state), boot_img_hdr(state, slot))) { + uint32_t tmp_size = 0; - if (flash_area_read(fap, off, &info, sizeof(info))) { - rc = BOOT_EFLASH; - goto done; - } + rc = bootutil_get_img_decomp_size(boot_img_hdr(state, slot), fap, &tmp_size); - protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; - if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { - if (protect_tlv_size != info.it_tlv_tot) { + if (rc) { rc = BOOT_EBADIMAGE; goto done; } - if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { + off = boot_img_hdr(state, slot)->ih_hdr_size + tmp_size; + + rc = boot_size_protected_tlvs(boot_img_hdr(state, slot), fap, &tmp_size); + + if (rc) { + rc = BOOT_EBADIMAGE; + goto done; + } + + off += tmp_size; + + if (flash_area_read(fap, (BOOT_TLV_OFF(boot_img_hdr(state, slot)) + + boot_img_hdr(state, slot)->ih_protect_tlv_size), &info, + sizeof(info))) { rc = BOOT_EFLASH; goto done; } - } else if (protect_tlv_size != 0) { - rc = BOOT_EBADIMAGE; - goto done; - } - if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { - rc = BOOT_EBADIMAGE; - goto done; + if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { + rc = BOOT_EBADIMAGE; + goto done; + } + + *size = off + info.it_tlv_tot; + } else { +#else + if (1) { +#endif + off = BOOT_TLV_OFF(boot_img_hdr(state, slot)); + + if (flash_area_read(fap, off, &info, sizeof(info))) { + rc = BOOT_EFLASH; + goto done; + } + + protect_tlv_size = boot_img_hdr(state, slot)->ih_protect_tlv_size; + if (info.it_magic == IMAGE_TLV_PROT_INFO_MAGIC) { + if (protect_tlv_size != info.it_tlv_tot) { + rc = BOOT_EBADIMAGE; + goto done; + } + + if (flash_area_read(fap, off + info.it_tlv_tot, &info, sizeof(info))) { + rc = BOOT_EFLASH; + goto done; + } + } else if (protect_tlv_size != 0) { + rc = BOOT_EBADIMAGE; + goto done; + } + + if (info.it_magic != IMAGE_TLV_INFO_MAGIC) { + rc = BOOT_EBADIMAGE; + goto done; + } + + *size = off + protect_tlv_size + info.it_tlv_tot; } - *size = off + protect_tlv_size + info.it_tlv_tot; rc = 0; done: diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index da8194e99..0f50a87d5 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -54,6 +54,11 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); #include "bootutil/mcuboot_manifest.h" #endif /* MCUBOOT_MANIFEST_UPDATES */ +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include +#endif + #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -211,7 +216,7 @@ bootutil_img_validate(struct boot_loader_state *state, #if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || \ (defined(EXPECTED_SIG_TLV) && defined(MCUBOOT_BUILTIN_KEY)) || \ defined(MCUBOOT_HW_ROLLBACK_PROT) || defined(MCUBOOT_MANIFEST_UPDATES) || \ - defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) + defined(MCUBOOT_UUID_VID) || defined(MCUBOOT_UUID_CID) || defined(MCUBOOT_DECOMPRESS_IMAGES) int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state)); #endif uint32_t off; @@ -272,6 +277,67 @@ bootutil_img_validate(struct boot_loader_state *state, #endif BOOT_LOG_DBG("bootutil_img_validate: flash area %p", fap); +#ifdef MCUBOOT_DECOMPRESS_IMAGES + /* If the image is compressed, the integrity of the image must also be validated */ + if (MUST_DECOMPRESS(fap, image_index, hdr)) { + bool found_decompressed_size = false; + bool found_decompressed_sha = false; + bool found_decompressed_signature = false; + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true); + if (rc) { + goto out; + } + + if (it.tlv_end > bootutil_max_image_size(state, fap)) { + rc = -1; + goto out; + } + + while (true) { + uint16_t expected_size = 0; + bool *found_flag = NULL; + + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + break; + } + + switch (type) { + case IMAGE_TLV_DECOMP_SIZE: + expected_size = sizeof(size_t); + found_flag = &found_decompressed_size; + break; + case IMAGE_TLV_DECOMP_SHA: + expected_size = IMAGE_HASH_SIZE; + found_flag = &found_decompressed_sha; + break; + case IMAGE_TLV_DECOMP_SIGNATURE: + found_flag = &found_decompressed_signature; + break; + default: + continue; + }; + + if (type == IMAGE_TLV_DECOMP_SIGNATURE && !EXPECTED_SIG_LEN(len)) { + rc = -1; + goto out; + } else if (type != IMAGE_TLV_DECOMP_SIGNATURE && len != expected_size) { + rc = -1; + goto out; + } + + *found_flag = true; + } + + rc = (!found_decompressed_size || !found_decompressed_sha || !found_decompressed_signature); + if (rc) { + goto out; + } + } +#endif #if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) rc = bootutil_img_hash(state, hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len); @@ -713,6 +779,161 @@ bootutil_img_validate(struct boot_loader_state *state, } #endif +#ifdef MCUBOOT_DECOMPRESS_IMAGES + /* Only after all previous verifications have passed, perform a dry-run of the decompression + * and ensure the image is valid + */ + if (!rc && MUST_DECOMPRESS(fap, image_index, hdr)) { + image_hash_valid = 0; + FIH_SET(valid_signature, FIH_FAILURE); + + rc = bootutil_img_hash_decompress(state, hdr, fap, tmp_buf, tmp_buf_sz, + hash, seed, seed_len); + if (rc) { + goto out; + } + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SHA, true); + if (rc) { + goto out; + } + + if (it.tlv_end > bootutil_max_image_size(state, fap)) { + rc = -1; + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + break; + } + + if (type == IMAGE_TLV_DECOMP_SHA) { + /* Verify the image hash. This must always be present. */ + if (len != sizeof(hash)) { + rc = -1; + goto out; + } + rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, sizeof(hash)); + if (rc) { + goto out; + } + + FIH_CALL(boot_fih_memequal, fih_rc, hash, buf, sizeof(hash)); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + FIH_SET(fih_rc, FIH_FAILURE); + goto out; + } + + image_hash_valid = 1; + } + } + + rc = !image_hash_valid; + if (rc) { + goto out; + } + +#ifdef EXPECTED_SIG_TLV +#ifdef EXPECTED_KEY_TLV + rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false); + if (rc) { + goto out; + } + + if (it.tlv_end > bootutil_max_image_size(state, fap)) { + rc = -1; + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + break; + } + + if (type == EXPECTED_KEY_TLV) { + /* + * Determine which key we should be checking. + */ + if (len > KEY_BUF_SIZE) { + rc = -1; + goto out; + } +#ifndef MCUBOOT_HW_KEY + rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); + if (rc) { + goto out; + } + key_id = bootutil_find_key(buf, len); +#else + rc = LOAD_IMAGE_DATA(hdr, fap, off, key_buf, len); + if (rc) { + goto out; + } + key_id = bootutil_find_key(image_index, key_buf, len); +#endif /* !MCUBOOT_HW_KEY */ + /* + * The key may not be found, which is acceptable. There + * can be multiple signatures, each preceded by a key. + */ + } + } +#endif /* EXPECTED_KEY_TLV */ + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true); + if (rc) { + goto out; + } + + if (it.tlv_end > bootutil_max_image_size(state, fap)) { + rc = -1; + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + + if (type == IMAGE_TLV_DECOMP_SIGNATURE) { + /* Ignore this signature if it is out of bounds. */ + if (key_id < 0 || key_id >= bootutil_key_cnt) { + key_id = -1; + continue; + } + + if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { + rc = -1; + goto out; + } + rc = LOAD_IMAGE_DATA(hdr, fap, off, buf, len); + if (rc) { + goto out; + } + + FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash), + buf, len, key_id); + key_id = -1; + } + } +#endif /* EXPECTED_SIG_TLV */ + } +#endif + +#ifdef EXPECTED_SIG_TLV + FIH_SET(fih_rc, valid_signature); +#endif + out: if (rc) { FIH_SET(fih_rc, FIH_FAILURE); diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index e4b6e968a..26e3d95ca 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -53,6 +53,11 @@ #ifndef MCUBOOT_MANIFEST_UPDATES +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include +#endif + #ifdef __ZEPHYR__ #include #endif @@ -744,6 +749,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, * attempts to validate and boot it. */ } + #if !defined(__BOOTSIM__) BOOT_LOG_ERR("Image in the %s slot is not valid!", (slot == BOOT_SLOT_PRIMARY) ? "primary" : "secondary"); @@ -1207,6 +1213,9 @@ boot_copy_region(struct boot_loader_state *state, #else (void)state; #endif +#if defined(MCUBOOT_DECOMPRESS_IMAGES) && !defined(MCUBOOT_ENC_IMAGES) + struct image_header *hdr; +#endif TARGET_STATIC uint8_t buf[BUF_SZ] __attribute__((aligned(4))); @@ -1232,6 +1241,16 @@ boot_copy_region(struct boot_loader_state *state, } #endif +#ifdef MCUBOOT_DECOMPRESS_IMAGES + hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY); + + if (MUST_DECOMPRESS(fap_src, BOOT_CURR_IMG(state), hdr)) { + /* Use alternative function for compressed images */ + return boot_copy_region_decompress(state, fap_src, fap_dst, off_src, off_dst, sz, buf, + BUF_SZ); + } +#endif + bytes_copied = 0; while (bytes_copied < sz) { if (sz - bytes_copied > sizeof buf) { diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index e9f4cebee..c1974d7a1 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -356,6 +356,12 @@ if(CONFIG_BOOT_ENCRYPT_EC256 AND NOT CONFIG_BOOT_ECDSA_PSA) ) endif() +if(CONFIG_BOOT_DECOMPRESSION) + zephyr_library_sources( + decompression.c + ) +endif() + if(CONFIG_MCUBOOT_SERIAL) zephyr_sources(${BOOT_DIR}/zephyr/serial_adapter.c) zephyr_sources(${BOOT_DIR}/boot_serial/src/boot_serial.c) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 39ce565c8..78fb6a59b 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1228,6 +1228,9 @@ config MCUBOOT_USE_TLV_ALLOW_LIST config BOOT_DECOMPRESSION_SUPPORT bool + depends on NRF_COMPRESS && NRF_COMPRESS_DECOMPRESSION && (NRF_COMPRESS_LZMA_VERSION_LZMA1 || NRF_COMPRESS_LZMA_VERSION_LZMA2) + depends on !SINGLE_APPLICATION_SLOT && BOOT_UPGRADE_ONLY + default y help Hidden symbol which should be selected if a system provided decompression support. @@ -1235,6 +1238,8 @@ if BOOT_DECOMPRESSION_SUPPORT menuconfig BOOT_DECOMPRESSION bool "Decompression" + select NRF_COMPRESS_CLEANUP + select PM_USE_CONFIG_SRAM_SIZE if SOC_NRF54L15_CPUAPP help If enabled, will include support for compressed images being loaded to the secondary slot which then get decompressed into the primary slot. This mode allows the secondary slot to @@ -1243,9 +1248,9 @@ menuconfig BOOT_DECOMPRESSION if BOOT_DECOMPRESSION config BOOT_DECOMPRESSION_BUFFER_SIZE - int "Write buffer size" + int range 16 16384 - default 4096 + default NRF_COMPRESS_CHUNK_SIZE help The size of a secondary buffer used for writing decompressed data to the storage device. diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c new file mode 100644 index 000000000..384899922 --- /dev/null +++ b/boot/zephyr/decompression.c @@ -0,0 +1,1505 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include "compression/decompression.h" +#include "bootutil/crypto/sha.h" +#include "bootutil/bootutil_log.h" + +#if !defined(__BOOTSIM__) +#define TARGET_STATIC static +#else +#define TARGET_STATIC +#endif + +#if defined(MCUBOOT_SIGN_RSA) +#if MCUBOOT_SIGN_RSA_LEN == 2048 +#define EXPECTED_SIG_TLV IMAGE_TLV_RSA2048_PSS +#elif MCUBOOT_SIGN_RSA_LEN == 3072 +#define EXPECTED_SIG_TLV IMAGE_TLV_RSA3072_PSS +#endif +#elif defined(MCUBOOT_SIGN_EC256) || \ + defined(MCUBOOT_SIGN_EC384) || \ + defined(MCUBOOT_SIGN_EC) +#define EXPECTED_SIG_TLV IMAGE_TLV_ECDSA_SIG +#elif defined(MCUBOOT_SIGN_ED25519) +#define EXPECTED_SIG_TLV IMAGE_TLV_ED25519 +#endif + +#define DECOMP_BUF_SIZE CONFIG_BOOT_DECOMPRESSION_BUFFER_SIZE +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) +/* Extra buffer space for being able to writeback ARM thumb decompression output, + * which may be of +2 bytes more size than its input. + */ +#define DECOMP_BUF_EXTRA_SIZE 2 +#else +#define DECOMP_BUF_EXTRA_SIZE 0 +#endif +#define DECOMP_BUF_ALLOC_SIZE (DECOMP_BUF_SIZE + DECOMP_BUF_EXTRA_SIZE) + +#define DECRYPTION_BLOCK_SIZE_AES128 16 +#define DECRYPTION_BLOCK_SIZE_AES256 32 + +/* Number of times that consumed data by decompression system can be 0 in a row before aborting */ +#define OFFSET_ZERO_CHECK_TIMES 3 + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +static int boot_sha_protected_tlvs(const struct image_header *hdr, + const struct flash_area *fap_src, uint32_t protected_size, + uint8_t *buf, size_t buf_size, bootutil_sha_context *sha_ctx); + +bool boot_is_compressed_header_valid(const struct image_header *hdr, const struct flash_area *fap, + struct boot_loader_state *state) +{ + /* Image is compressed in secondary slot, need to check if fits into the primary slot */ + bool opened_flash_area = false; + int primary_fa_id; + int rc; + int size_check; + int size; + uint32_t protected_tlvs_size; + uint32_t decompressed_size; + + primary_fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), BOOT_SLOT_PRIMARY); + + if (primary_fa_id == fap->fa_id) { + BOOT_LOG_ERR("Primary slots cannot be compressed, image: %d", BOOT_CURR_IMG(state)); + return false; + } + + if (BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY) == NULL) { + opened_flash_area = true; + } + + rc = flash_area_open(primary_fa_id, &BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); + assert(rc == 0); + + size_check = flash_area_get_size(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); + + if (opened_flash_area) { + (void)flash_area_close(BOOT_IMG_AREA(state, BOOT_SLOT_PRIMARY)); + } + + rc = bootutil_get_img_decomp_size(hdr, fap, &decompressed_size); + + if (rc) { + return false; + } + + if (!boot_u32_safe_add(&size, decompressed_size, hdr->ih_hdr_size)) { + return false; + } + + rc = boot_size_protected_tlvs(hdr, fap, &protected_tlvs_size); + + if (rc) { + return false; + } + + if (!boot_u32_safe_add(&size, size, protected_tlvs_size)) { + return false; + } + + if (size >= size_check) { + BOOT_LOG_ERR("Compressed image too large, decompressed image size: 0x%x, slot size: 0x%x", + size, size_check); + return false; + } + + return true; +} + +static bool is_compression_object_valid(struct nrf_compress_implementation *compression) +{ + if (compression == NULL || compression->init == NULL || compression->deinit == NULL || + compression->decompress_bytes_needed == NULL || compression->decompress == NULL) { + return false; + } + + return true; +} + +#ifdef MCUBOOT_ENC_IMAGES +int bootutil_get_img_decrypted_comp_size(const struct image_header *hdr, + const struct flash_area *fap, uint32_t *img_comp_size) +{ + if (hdr == NULL || fap == NULL || img_comp_size == NULL) { + return BOOT_EBADARGS; + } else if (hdr->ih_protect_tlv_size == 0) { + return BOOT_EBADIMAGE; + } + + if (!IS_ENCRYPTED(hdr)) { + /* Update is not encrypted so use size from header */ + *img_comp_size = hdr->ih_img_size; + } else { + struct image_tlv_iter it; + uint32_t off; + uint16_t len; + int32_t rc; + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_COMP_DEC_SIZE, true); + + if (rc) { + return rc; + } + + rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); + + if (rc != 0) { + return -1; + } + + if (len != sizeof(*img_comp_size)) { + BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); + return BOOT_EBADIMAGE; + } + + rc = LOAD_IMAGE_DATA(hdr, fap, off, img_comp_size, len); + + if (rc) { + BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + off, len, fap->fa_id, rc); + return BOOT_EFLASH; + } + } + + return 0; +} +#endif + +int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_header *hdr, + const struct flash_area *fap, uint8_t *tmp_buf, + uint32_t tmp_buf_sz, uint8_t *hash_result, + uint8_t *seed, int seed_len) +{ + int rc; + uint32_t read_pos = 0; + uint32_t write_pos = 0; + uint32_t protected_tlv_size = 0; + uint32_t decompressed_image_size; + uint32_t output_size_total = 0; + struct nrf_compress_implementation *compression_lzma = NULL; + struct nrf_compress_implementation *compression_arm_thumb = NULL; + TARGET_STATIC struct image_header modified_hdr; + bootutil_sha_context sha_ctx; + +#ifdef MCUBOOT_ENC_IMAGES + struct enc_key_data *enc_state; + int image_index; + uint32_t comp_size = 0; + uint8_t decryption_block_size = 0; + + rc = bootutil_get_img_decrypted_comp_size(hdr, fap, &comp_size); + + if (rc) { + BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); + rc = BOOT_EBADIMAGE; + goto finish_end; + } + + if (state == NULL) { + enc_state = NULL; + image_index = 0; + } else { + enc_state = BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY); + image_index = BOOT_CURR_IMG(state); + } + + /* Encrypted images only exist in the secondary slot */ + if (MUST_DECRYPT(fap, image_index, hdr) && !boot_enc_valid(enc_state)) { + return -1; + } + + if (MUST_DECRYPT(fap, image_index, hdr)) { + if (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES128) { + decryption_block_size = DECRYPTION_BLOCK_SIZE_AES128; + } else if (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES256) { + decryption_block_size = DECRYPTION_BLOCK_SIZE_AES256; + } else { + LOG_ERR("Unknown decryption block size"); + rc = BOOT_EBADIMAGE; + goto finish_end; + } + } +#endif + + bootutil_sha_init(&sha_ctx); + + /* Setup decompression system */ +#if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 + if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { +#elif CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2 + if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) { +#endif + /* Compressed image does not use the correct compression type which is supported by this + * build + */ + BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); + rc = BOOT_EBADIMAGE; + goto finish_without_clean; + } + + compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); + compression_arm_thumb = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_ARM_THUMB); + + if (!is_compression_object_valid(compression_lzma) || + !is_compression_object_valid(compression_arm_thumb)) { + /* Compression library missing or missing required function pointer */ + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish_without_clean; + } + + rc = compression_lzma->init(NULL); + rc = compression_arm_thumb->init(NULL); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish_without_clean; + } + + /* We need a modified header which has the updated sizes, start with the original header */ + memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); + + /* Extract the decompressed image size from the protected TLV, set it and remove the + * compressed image flags + */ + rc = bootutil_get_img_decomp_size(hdr, fap, &decompressed_image_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); + rc = BOOT_EBADIMAGE; + goto finish; + } + + modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; + modified_hdr.ih_img_size = decompressed_image_size; + + /* Calculate the protected TLV size, these will not include the decompressed + * sha/size/signature entries + */ + rc = boot_size_protected_tlvs(hdr, fap, &protected_tlv_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); + rc = BOOT_EBADIMAGE; + goto finish; + } + + modified_hdr.ih_protect_tlv_size = protected_tlv_size; + bootutil_sha_update(&sha_ctx, &modified_hdr, sizeof(modified_hdr)); + read_pos = sizeof(modified_hdr); + + while (read_pos < modified_hdr.ih_hdr_size) { + uint32_t copy_size = tmp_buf_sz; + + if ((read_pos + copy_size) > modified_hdr.ih_hdr_size) { + copy_size = modified_hdr.ih_hdr_size - read_pos; + } + + rc = flash_area_read(fap, read_pos, tmp_buf, copy_size); + + if (rc != 0) { + BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (hdr->ih_hdr_size + read_pos), copy_size, fap->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + + bootutil_sha_update(&sha_ctx, tmp_buf, copy_size); + read_pos += copy_size; + } + + /* Read in compressed data, decompress and add to hash calculation */ + read_pos = 0; + +#ifdef MCUBOOT_ENC_IMAGES + while (read_pos < comp_size) { + uint32_t copy_size = comp_size - read_pos; +#else + while (read_pos < hdr->ih_img_size) { + uint32_t copy_size = hdr->ih_img_size - read_pos; +#endif + uint32_t tmp_off = 0; + uint8_t offset_zero_check = 0; + + if (copy_size > tmp_buf_sz) { + copy_size = tmp_buf_sz; + } + + rc = flash_area_read(fap, (hdr->ih_hdr_size + read_pos), tmp_buf, copy_size); + + if (rc != 0) { + BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (hdr->ih_hdr_size + read_pos), copy_size, fap->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + +#ifdef MCUBOOT_ENC_IMAGES + if (MUST_DECRYPT(fap, image_index, hdr)) { + uint8_t dummy_bytes = 0; + + if ((copy_size % decryption_block_size)) { + dummy_bytes = decryption_block_size - (copy_size % decryption_block_size); + memset(&tmp_buf[copy_size], 0x00, dummy_bytes); + } + + boot_enc_decrypt(enc_state, read_pos, (copy_size + dummy_bytes), (read_pos & 0xf), + tmp_buf); + } +#endif + + /* Decompress data in chunks, writing it back with a larger write offset of the primary + * slot than read size of the secondary slot + */ + while (tmp_off < copy_size) { + uint32_t offset = 0; + uint8_t *output = NULL; + uint32_t output_size = 0; + uint32_t chunk_size; + bool last_packet = false; + + chunk_size = compression_lzma->decompress_bytes_needed(NULL); + + if (chunk_size > (copy_size - tmp_off)) { + chunk_size = (copy_size - tmp_off); + } + +#ifdef MCUBOOT_ENC_IMAGES + if ((read_pos + tmp_off + chunk_size) >= comp_size) { +#else + if ((read_pos + tmp_off + chunk_size) >= hdr->ih_img_size) { +#endif + last_packet = true; + } + + rc = compression_lzma->decompress(NULL, &tmp_buf[tmp_off], chunk_size, last_packet, + &offset, &output, &output_size); + + if (rc) { + BOOT_LOG_ERR("Decompression error: %d", rc); + rc = BOOT_EBADSTATUS; + goto finish; + } + + write_pos += output_size; + + if (write_pos > decompressed_image_size) { + BOOT_LOG_ERR("Decompressed image larger than claimed TLV size, at least: %d", + write_pos); + rc = BOOT_EBADIMAGE; + goto finish; + } + + /* Additional dry-run validity checks */ + if (last_packet == true && write_pos == 0) { + /* Last packet and we still have no output, this is a faulty update */ + BOOT_LOG_ERR("All compressed data consumed without any output, image not valid"); + rc = BOOT_EBADIMAGE; + goto finish; + } + + if (offset == 0) { + /* If the decompression system continually consumes 0 bytes, then there is a + * problem with this update image, abort and mark image as bad + */ + if (offset_zero_check >= OFFSET_ZERO_CHECK_TIMES) { + BOOT_LOG_ERR("Decompression system returning no output data, image not valid"); + rc = BOOT_EBADIMAGE; + goto finish; + } + + ++offset_zero_check; + + break; + } else { + offset_zero_check = 0; + } + + /* Copy data to secondary buffer for calculating hash */ + if (output_size > 0) { + if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { + /* Run this through the ARM thumb filter */ + uint32_t offset_arm_thumb = 0; + uint8_t *output_arm_thumb = NULL; + uint32_t processed_size = 0; + uint32_t output_size_arm_thumb = 0; + + while (processed_size < output_size) { + uint32_t current_size = output_size - processed_size; + bool arm_thumb_last_packet = false; + + if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) { + current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE; + } + + if (last_packet && (processed_size + current_size) == + output_size) { + arm_thumb_last_packet = true; + } + + rc = compression_arm_thumb->decompress(NULL, &output[processed_size], + current_size, arm_thumb_last_packet, + &offset_arm_thumb, + &output_arm_thumb, + &output_size_arm_thumb); + + if (rc) { + BOOT_LOG_ERR("Decompression error: %d", rc); + rc = BOOT_EBADSTATUS; + goto finish; + } + + bootutil_sha_update(&sha_ctx, output_arm_thumb, output_size_arm_thumb); + output_size_total += output_size_arm_thumb; + processed_size += current_size; + } + } else { + bootutil_sha_update(&sha_ctx, output, output_size); + output_size_total += output_size; + } + } + + tmp_off += offset; + } + + read_pos += copy_size; + } + + if (modified_hdr.ih_img_size != output_size_total) { + BOOT_LOG_ERR("Decompression expected output_size mismatch: %d vs %d", + modified_hdr.ih_img_size, output_size_total); + rc = BOOT_EBADSTATUS; + goto finish; + } + + /* If there are any protected TLVs present, add them after the main decompressed image */ + if (modified_hdr.ih_protect_tlv_size > 0) { + rc = boot_sha_protected_tlvs(hdr, fap, modified_hdr.ih_protect_tlv_size, tmp_buf, + tmp_buf_sz, &sha_ctx); + } + + bootutil_sha_finish(&sha_ctx, hash_result); + +finish: + /* Clean up decompression system */ + (void)compression_lzma->deinit(NULL); + (void)compression_arm_thumb->deinit(NULL); + +finish_without_clean: + bootutil_sha_drop(&sha_ctx); + +#ifdef MCUBOOT_ENC_IMAGES +finish_end: +#endif + return rc; +} + +static int boot_copy_protected_tlvs(const struct image_header *hdr, + const struct flash_area *fap_src, + const struct flash_area *fap_dst, uint32_t off_dst, + uint32_t protected_size, uint8_t *buf, size_t buf_size, + uint16_t *buf_pos, uint32_t *written) +{ + int rc; + uint32_t off; + uint32_t write_pos = 0; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + struct image_tlv tlv_header; + struct image_tlv_info tlv_info_header = { + .it_magic = IMAGE_TLV_PROT_INFO_MAGIC, + .it_tlv_tot = protected_size, + }; + uint16_t info_size_left = sizeof(tlv_info_header); + + while (info_size_left > 0) { + uint16_t copy_size = buf_size - *buf_pos; + + if (info_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + uint8_t *tlv_info_header_address = (uint8_t *)&tlv_info_header; + + if (single_copy_size > info_size_left) { + single_copy_size = info_size_left; + } + + memcpy(&buf[*buf_pos], &tlv_info_header_address[sizeof(tlv_info_header) - + info_size_left], single_copy_size); + *buf_pos += single_copy_size; + info_size_left -= single_copy_size; + } + + if (*buf_pos == buf_size) { + rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); + + if (rc != 0) { + BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto out; + } + + write_pos += *buf_pos; + *buf_pos = 0; + } + } + + rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, true); + + if (rc) { + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + + if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || + type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { + /* Skip these TLVs as they are not needed */ + continue; + } else { + uint16_t header_size_left = sizeof(tlv_header); + uint16_t data_size_left = len; + + tlv_header.it_type = type; + tlv_header.it_len = len; + + while (header_size_left > 0 || data_size_left > 0) { + uint16_t copy_size = buf_size - *buf_pos; + uint8_t *tlv_header_address = (uint8_t *)&tlv_header; + + if (header_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + + if (single_copy_size > header_size_left) { + single_copy_size = header_size_left; + } + + memcpy(&buf[*buf_pos], &tlv_header_address[sizeof(tlv_header) - + header_size_left], + single_copy_size); + *buf_pos += single_copy_size; + copy_size -= single_copy_size; + header_size_left -= single_copy_size; + } + + if (data_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + + if (single_copy_size > data_size_left) { + single_copy_size = data_size_left; + } + + rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + (len - data_size_left)), + &buf[*buf_pos], single_copy_size); + + if (rc) { + BOOT_LOG_ERR( + "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); + goto out; + } + + *buf_pos += single_copy_size; + data_size_left -= single_copy_size; + } + + if (*buf_pos == buf_size) { + rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto out; + } + + write_pos += *buf_pos; + *buf_pos = 0; + } + } + } + } + + *written = write_pos; + +out: + return rc; +} + +static int boot_sha_protected_tlvs(const struct image_header *hdr, + const struct flash_area *fap_src, uint32_t protected_size, + uint8_t *buf, size_t buf_size, bootutil_sha_context *sha_ctx) +{ + int rc; + uint32_t off; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + struct image_tlv tlv_header; + struct image_tlv_info tlv_info_header = { + .it_magic = IMAGE_TLV_PROT_INFO_MAGIC, + .it_tlv_tot = protected_size, + }; + + bootutil_sha_update(sha_ctx, &tlv_info_header, sizeof(tlv_info_header)); + + rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, true); + if (rc) { + goto out; + } + + while (true) { + uint32_t read_off = 0; + + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + + if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || + type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { + /* Skip these TLVs as they are not needed */ + continue; + } + + tlv_header.it_type = type; + tlv_header.it_len = len; + + bootutil_sha_update(sha_ctx, &tlv_header, sizeof(tlv_header)); + + while (read_off < len) { + uint32_t copy_size = buf_size; + + if (copy_size > (len - read_off)) { + copy_size = len - read_off; + } + + rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + read_off), buf, copy_size); + + if (rc) { + BOOT_LOG_ERR( + "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off + read_off), copy_size, fap_src->fa_id, rc); + goto out; + } + + bootutil_sha_update(sha_ctx, buf, copy_size); + read_off += copy_size; + } + } + +out: + return rc; +} + +int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_area *fap, + uint32_t *sz) +{ + int rc = 0; + uint32_t tlv_size; + uint32_t off; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + + *sz = 0; + tlv_size = hdr->ih_protect_tlv_size; + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, true); + + if (rc) { + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + + if (type == IMAGE_TLV_DECOMP_SIZE || type == IMAGE_TLV_DECOMP_SHA || + type == IMAGE_TLV_DECOMP_SIGNATURE || type == IMAGE_TLV_COMP_DEC_SIZE) { + /* Exclude these TLVs as they will be copied to the unprotected area */ + tlv_size -= len + sizeof(struct image_tlv); + } + } + + if (!rc) { + if (tlv_size == sizeof(struct image_tlv_info)) { + /* If there are no entries then omit protected TLV section entirely */ + tlv_size = 0; + } + + *sz = tlv_size; + } + +out: + return rc; +} + +int boot_size_unprotected_tlvs(const struct image_header *hdr, const struct flash_area *fap, + uint32_t *sz) +{ + int rc = 0; + uint32_t tlv_size; + uint32_t off; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + + *sz = 0; + tlv_size = sizeof(struct image_tlv_info); + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false); + + if (rc) { + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } else if (bootutil_tlv_iter_is_prot(&it, off) && type != IMAGE_TLV_DECOMP_SHA && + type != IMAGE_TLV_DECOMP_SIGNATURE) { + /* Include size of protected hash and signature as these will be replacing the + * original ones + */ + continue; + } else if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV || type == IMAGE_TLV_COMP_DEC_SIZE) { + /* Exclude the original unprotected TLVs for signature and hash, the length of the + * signature of the compressed data might not be the same size as the signaute of the + * decompressed data, as is the case when using ECDSA-P256 + */ + continue; + } + + tlv_size += len + sizeof(struct image_tlv); + } + + if (!rc) { + if (tlv_size == sizeof(struct image_tlv_info)) { + /* If there are no entries in the unprotected TLV section then there is something wrong + * with this image + */ + BOOT_LOG_ERR("No unprotected TLVs in post-decompressed image output, image is invalid"); + rc = BOOT_EBADIMAGE; + goto out; + } + + *sz = tlv_size; + } + +out: + return rc; +} + +static int boot_copy_unprotected_tlvs(const struct image_header *hdr, + const struct flash_area *fap_src, + const struct flash_area *fap_dst, uint32_t off_dst, + uint32_t unprotected_size, uint8_t *buf, size_t buf_size, + uint16_t *buf_pos, uint32_t *written) +{ + int rc; + uint32_t write_pos = 0; + uint32_t off; + uint16_t len; + uint16_t type; + struct image_tlv_iter it; + struct image_tlv_iter it_protected; + struct image_tlv tlv_header; + struct image_tlv_info tlv_info_header = { + .it_magic = IMAGE_TLV_INFO_MAGIC, + .it_tlv_tot = unprotected_size, + }; + uint16_t info_size_left = sizeof(tlv_info_header); + + while (info_size_left > 0) { + uint16_t copy_size = buf_size - *buf_pos; + + if (info_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + uint8_t *tlv_info_header_address = (uint8_t *)&tlv_info_header; + + if (single_copy_size > info_size_left) { + single_copy_size = info_size_left; + } + + memcpy(&buf[*buf_pos], &tlv_info_header_address[sizeof(tlv_info_header) - + info_size_left], single_copy_size); + *buf_pos += single_copy_size; + info_size_left -= single_copy_size; + } + + if (*buf_pos == buf_size) { + rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); + + if (rc != 0) { + BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto out; + } + + write_pos += *buf_pos; + *buf_pos = 0; + } + } + + rc = bootutil_tlv_iter_begin(&it, hdr, fap_src, IMAGE_TLV_ANY, false); + if (rc) { + goto out; + } + + while (true) { + uint16_t header_size_left = sizeof(tlv_header); + uint16_t data_size_left; + + rc = bootutil_tlv_iter_next(&it, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } else if (bootutil_tlv_iter_is_prot(&it, off)) { + /* Skip protected TLVs */ + continue; + } + + /* Change the values of these fields from having the data in the compressed image + * unprotected TLV (which is valid only for the compressed image data) to having the + * fields in the protected TLV section (which is valid for the decompressed image data). + * The compressed data is no longer needed + */ + if (type == EXPECTED_HASH_TLV || type == EXPECTED_SIG_TLV) { + rc = bootutil_tlv_iter_begin(&it_protected, hdr, fap_src, (type == EXPECTED_HASH_TLV ? + IMAGE_TLV_DECOMP_SHA : + IMAGE_TLV_DECOMP_SIGNATURE), + true); + + if (rc) { + goto out; + } + + while (true) { + rc = bootutil_tlv_iter_next(&it_protected, &off, &len, &type); + if (rc < 0) { + goto out; + } else if (rc > 0) { + rc = 0; + break; + } + } + + if (type == IMAGE_TLV_DECOMP_SHA) { + type = EXPECTED_HASH_TLV; + } else { + type = EXPECTED_SIG_TLV; + } + } + + data_size_left = len; + tlv_header.it_type = type; + tlv_header.it_len = len; + + while (header_size_left > 0 || data_size_left > 0) { + uint16_t copy_size = buf_size - *buf_pos; + + if (header_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + uint8_t *tlv_header_address = (uint8_t *)&tlv_header; + + if (single_copy_size > header_size_left) { + single_copy_size = header_size_left; + } + + memcpy(&buf[*buf_pos], &tlv_header_address[sizeof(tlv_header) - header_size_left], + single_copy_size); + *buf_pos += single_copy_size; + copy_size -= single_copy_size; + header_size_left -= single_copy_size; + } + + if (data_size_left > 0 && copy_size > 0) { + uint16_t single_copy_size = copy_size; + + if (single_copy_size > data_size_left) { + single_copy_size = data_size_left; + } + + rc = LOAD_IMAGE_DATA(hdr, fap_src, (off + len - data_size_left), + &buf[*buf_pos], single_copy_size); + + if (rc) { + BOOT_LOG_ERR( + "Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off + (len - data_size_left)), single_copy_size, fap_src->fa_id, rc); + goto out; + } + + *buf_pos += single_copy_size; + data_size_left -= single_copy_size; + } + + if (*buf_pos == buf_size) { + rc = flash_area_write(fap_dst, (off_dst + write_pos), buf, *buf_pos); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + write_pos), *buf_pos, fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto out; + } + + write_pos += *buf_pos; + *buf_pos = 0; + } + } + } + + *written = write_pos; + +out: + return rc; +} + +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) +/** + * @brief Helper function for in-place ARM Thumb filtering. + * This function places the decompressed data back into the same buffer + * at the beginning, overwriting the compressed data. WARNING: because + * ARM Thumb filtering can return +-2 more/less bytes than the input, + * the buffer provided needs to have free DECOMP_BUF_EXTRA_SIZE bytes at + * the beginning and provide valid data for filtering after these. + * + * @param[in] arm_thumb_impl Pointer to the ARM Thumb decompression implementation. + * @param[in,out] buf Pointer to the buffer containing the compressed data / filtered data. + * @param[in] buf_size Size of the buffer (including DECOMP_BUF_EXTRA_SIZE bytes at the beginning). + * @param[out] out_size Pointer to a variable where the size of the filtered data will be stored. + * @param[in] last_part Indicates if this is the last part of the data to be filtered. + * + * @return 0 on success, BOOT_EBADSTATUS on error. + */ +static int boot_arm_thumb_filter(struct nrf_compress_implementation * const arm_thumb_impl, + uint8_t *buf, size_t buf_size, size_t *out_size, bool last_part) { + + uint32_t filter_writeback_pos = 0; + uint32_t processed_size = 0; + int rc; + + while (processed_size < (buf_size - DECOMP_BUF_EXTRA_SIZE)) { + uint32_t offset_arm_thumb = 0; + uint32_t output_size_arm_thumb = 0; + uint8_t *output_arm_thumb = NULL; + uint32_t current_size = (buf_size - DECOMP_BUF_EXTRA_SIZE - processed_size); + bool arm_thumb_last_packet = false; + + if (current_size > CONFIG_NRF_COMPRESS_CHUNK_SIZE) { + current_size = CONFIG_NRF_COMPRESS_CHUNK_SIZE; + } + + if (last_part && (processed_size + current_size) == (buf_size - DECOMP_BUF_EXTRA_SIZE)) { + arm_thumb_last_packet = true; + } + + rc = arm_thumb_impl->decompress(NULL, + &buf[processed_size + + DECOMP_BUF_EXTRA_SIZE], + current_size, + arm_thumb_last_packet, + &offset_arm_thumb, + &output_arm_thumb, + &output_size_arm_thumb); + + if (rc) { + BOOT_LOG_ERR("Decompression error: %d", rc); + return BOOT_EBADSTATUS; + } + + if (output_size_arm_thumb > (buf_size - filter_writeback_pos)) { + BOOT_LOG_ERR("Filter writeback position exceeds buffer size"); + return BOOT_EBADSTATUS; + } + + memcpy(&buf[filter_writeback_pos], output_arm_thumb, + output_size_arm_thumb); + filter_writeback_pos += output_size_arm_thumb; + processed_size += offset_arm_thumb; + } + *out_size = filter_writeback_pos; + + return 0; +} +#endif /* CONFIG_NRF_COMPRESS_ARM_THUMB */ + +int boot_copy_region_decompress(struct boot_loader_state *state, const struct flash_area *fap_src, + const struct flash_area *fap_dst, uint32_t off_src, + uint32_t off_dst, uint32_t sz, uint8_t *buf, size_t buf_size) +{ + int rc; + uint32_t pos = 0; + uint16_t decomp_buf_size = 0; + uint16_t write_alignment; + uint32_t write_pos = 0; + uint32_t protected_tlv_size = 0; + uint32_t unprotected_tlv_size = 0; + uint32_t tlv_write_size = 0; + uint32_t decompressed_image_size; + struct nrf_compress_implementation *compression_lzma = NULL; + struct nrf_compress_implementation *compression_arm_thumb = NULL; + struct image_header *hdr; + TARGET_STATIC uint8_t decomp_buf[DECOMP_BUF_ALLOC_SIZE] __attribute__((aligned(4))); + TARGET_STATIC struct image_header modified_hdr; + uint16_t decomp_buf_max_size; + +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) + uint8_t unaligned_data_length = 0; +#endif + +#ifdef MCUBOOT_ENC_IMAGES + uint32_t comp_size = 0; + uint8_t decryption_block_size = 0; +#endif + + hdr = boot_img_hdr(state, BOOT_SLOT_SECONDARY); + +#ifdef MCUBOOT_ENC_IMAGES + rc = bootutil_get_img_decrypted_comp_size(hdr, fap_src, &comp_size); + + if (rc) { + BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); + rc = BOOT_EBADIMAGE; + goto finish; + } + + if (IS_ENCRYPTED(hdr)) { + if (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES128) { + decryption_block_size = DECRYPTION_BLOCK_SIZE_AES128; + } else if (hdr->ih_flags & IMAGE_F_ENCRYPTED_AES256) { + decryption_block_size = DECRYPTION_BLOCK_SIZE_AES256; + } + } +#endif + + /* Setup decompression system */ +#if CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA1 + if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA1)) { +#elif CONFIG_NRF_COMPRESS_LZMA_VERSION_LZMA2 + if (!(hdr->ih_flags & IMAGE_F_COMPRESSED_LZMA2)) { +#endif + /* Compressed image does not use the correct compression type which is supported by this + * build + */ + BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); + rc = BOOT_EBADIMAGE; + goto finish; + } + + compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); + compression_arm_thumb = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_ARM_THUMB); + + if (!is_compression_object_valid(compression_lzma) || + !is_compression_object_valid(compression_arm_thumb)) { + /* Compression library missing or missing required function pointer */ + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish; + } + + rc = compression_lzma->init(NULL); + rc = compression_arm_thumb->init(NULL); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish; + } + + write_alignment = flash_area_align(fap_dst); + + decomp_buf_max_size = DECOMP_BUF_SIZE - (DECOMP_BUF_SIZE % write_alignment); + + memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); + + rc = bootutil_get_img_decomp_size(hdr, fap_src, &decompressed_image_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); + rc = BOOT_EBADIMAGE; + goto finish; + } + + modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; + modified_hdr.ih_img_size = decompressed_image_size; + + /* Calculate protected TLV size for target image once items are removed */ + rc = boot_size_protected_tlvs(hdr, fap_src, &protected_tlv_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine protected TLV size of compressed image"); + rc = BOOT_EBADIMAGE; + goto finish; + } + + modified_hdr.ih_protect_tlv_size = protected_tlv_size; + + rc = boot_size_unprotected_tlvs(hdr, fap_src, &unprotected_tlv_size); + + if (rc) { + BOOT_LOG_ERR("Unable to determine unprotected TLV size of compressed image"); + rc = BOOT_EBADIMAGE; + goto finish; + } + + /* Write out the image header first, this should be a multiple of the write size */ + rc = flash_area_write(fap_dst, off_dst, &modified_hdr, sizeof(modified_hdr)); + + if (rc != 0) { + BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + off_dst, sizeof(modified_hdr), fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + + /* Read in, decompress and write out data */ +#ifdef MCUBOOT_ENC_IMAGES + while (pos < comp_size) { + uint32_t copy_size = comp_size - pos; +#else + while (pos < hdr->ih_img_size) { + uint32_t copy_size = hdr->ih_img_size - pos; +#endif + uint32_t tmp_off = 0; + + if (copy_size > buf_size) { + copy_size = buf_size; + } + + rc = flash_area_read(fap_src, off_src + hdr->ih_hdr_size + pos, buf, copy_size); + + if (rc != 0) { + BOOT_LOG_ERR("Flash read failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_src + hdr->ih_hdr_size + pos), copy_size, fap_src->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + +#ifdef MCUBOOT_ENC_IMAGES + if (IS_ENCRYPTED(hdr)) { + uint8_t dummy_bytes = 0; + + if ((copy_size % decryption_block_size)) { + dummy_bytes = decryption_block_size - (copy_size % decryption_block_size); + memset(&buf[copy_size], 0x00, dummy_bytes); + } + + boot_enc_decrypt(BOOT_CURR_ENC_SLOT(state, BOOT_SLOT_SECONDARY), pos, + (copy_size + dummy_bytes), (pos & 0xf), buf); + } +#endif + + /* Decompress data in chunks, writing it back with a larger write offset of the primary + * slot than read size of the secondary slot + */ + while (tmp_off < copy_size) { + uint32_t offset = 0; + uint32_t output_size = 0; + uint32_t chunk_size; + uint32_t compression_buffer_pos = 0; + uint8_t *output = NULL; + bool last_packet = false; + + chunk_size = compression_lzma->decompress_bytes_needed(NULL); + + if (chunk_size > (copy_size - tmp_off)) { + chunk_size = (copy_size - tmp_off); + } + +#ifdef MCUBOOT_ENC_IMAGES + if ((pos + tmp_off + chunk_size) >= comp_size) { +#else + if ((pos + tmp_off + chunk_size) >= hdr->ih_img_size) { +#endif + last_packet = true; + } + + rc = compression_lzma->decompress(NULL, &buf[tmp_off], chunk_size, last_packet, + &offset, &output, &output_size); + + if (rc) { + BOOT_LOG_ERR("Decompression error: %d", rc); + rc = BOOT_EBADSTATUS; + goto finish; + } + + /* Copy data to secondary buffer for writing out */ + while (output_size > 0) { + uint32_t data_size = (decomp_buf_max_size - decomp_buf_size); + + if (data_size > output_size) { + data_size = output_size; + } + +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) + if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { + memcpy(&decomp_buf[decomp_buf_size + DECOMP_BUF_EXTRA_SIZE], + &output[compression_buffer_pos], data_size); + } else +#endif + { + memcpy(&decomp_buf[decomp_buf_size], &output[compression_buffer_pos], + data_size); + } + + compression_buffer_pos += data_size; + + decomp_buf_size += data_size; + output_size -= data_size; + + /* Write data out from secondary buffer when it is full */ + if (decomp_buf_size == decomp_buf_max_size) { +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) + if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT) { + + uint32_t filter_output_size; + + /* Run this through the ARM thumb filter */ + rc = boot_arm_thumb_filter(compression_arm_thumb, + &decomp_buf[unaligned_data_length], + decomp_buf_size - unaligned_data_length + DECOMP_BUF_EXTRA_SIZE, + &filter_output_size, + last_packet && output_size == 0); + + if (rc) { + goto finish; + } + + decomp_buf_size = filter_output_size + unaligned_data_length; + unaligned_data_length = decomp_buf_size % write_alignment; + + rc = flash_area_write(fap_dst, + (off_dst + hdr->ih_hdr_size + write_pos), + decomp_buf, + (decomp_buf_size - unaligned_data_length)); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + hdr->ih_hdr_size + write_pos), + (decomp_buf_size - unaligned_data_length), + fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + + memmove(decomp_buf, + &decomp_buf[decomp_buf_size - unaligned_data_length], + unaligned_data_length); + write_pos += decomp_buf_size - unaligned_data_length; + decomp_buf_size = unaligned_data_length; + } else +#endif + { + rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), + decomp_buf, decomp_buf_max_size); + + if (rc != 0) { + BOOT_LOG_ERR( + "Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_max_size, + fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + + write_pos += decomp_buf_max_size; + decomp_buf_size = 0; + } + } + } + + tmp_off += offset; + } + + pos += copy_size; + } + +#if defined(CONFIG_NRF_COMPRESS_ARM_THUMB) + if (hdr->ih_flags & IMAGE_F_COMPRESSED_ARM_THUMB_FLT && decomp_buf_size > 0) { + /* Extra data that has not been written out that needs ARM thumb filter applied */ + + uint32_t filter_output_size; + + rc = boot_arm_thumb_filter(compression_arm_thumb, + &decomp_buf[unaligned_data_length], + decomp_buf_size - unaligned_data_length + DECOMP_BUF_EXTRA_SIZE, + &filter_output_size, + true); + + if (rc) { + goto finish; + } + + decomp_buf_size = filter_output_size + unaligned_data_length; + + if (decomp_buf_size > decomp_buf_max_size) { + /* It can happen if ARM thumb decompression returned +2 bytes and we had near full + * decomp_buf. We still can hold these additional 2 bytes because of + * DECOMP_BUF_EXTRA_SIZE allocated. */ + + rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), + decomp_buf, decomp_buf_max_size); + + if (rc != 0) { + BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_max_size, + fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + memmove(decomp_buf, &decomp_buf[decomp_buf_max_size], + (decomp_buf_size - decomp_buf_max_size)); + + decomp_buf_size = decomp_buf_size - decomp_buf_max_size; + write_pos += decomp_buf_max_size; + } + } +#endif + + /* Clean up decompression system */ + (void)compression_lzma->deinit(NULL); + (void)compression_arm_thumb->deinit(NULL); + + if (protected_tlv_size > 0) { + rc = boot_copy_protected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + + write_pos), protected_tlv_size, + decomp_buf, decomp_buf_max_size, &decomp_buf_size, + &tlv_write_size); + + if (rc) { + BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); + goto finish; + } + + write_pos += tlv_write_size; + } + + tlv_write_size = 0; + rc = boot_copy_unprotected_tlvs(hdr, fap_src, fap_dst, (off_dst + hdr->ih_hdr_size + + write_pos), unprotected_tlv_size, + decomp_buf, decomp_buf_max_size, &decomp_buf_size, + &tlv_write_size); + + if (rc) { + BOOT_LOG_ERR("Protected TLV copy failure: %d", rc); + goto finish; + } + + write_pos += tlv_write_size; + + /* Check if we have unwritten data buffered up and, if so, write it out */ + if (decomp_buf_size > 0) { + uint32_t write_padding_size = write_alignment - (decomp_buf_size % write_alignment); + + /* Check if additional write padding should be applied to meet the minimum write size */ + if (write_alignment > 1 && write_padding_size) { + uint8_t flash_erased_value; + + flash_erased_value = flash_area_erased_val(fap_dst); + memset(&decomp_buf[decomp_buf_size], flash_erased_value, write_padding_size); + decomp_buf_size += write_padding_size; + } + + rc = flash_area_write(fap_dst, (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf, + decomp_buf_size); + + if (rc != 0) { + BOOT_LOG_ERR("Flash write failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + (off_dst + hdr->ih_hdr_size + write_pos), decomp_buf_size, + fap_dst->fa_id, rc); + rc = BOOT_EFLASH; + goto finish; + } + + write_pos += decomp_buf_size; + decomp_buf_size = 0; + } + +finish: + memset(decomp_buf, 0, sizeof(decomp_buf)); + + return rc; +} + +int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct flash_area *fap, + uint32_t *img_decomp_size) +{ + struct image_tlv_iter it; + uint32_t off; + uint16_t len; + int32_t rc; + + if (hdr == NULL || fap == NULL || img_decomp_size == NULL) { + return BOOT_EBADARGS; + } else if (hdr->ih_protect_tlv_size == 0) { + return BOOT_EBADIMAGE; + } + + rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIZE, true); + + if (rc) { + return rc; + } + + rc = bootutil_tlv_iter_next(&it, &off, &len, NULL); + + if (rc != 0) { + return -1; + } + + if (len != sizeof(*img_decomp_size)) { + BOOT_LOG_ERR("Invalid decompressed image size TLV: %d", len); + return BOOT_EBADIMAGE; + } + + rc = LOAD_IMAGE_DATA(hdr, fap, off, img_decomp_size, len); + + if (rc) { + BOOT_LOG_ERR("Image data load failed at offset: 0x%x, size: 0x%x, area: %d, rc: %d", + off, len, fap->fa_id, rc); + return BOOT_EFLASH; + } + + return 0; +} diff --git a/boot/zephyr/include/compression/decompression.h b/boot/zephyr/include/compression/decompression.h new file mode 100644 index 000000000..2104c4eb6 --- /dev/null +++ b/boot/zephyr/include/compression/decompression.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef H_DECOMPRESSION_ +#define H_DECOMPRESSION_ + +#include +#include +#include +#include "bootutil/bootutil.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/image.h" +#include "../src/bootutil_priv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Checks if a compressed image header is valid. + * + * @param hdr Image header. + * @param fap Flash area of the slot. + * @param state Bootloader state object. + * + * @return true if valid; false if invalid. + */ +bool boot_is_compressed_header_valid(const struct image_header *hdr, const struct flash_area *fap, + struct boot_loader_state *state); + +/** + * Reads in compressed image data from a slot, decompresses it and writes it out to a destination + * slot, including corresponding image headers and TLVs. + * + * @param state Bootloader state object. + * @param fap_src Flash area of the source slot. + * @param fap_dst Flash area of the destination slot. + * @param off_src Offset of the source slot to read from (should be 0). + * @param off_dst Offset of the destination slot to write to (should be 0). + * @param sz Size of the source slot data. + * @param buf Temporary buffer for reading data from. + * @param buf_size Size of temporary buffer. + * + * @return 0 on success; nonzero on failure. + */ +int boot_copy_region_decompress(struct boot_loader_state *state, const struct flash_area *fap_src, + const struct flash_area *fap_dst, uint32_t off_src, + uint32_t off_dst, uint32_t sz, uint8_t *buf, size_t buf_size); + +/** + * Gets the total data size (excluding headers and TLVs) of a compressed image when it is + * decompressed. + * + * @param hdr Image header. + * @param fap Flash area of the slot. + * @param img_decomp_size Pointer to variable that will be updated with the decompressed image + * size. + * + * @return 0 on success; nonzero on failure. + */ +int bootutil_get_img_decomp_size(const struct image_header *hdr, const struct flash_area *fap, + uint32_t *img_decomp_size); + +/** + * Calculate MCUboot-compatible image hash of compressed image slot. + * + * @param state MCUboot state. + * @param hdr Image header. + * @param fap Flash area of the slot. + * @param tmp_buf Temporary buffer for reading data from. + * @param tmp_buf_sz Size of temporary buffer. + * @param hash_result Pointer to a variable that will be updated with the image hash. + * @param seed Not currently used, set to NULL. + * @param seed_len Not currently used, set to 0. + * + * @return 0 on success; nonzero on failure. + */ +int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_header *hdr, + const struct flash_area *fap, uint8_t *tmp_buf, + uint32_t tmp_buf_sz, uint8_t *hash_result, + uint8_t *seed, int seed_len); + +/** + * Calculates the size that the compressed image protected TLV section will occupy once the image + * has been decompressed. + * + * @param hdr Image header. + * @param fap Flash area of the slot. + * @param sz Pointer to variable that will be updated with the protected TLV size. + * + * @return 0 on success; nonzero on failure. + */ +int boot_size_protected_tlvs(const struct image_header *hdr, const struct flash_area *fap_src, + uint32_t *sz); + +#ifdef __cplusplus +} +#endif + +#endif /* H_DECOMPRESSION_ */ From 496e9f4516169b42590f9673292f565f9038fd78 Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Tue, 13 May 2025 13:33:22 +0200 Subject: [PATCH 134/149] [nrf noup] decompression: Align to changes in nrfcompress API This commit aligns to the changes in the nrfcompress API, which now enables the caller to provide the expected size of the decompressed image. ref: NCSDK-32340 Signed-off-by: Michal Kozikowski Signed-off-by: Dominik Ermel (cherry picked from commit 8900bdaf1dd401b08748d4141f1196520579f4fd) (cherry picked from commit 1efcec19d74e45296dc9a8c514c77873730d1a08) --- boot/zephyr/decompression.c | 65 ++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/boot/zephyr/decompression.c b/boot/zephyr/decompression.c index 384899922..5b161feb1 100644 --- a/boot/zephyr/decompression.c +++ b/boot/zephyr/decompression.c @@ -255,15 +255,6 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h goto finish_without_clean; } - rc = compression_lzma->init(NULL); - rc = compression_arm_thumb->init(NULL); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish_without_clean; - } - /* We need a modified header which has the updated sizes, start with the original header */ memcpy(&modified_hdr, hdr, sizeof(modified_hdr)); @@ -275,12 +266,28 @@ int bootutil_img_hash_decompress(struct boot_loader_state *state, struct image_h if (rc) { BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); rc = BOOT_EBADIMAGE; - goto finish; + goto finish_without_clean; } modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; modified_hdr.ih_img_size = decompressed_image_size; + rc = compression_lzma->init(NULL, decompressed_image_size); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish_without_clean; + } + + rc = compression_arm_thumb->init(NULL, decompressed_image_size); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish; + } + /* Calculate the protected TLV size, these will not include the decompressed * sha/size/signature entries */ @@ -1100,7 +1107,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Invalid/missing image decrypted compressed size value"); rc = BOOT_EBADIMAGE; - goto finish; + goto finish_without_clean; } if (IS_ENCRYPTED(hdr)) { @@ -1123,7 +1130,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl */ BOOT_LOG_ERR("Invalid image compression flags: no supported compression found"); rc = BOOT_EBADIMAGE; - goto finish; + goto finish_without_clean; } compression_lzma = nrf_compress_implementation_find(NRF_COMPRESS_TYPE_LZMA); @@ -1134,16 +1141,7 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl /* Compression library missing or missing required function pointer */ BOOT_LOG_ERR("Decompression library fatal error"); rc = BOOT_EBADSTATUS; - goto finish; - } - - rc = compression_lzma->init(NULL); - rc = compression_arm_thumb->init(NULL); - - if (rc) { - BOOT_LOG_ERR("Decompression library fatal error"); - rc = BOOT_EBADSTATUS; - goto finish; + goto finish_without_clean; } write_alignment = flash_area_align(fap_dst); @@ -1157,12 +1155,28 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl if (rc) { BOOT_LOG_ERR("Unable to determine decompressed size of compressed image"); rc = BOOT_EBADIMAGE; - goto finish; + goto finish_without_clean; } modified_hdr.ih_flags &= ~COMPRESSIONFLAGS; modified_hdr.ih_img_size = decompressed_image_size; + rc = compression_lzma->init(NULL, decompressed_image_size); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish_without_clean; + } + + rc = compression_arm_thumb->init(NULL, decompressed_image_size); + + if (rc) { + BOOT_LOG_ERR("Decompression library fatal error"); + rc = BOOT_EBADSTATUS; + goto finish; + } + /* Calculate protected TLV size for target image once items are removed */ rc = boot_size_protected_tlvs(hdr, fap_src, &protected_tlv_size); @@ -1457,6 +1471,11 @@ int boot_copy_region_decompress(struct boot_loader_state *state, const struct fl } finish: + /* Clean up decompression system */ + (void)compression_lzma->deinit(NULL); + (void)compression_arm_thumb->deinit(NULL); + +finish_without_clean: memset(decomp_buf, 0, sizeof(decomp_buf)); return rc; From df60648032e4b5899cb9669c8336fe9972e211d8 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 7 Nov 2024 10:53:06 +0000 Subject: [PATCH 135/149] [nrf noup] boot: zephyr: Add experimental selection to compression Adds selecting the experimental Kconfig when compession is in use Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 4a528baa162b14d44a95892340aa299525ee1b8b) (cherry picked from commit 4d4123bb5a508c8bfbb39301cab0c53e6ecfb84c) --- boot/zephyr/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 78fb6a59b..a2cbd0f78 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1237,9 +1237,10 @@ config BOOT_DECOMPRESSION_SUPPORT if BOOT_DECOMPRESSION_SUPPORT menuconfig BOOT_DECOMPRESSION - bool "Decompression" + bool "Decompression [EXPERIMENTAL]" select NRF_COMPRESS_CLEANUP select PM_USE_CONFIG_SRAM_SIZE if SOC_NRF54L15_CPUAPP + select EXPERIMENTAL help If enabled, will include support for compressed images being loaded to the secondary slot which then get decompressed into the primary slot. This mode allows the secondary slot to From f7f87cd01cfcb7962931f30d1f7bcc283edc9cd3 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 20 Sep 2024 16:34:00 +0000 Subject: [PATCH 136/149] [nrf noup] bootutil: Add support for KMU stored ED25519 signature key The commit adds verification of image using keys stored in KMU. Signed-off-by: Dominik Ermel (cherry picked from commit 26192ca1c9986dd9f50b9e5537bfc38fd2953128) (cherry picked from commit 6ba9587457e8b2b705528ffe6cc77435ae9df080) (cherry picked from commit d0cd58f1d7fceb6bbb7de0add810b652effb4b3b) --- boot/bootutil/src/ed25519_psa.c | 51 ++++++++++++++++++++++++++++++ boot/bootutil/src/image_ed25519.c | 9 +++++- boot/bootutil/src/image_validate.c | 11 +++++-- boot/zephyr/CMakeLists.txt | 2 +- boot/zephyr/Kconfig | 26 +++++++++++++++ 5 files changed, 95 insertions(+), 4 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 5b8a4ed7c..cd016158b 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -12,6 +12,9 @@ #include #include +#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +#include +#endif BOOT_LOG_MODULE_REGISTER(ed25519_psa); @@ -19,6 +22,18 @@ BOOT_LOG_MODULE_REGISTER(ed25519_psa); #define EDDSA_KEY_LENGTH 32 #define EDDSA_SIGNAGURE_LENGTH 64 +#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +/* List of KMU stored key ids available for MCUboot */ +#define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id) +static psa_key_id_t kmu_key_ids[3] = { + MAKE_PSA_KMU_KEY_ID(226), + MAKE_PSA_KMU_KEY_ID(228), + MAKE_PSA_KMU_KEY_ID(230) +}; +#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0])) +#endif + +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], const uint8_t public_key[EDDSA_KEY_LENGTH]) @@ -71,3 +86,39 @@ int ED25519_verify(const uint8_t *message, size_t message_len, return ret; } +#else +int ED25519_verify(const uint8_t *message, size_t message_len, + const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], + const uint8_t public_key[EDDSA_KEY_LENGTH]) +{ + ARG_UNUSED(public_key); + /* Set to any error */ + psa_status_t status = PSA_ERROR_BAD_STATE; + int ret = 0; /* Fail by default */ + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed %d", status); + return 0; + } + + status = PSA_ERROR_BAD_STATE; + + for (int i = 0; i < KMU_KEY_COUNT; ++i) { + psa_key_id_t kid = kmu_key_ids[i]; + + status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, + message_len, signature, + EDDSA_SIGNAGURE_LENGTH); + if (status == PSA_SUCCESS) { + ret = 1; + break; + } + + BOOT_LOG_ERR("ED25519 signature verification failed %d", status); + } + + return ret; +} +#endif diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 4d83bb3d7..1a02811e3 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -34,6 +34,7 @@ extern int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNATURE_LENGTH], const uint8_t public_key[NUM_ED25519_BYTES]); +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #if !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) /* * Parse the public key used for signing. @@ -76,6 +77,7 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) return 0; } #endif /* !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) */ +#endif /* Signature verification base function. * The function takes buffer of specified length and tries to verify @@ -90,8 +92,10 @@ bootutil_verify(uint8_t *buf, uint32_t blen, { int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); - uint8_t *pubkey; + uint8_t *pubkey = NULL; +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) uint8_t *end; +#endif BOOT_LOG_DBG("bootutil_verify: ED25519 key_id %d", (int)key_id); @@ -102,6 +106,7 @@ bootutil_verify(uint8_t *buf, uint32_t blen, goto out; } +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) pubkey = (uint8_t *)bootutil_keys[key_id].key; end = pubkey + *bootutil_keys[key_id].len; @@ -125,6 +130,8 @@ bootutil_verify(uint8_t *buf, uint32_t blen, } pubkey = end - NUM_ED25519_BYTES; +#endif + #endif rc = ED25519_verify(buf, blen, sig, pubkey); diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 0f50a87d5..d3c28fa3f 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -121,6 +121,7 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); # define EXPECTED_KEY_TLV IMAGE_TLV_PUBKEY # define KEY_BUF_SIZE (SIG_BUF_SIZE + 24) #endif /* !MCUBOOT_HW_KEY */ + #endif /* !MCUBOOT_BUILTIN_KEY */ #endif /* EXPECTED_SIG_TLV */ @@ -507,6 +508,7 @@ bootutil_img_validate(struct boot_loader_state *state, break; } #endif /* defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) */ +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #ifdef EXPECTED_KEY_TLV case EXPECTED_KEY_TLV: { @@ -538,15 +540,18 @@ bootutil_img_validate(struct boot_loader_state *state, break; } #endif /* EXPECTED_KEY_TLV */ +#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #ifdef EXPECTED_SIG_TLV case EXPECTED_SIG_TLV: { BOOT_LOG_DBG("bootutil_img_validate: EXPECTED_SIG_TLV == %d", EXPECTED_SIG_TLV); +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } +#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; goto out; @@ -838,7 +843,7 @@ bootutil_img_validate(struct boot_loader_state *state, } #ifdef EXPECTED_SIG_TLV -#ifdef EXPECTED_KEY_TLV +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && defined(EXPECTED_KEY_TLV) rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_KEY_TLV, false); if (rc) { goto out; @@ -884,7 +889,7 @@ bootutil_img_validate(struct boot_loader_state *state, */ } } -#endif /* EXPECTED_KEY_TLV */ +#endif /* !CONFIG_BOOT_SIGNATURE_USING_KMU && EXPECTED_KEY_TLV */ rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_DECOMP_SIGNATURE, true); if (rc) { @@ -907,10 +912,12 @@ bootutil_img_validate(struct boot_loader_state *state, if (type == IMAGE_TLV_DECOMP_SIGNATURE) { /* Ignore this signature if it is out of bounds. */ +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } +#endif if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index c1974d7a1..d92f3fe5a 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -383,7 +383,7 @@ if(CONFIG_MCUBOOT_SERIAL) endif() endif() -if(NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") +if(NOT CONFIG_BOOT_SIGNATURE_USING_KMU AND NOT CONFIG_BOOT_SIGNATURE_KEY_FILE STREQUAL "") # CONF_FILE points to the KConfig configuration files of the bootloader. foreach (filepath ${CONF_FILE}) file(READ ${filepath} temp_text) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index a2cbd0f78..7555e5058 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -397,6 +397,22 @@ config BOOT_BYPASS_KEY_MATCH Enabling this option turns off key matching, slightly reducing MCUboot code and boot time. +config BOOT_SIGNATURE_USING_KMU + bool "Use KMU stored keys for signature verification" + depends on NRF_SECURITY + depends on CRACEN_LIB_KMU + select PSA_WANT_ALG_GCM + select PSA_WANT_KEY_TYPE_AES + select PSA_WANT_AES_KEY_SIZE_256 + select PSA_WANT_ALG_SP800_108_COUNTER_CMAC + select PSA_WANT_ALG_CMAC + select PSA_WANT_ALG_ECB_NO_PADDING + help + MCUboot will use keys provisioned to the device key management unit for signature + verification instead of compiling in key data from a file. + +if !BOOT_SIGNATURE_USING_KMU + config BOOT_SIGNATURE_KEY_FILE string "PEM key file" default "root-ec-p256.pem" if BOOT_SIGNATURE_TYPE_ECDSA_P256 @@ -414,6 +430,8 @@ config BOOT_SIGNATURE_KEY_FILE with the public key information will be written in a format expected by MCUboot. +endif + config MCUBOOT_CLEANUP_ARM_CORE bool "Perform core cleanup before chain-load the application" depends on CPU_CORTEX_M || ARMV7_R @@ -456,6 +474,14 @@ config MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP Verification option that keeps execution in infinite loop after RAM cleanup has been performed. +# Disable MBEDTLS from being selected if NRF_SECURITY is enabled, and use default NRF_SECURITY +# configuration file for MBEDTLS +config MBEDTLS + depends on !NRF_SECURITY + +config NRF_SECURITY + select MBEDTLS_PROMPTLESS + config MBEDTLS_CFG_FILE # It might be awkward to define an Mbed TLS header file when TinyCrypt # is used, but the fact is that Mbed TLS' ASN1 parse module is used From 15cc89a2b0844f9a7202f0d1c27dcb70ee65b01d Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 2 Dec 2024 10:51:41 +0000 Subject: [PATCH 137/149] [nrf noup] boot: bootutil: Allow configuring number of KMU keys Adds a new Kconfig CONFIG_BOOT_SIGNATURE_KMU_SLOTS which allows specifying how many KMU key IDs are supported, the default is set to 1 instead of 3 which was set before NCSDK-30743 Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 83d1d959de612b8bc17dae56355b0ccc40cebde6) (cherry picked from commit 37df88a122d6c12eaae322ba4ec9efca067741bf) --- boot/bootutil/src/ed25519_psa.c | 7 +++++-- boot/zephyr/Kconfig | 12 ++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index cd016158b..7665e4067 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -12,6 +12,7 @@ #include #include +#include #if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #include #endif @@ -30,7 +31,9 @@ static psa_key_id_t kmu_key_ids[3] = { MAKE_PSA_KMU_KEY_ID(228), MAKE_PSA_KMU_KEY_ID(230) }; -#define KMU_KEY_COUNT (sizeof(kmu_key_ids)/sizeof(kmu_key_ids[0])) + +BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(kmu_key_ids), + "Invalid number of KMU slots, up to 3 are supported on nRF54L15"); #endif #if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) @@ -105,7 +108,7 @@ int ED25519_verify(const uint8_t *message, size_t message_len, status = PSA_ERROR_BAD_STATE; - for (int i = 0; i < KMU_KEY_COUNT; ++i) { + for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; ++i) { psa_key_id_t kid = kmu_key_ids[i]; status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 7555e5058..a76b9a53a 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -411,6 +411,18 @@ config BOOT_SIGNATURE_USING_KMU MCUboot will use keys provisioned to the device key management unit for signature verification instead of compiling in key data from a file. +if BOOT_SIGNATURE_USING_KMU + +config BOOT_SIGNATURE_KMU_SLOTS + int "KMU key slots" + range 1 3 + default 1 + help + Selects the number of KMU key slots (also known as generations) to use when verifying + an image. + +endif + if !BOOT_SIGNATURE_USING_KMU config BOOT_SIGNATURE_KEY_FILE From 3a044cf1adf5e03b4005fe37042ac23299ac3585 Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Mon, 17 Mar 2025 21:25:41 +0100 Subject: [PATCH 138/149] [nrf noup] bootutil: key revocation Disable previous generation key when update comes with new valid key and application is confirmed. Signed-off-by: Mateusz Michalek Signed-off-by: Dominik Ermel (cherry picked from commit 51b0897bc30cf6cf5a33127bdd5501e59d051499) (cherry picked from commit 08e2009fbcdbcb8292cdb8bd62332f656443d170) --- .../include/bootutil/key_revocation.h | 30 ++++++++++++++ boot/bootutil/src/ed25519_psa.c | 41 +++++++++++++++++++ boot/bootutil/src/key_revocation.c | 24 +++++++++++ boot/bootutil/src/loader.c | 16 ++++++++ boot/zephyr/CMakeLists.txt | 6 +++ boot/zephyr/Kconfig | 12 ++++++ 6 files changed, 129 insertions(+) create mode 100644 boot/bootutil/include/bootutil/key_revocation.h create mode 100644 boot/bootutil/src/key_revocation.c diff --git a/boot/bootutil/include/bootutil/key_revocation.h b/boot/bootutil/include/bootutil/key_revocation.h new file mode 100644 index 000000000..d184c9579 --- /dev/null +++ b/boot/bootutil/include/bootutil/key_revocation.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef H_KEY_REVOCATION_ +#define H_KEY_REVOCATION_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BOOT_KEY_REVOKE_OK 0 +#define BOOT_KEY_REVOKE_NOT_READY 1 +#define BOOT_KEY_REVOKE_INVALID 2 +#define BOOT_KEY_REVOKE_FAILED 2 + + +void allow_revoke(void); + +int revoke(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 7665e4067..6393d996e 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -32,6 +32,11 @@ static psa_key_id_t kmu_key_ids[3] = { MAKE_PSA_KMU_KEY_ID(230) }; +#if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) +#include +static psa_key_id_t *validated_with = NULL; +#endif + BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(kmu_key_ids), "Invalid number of KMU slots, up to 3 are supported on nRF54L15"); #endif @@ -116,6 +121,9 @@ int ED25519_verify(const uint8_t *message, size_t message_len, EDDSA_SIGNAGURE_LENGTH); if (status == PSA_SUCCESS) { ret = 1; +#if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) + validated_with = kmu_key_ids + i; +#endif break; } @@ -124,4 +132,37 @@ int ED25519_verify(const uint8_t *message, size_t message_len, return ret; } +#if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) +int exec_revoke(void) +{ + int ret = BOOT_KEY_REVOKE_OK; + psa_status_t status = psa_crypto_init(); + + if (!validated_with) { + ret = BOOT_KEY_REVOKE_INVALID; + goto out; + } + + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed with error %d", status); + ret = BOOT_KEY_REVOKE_FAILED; + goto out; + } + for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; i++) { + if ((kmu_key_ids + i) == validated_with) { + break; + } + BOOT_LOG_DBG("Invalidating key ID %d", i); + + status = psa_destroy_key(kmu_key_ids[i]); + if (status == PSA_SUCCESS) { + BOOT_LOG_DBG("Success on key ID %d", i); + } else { + BOOT_LOG_ERR("Key invalidation failed with: %d", status); + } + } +out: + return ret; +} +#endif /* CONFIG_BOOT_KMU_KEYS_REVOCATION */ #endif diff --git a/boot/bootutil/src/key_revocation.c b/boot/bootutil/src/key_revocation.c new file mode 100644 index 000000000..0768a3188 --- /dev/null +++ b/boot/bootutil/src/key_revocation.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include + +extern int exec_revoke(void); + +static uint8_t ready_to_revoke; + +void allow_revoke(void) +{ + ready_to_revoke = 1; +} + +int revoke(void) +{ + if (ready_to_revoke) { + return exec_revoke(); + } + return BOOT_KEY_REVOKE_NOT_READY; +} diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 26e3d95ca..560364376 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -80,6 +80,10 @@ int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); #include "mcuboot_config/mcuboot_config.h" +#if defined(CONFIG_BOOT_KEYS_REVOCATION) +#include "bootutil/key_revocation.h" +#endif + BOOT_LOG_MODULE_DECLARE(mcuboot); static struct boot_loader_state boot_data; @@ -2304,6 +2308,11 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } } +#if defined(CONFIG_BOOT_KEYS_REVOCATION) + if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) { + allow_revoke(); + } +#endif /* Iterate over all the images. At this point all required update operations * have finished. By the end of the loop each image in the primary slot will * have been re-validated. @@ -2412,6 +2421,13 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) fill_rsp(state, rsp); fih_rc = FIH_SUCCESS; +#if defined(CONFIG_BOOT_KEYS_REVOCATION) + rc = revoke(); + if (rc != BOOT_KEY_REVOKE_OK && + rc != BOOT_KEY_REVOKE_NOT_READY) { + FIH_SET(fih_rc, FIH_FAILURE); + } +#endif /* CONFIG_BOOT_KEYS_REVOCATION */ out: /* * Since the boot_status struct stores plaintext encryption keys, reset diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index d92f3fe5a..eb958425e 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -101,6 +101,12 @@ if(DEFINED CONFIG_BOOT_SHARE_BACKEND_RETENTION) ) endif() +if(DEFINED CONFIG_BOOT_KEYS_REVOCATION) + zephyr_library_sources( + ${BOOT_DIR}/bootutil/src/key_revocation.c +) +endif() + # Generic bootutil sources and includes. zephyr_library_include_directories(${BOOT_DIR}/bootutil/include) zephyr_library_sources( diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index a76b9a53a..9cc0f74b6 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -423,6 +423,18 @@ config BOOT_SIGNATURE_KMU_SLOTS endif +config BOOT_KEYS_REVOCATION + bool "Auto revoke previous gen key" + help + Automatically revoke previous generation key upon new valid key usage. + +config BOOT_KMU_KEYS_REVOCATION + bool + depends on BOOT_KEYS_REVOCATION + default y if BOOT_SIGNATURE_USING_KMU + help + Enabling KMU key revocation backend. + if !BOOT_SIGNATURE_USING_KMU config BOOT_SIGNATURE_KEY_FILE From 55a4637dd990c1b5f84a1d78264401417d0f6d16 Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Thu, 24 Jul 2025 13:31:00 +0200 Subject: [PATCH 139/149] [nrf noup] Added BOOT_SIGNATURE_USING_ITS for ecdsa configuration This configuration has the purpose of using keys provisioned to the internal trusted storage (ITS). It makes use of the already existing parts of code for MCUBOOT_BUILTIN_KEY Signed-off-by: Artur Hadasz Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 7ed49272a2f00e3e0936c333f2a0240e99226963) (cherry picked from commit e2bfd22d374aa91decc2d4d44b9dfde9bbb94213) --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 50 +++++++++++++++++++ boot/zephyr/Kconfig | 9 +++- .../include/mcuboot_config/mcuboot_config.h | 4 ++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index cbbff1783..7fc5474e2 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -475,6 +475,7 @@ static int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, } #endif /* !MCUBOOT_BUILTIN_KEY */ +#if !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) /* Verify the signature against the provided hash. The signature gets parsed from * the encoding first, then PSA Crypto has a dedicated API for ECDSA verification */ @@ -493,6 +494,55 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, return (int) psa_verify_hash(ctx->key_id, PSA_ALG_ECDSA(ctx->required_algorithm), hash, hlen, reformatted_signature, 2*ctx->curve_byte_count); } +#else /* !CONFIG_NCS_BOOT_SIGNATURE_USING_ITS */ + +static const psa_key_id_t builtin_key_ids[] = { + 0x40022100, + 0x40022101, + 0x40022102, + 0x40022103 +}; + +#define BOOT_SIGNATURE_BUILTIN_KEY_SLOTS ARRAY_SIZE(builtin_key_ids) + +static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, + uint8_t *pk, size_t pk_len, + uint8_t *hash, size_t hlen, + uint8_t *sig, size_t slen) +{ + (void)pk; + (void)pk_len; + (void)slen; + psa_status_t status = PSA_ERROR_BAD_STATE; + + /* Initialize PSA Crypto */ + status = psa_crypto_init(); + if (status != PSA_SUCCESS) { + BOOT_LOG_ERR("PSA crypto init failed %d", status); + return 1; + } + + uint8_t reformatted_signature[96] = {0}; /* Enough for P-384 signature sizes */ + parse_signature_from_rfc5480_encoding(sig, ctx->curve_byte_count, reformatted_signature); + + status = PSA_ERROR_BAD_STATE; + + for (int i = 0; i < BOOT_SIGNATURE_BUILTIN_KEY_SLOTS; ++i) { + psa_key_id_t kid = builtin_key_ids[i]; + + status = psa_verify_hash(kid, PSA_ALG_ECDSA(ctx->required_algorithm), + hash, hlen, reformatted_signature, 2*ctx->curve_byte_count); + if (status == PSA_SUCCESS) { + break; + } + BOOT_LOG_ERR("ECDSA signature verification failed %d", status); + } + + return status == PSA_SUCCESS ? 0 : 2; +} + +#endif /* !CONFIG_NCS_BOOT_SIGNATURE_USING_ITS */ + #elif defined(MCUBOOT_USE_MBED_TLS) typedef mbedtls_ecdsa_context bootutil_ecdsa_context; diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 9cc0f74b6..4ce3423ce 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -435,7 +435,14 @@ config BOOT_KMU_KEYS_REVOCATION help Enabling KMU key revocation backend. -if !BOOT_SIGNATURE_USING_KMU +config NCS_BOOT_SIGNATURE_USING_ITS + bool "Use ITS stored keys for signature verification" + depends on NRF_SECURITY + help + MCUboot will use keys provisioned to the internal trusted storage for signature + verification instead of compiling in key data from a file. + +if !BOOT_SIGNATURE_USING_KMU && !NCS_BOOT_SIGNATURE_USING_ITS config BOOT_SIGNATURE_KEY_FILE string "PEM key file" diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 4c192ca8e..c7e380937 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -68,6 +68,10 @@ #define MCUBOOT_HW_KEY #endif +#ifdef CONFIG_NCS_BOOT_SIGNATURE_USING_ITS +#define MCUBOOT_BUILTIN_KEY +#endif + #ifdef CONFIG_BOOT_VALIDATE_SLOT0 #define MCUBOOT_VALIDATE_PRIMARY_SLOT #endif From 5f54788235b026343f3a6398f0dddbfcfdcc5ae9 Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Fri, 22 Aug 2025 12:59:08 +0200 Subject: [PATCH 140/149] [nrf noup] Support for ed25519 signature verification using ITS Thic commit introduces support for ed25519 signature verification when CONFIG_NCS_BOOT_SIGNATURE_USING_ITS is set (through PSA API). Signed-off-by: Michal Kozikowski (cherry picked from commit 227eb0a50d1b1fa52f853b2cc4ff1e8cca4bbf71) (cherry picked from commit 335b6df85c2da36dd985b342456a7add5a35b564) --- boot/bootutil/src/ed25519_psa.c | 38 ++++++++++++++++++++---------- boot/bootutil/src/image_ed25519.c | 6 +++-- boot/bootutil/src/image_validate.c | 6 ++--- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 6393d996e..8460da7c8 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -26,22 +26,35 @@ BOOT_LOG_MODULE_REGISTER(ed25519_psa); #if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) /* List of KMU stored key ids available for MCUboot */ #define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id) -static psa_key_id_t kmu_key_ids[3] = { +static psa_key_id_t key_ids[] = { MAKE_PSA_KMU_KEY_ID(226), MAKE_PSA_KMU_KEY_ID(228), MAKE_PSA_KMU_KEY_ID(230) }; +#define KEY_SLOTS_COUNT CONFIG_BOOT_SIGNATURE_KMU_SLOTS + #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) #include static psa_key_id_t *validated_with = NULL; #endif -BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(kmu_key_ids), +BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(key_ids), "Invalid number of KMU slots, up to 3 are supported on nRF54L15"); #endif -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +#if defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) +static const psa_key_id_t key_ids[] = { + 0x40022100, + 0x40022101, + 0x40022102, + 0x40022103 +}; + +#define KEY_SLOTS_COUNT ARRAY_SIZE(key_ids) +#endif + +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) int ED25519_verify(const uint8_t *message, size_t message_len, const uint8_t signature[EDDSA_SIGNAGURE_LENGTH], const uint8_t public_key[EDDSA_KEY_LENGTH]) @@ -102,7 +115,6 @@ int ED25519_verify(const uint8_t *message, size_t message_len, ARG_UNUSED(public_key); /* Set to any error */ psa_status_t status = PSA_ERROR_BAD_STATE; - int ret = 0; /* Fail by default */ /* Initialize PSA Crypto */ status = psa_crypto_init(); @@ -113,24 +125,24 @@ int ED25519_verify(const uint8_t *message, size_t message_len, status = PSA_ERROR_BAD_STATE; - for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; ++i) { - psa_key_id_t kid = kmu_key_ids[i]; + for (int i = 0; i < KEY_SLOTS_COUNT; ++i) { + psa_key_id_t kid = key_ids[i]; status = psa_verify_message(kid, PSA_ALG_PURE_EDDSA, message, message_len, signature, EDDSA_SIGNAGURE_LENGTH); if (status == PSA_SUCCESS) { - ret = 1; #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) - validated_with = kmu_key_ids + i; + validated_with = key_ids + i; #endif - break; + return 1; } - BOOT_LOG_ERR("ED25519 signature verification failed %d", status); } - return ret; + BOOT_LOG_ERR("ED25519 signature verification failed %d", status); + + return 0; } #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) int exec_revoke(void) @@ -149,12 +161,12 @@ int exec_revoke(void) goto out; } for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; i++) { - if ((kmu_key_ids + i) == validated_with) { + if ((key_ids + i) == validated_with) { break; } BOOT_LOG_DBG("Invalidating key ID %d", i); - status = psa_destroy_key(kmu_key_ids[i]); + status = psa_destroy_key(key_ids[i]); if (status == PSA_SUCCESS) { BOOT_LOG_DBG("Success on key ID %d", i); } else { diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index 1a02811e3..177550749 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -36,6 +36,7 @@ extern int ED25519_verify(const uint8_t *message, size_t message_len, #if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) #if !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) +#if !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) /* * Parse the public key used for signing. */ @@ -78,6 +79,7 @@ bootutil_import_key(uint8_t **cp, uint8_t *end) } #endif /* !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) */ #endif +#endif /* Signature verification base function. * The function takes buffer of specified length and tries to verify @@ -93,7 +95,7 @@ bootutil_verify(uint8_t *buf, uint32_t blen, int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); uint8_t *pubkey = NULL; -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) uint8_t *end; #endif @@ -106,7 +108,7 @@ bootutil_verify(uint8_t *buf, uint32_t blen, goto out; } -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) pubkey = (uint8_t *)bootutil_keys[key_id].key; end = pubkey + *bootutil_keys[key_id].len; diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index d3c28fa3f..954b233af 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -545,13 +545,13 @@ bootutil_img_validate(struct boot_loader_state *state, case EXPECTED_SIG_TLV: { BOOT_LOG_DBG("bootutil_img_validate: EXPECTED_SIG_TLV == %d", EXPECTED_SIG_TLV); -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; } -#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ +#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) */ if (!EXPECTED_SIG_LEN(len) || len > sizeof(buf)) { rc = -1; goto out; @@ -912,7 +912,7 @@ bootutil_img_validate(struct boot_loader_state *state, if (type == IMAGE_TLV_DECOMP_SIGNATURE) { /* Ignore this signature if it is out of bounds. */ -#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +#if !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) && !defined(CONFIG_NCS_BOOT_SIGNATURE_USING_ITS) if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; continue; From 5960e00810b556682763d82a114f56c9785690de Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 3 Jul 2025 17:50:21 +0000 Subject: [PATCH 141/149] [nrf noup] bootutil: Locking KMU keys Lock KMU keys before passing execution to application. Signed-off-by: Dominik Ermel (cherry picked from commit b6b46a782d503cc52b41672e096fb526daaac31c) (cherry picked from commit cb297debeee5a5878c3e3be1b2466ba63772253b) --- boot/bootutil/src/ed25519_psa.c | 27 +++++++++++++++++++++++++++ boot/zephyr/include/nrf_cleanup.h | 11 +++++++++++ boot/zephyr/main.c | 7 +++++++ 3 files changed, 45 insertions(+) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 8460da7c8..3df1acbdd 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -177,4 +177,31 @@ int exec_revoke(void) return ret; } #endif /* CONFIG_BOOT_KMU_KEYS_REVOCATION */ + +void nrf_crypto_keys_housekeeping(void) +{ + psa_status_t status; + + /* We will continue through all keys, even if we have error while + * processing any of it. Only doing BOOT_LOG_DBG, as we do not + * really want to inform on failures to lock. + */ + for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; ++i) { + psa_key_attributes_t attr; + + status = psa_get_key_attributes(key_ids[i], &attr); + BOOT_LOG_DBG("KMU key 0x%x(%d) attr query status == %d", + key_ids[i], i, status); + + if (status == PSA_SUCCESS) { + status = cracen_kmu_block(&attr); + BOOT_LOG_DBG("KMU key lock status == %d", status); + } + + status = psa_purge_key(key_ids[i]); + BOOT_LOG_DBG("KMU key 0x%x(%d) purge status == %d", + key_ids[i], i, status); + } +} + #endif diff --git a/boot/zephyr/include/nrf_cleanup.h b/boot/zephyr/include/nrf_cleanup.h index 9e87e13f5..8cd8fe377 100644 --- a/boot/zephyr/include/nrf_cleanup.h +++ b/boot/zephyr/include/nrf_cleanup.h @@ -21,4 +21,15 @@ void nrf_cleanup_peripheral(void); */ void nrf_cleanup_ns_ram(void); +/** + * Crypto key storage housekeeping. Intended to clean up key objects from + * crypto backend and apply key policies that should take effect after + * MCUboot no longer needs access to keys. + */ +#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) +extern void nrf_crypto_keys_housekeeping(void); +#else +#define nrf_crypto_keys_housekeeping() do {} while (0) +#endif + #endif diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 93e00060a..ad36a60a2 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -894,6 +894,13 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND); + /* From this point MCUboot does not need access to crypto keys. + * Clean up backend key objects and apply key access policies that + * will take effect from now through entire boot session and application + * run. + */ + nrf_crypto_keys_housekeeping(); + #if USE_PARTITION_MANAGER && CONFIG_FPROTECT #ifdef PM_S1_ADDRESS From d2d0527d5629dae2579eb0b5a8b095931b70c699 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Tue, 30 Sep 2025 14:25:29 +0200 Subject: [PATCH 142/149] [nrf noup] bootutil/loader: integrate nRF54h S2RAM with diect-xip Added call which designate active slot so MCUBoot can jump to proper slot when CPU is resuming from S2RAM. Signed-off-by: Andrzej Puzdrowski (cherry picked from commit 1c8a5953c5411bb1e453c3747a4d13ac0680ff14) --- boot/bootutil/src/loader.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 560364376..5fe219e3c 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -84,6 +84,10 @@ int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); #include "bootutil/key_revocation.h" #endif +#ifdef CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE +void s2ram_designate_slot(uint8_t slot); +#endif + BOOT_LOG_MODULE_DECLARE(mcuboot); static struct boot_loader_state boot_data; @@ -2900,6 +2904,11 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } } +#ifdef CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE + /* Designate the slot to be used by the PM_S2RAM resume module */ + s2ram_designate_slot((uint8_t)state->slot_usage[0].active_slot); +#endif + /* All image loaded successfully. */ #ifdef MCUBOOT_HAVE_LOGGING print_loaded_images(state); From d8e55827e7173d6c57cb99200edb2464aed08c2c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Fri, 12 Sep 2025 11:09:19 +0100 Subject: [PATCH 143/149] [nrf noup] bootutil: Use correct set of KMU key slots nrf-squash! [nrf noup] bootutil: Add support for KMU stored ED25519 signature key Will instead use the immutable bootloader key slot IDs if b0 is not enabled, adds a Kconfig which can be used to fall back to the previous slot IDs for previously deployed bootloaders Signed-off-by: Jamie McCrae (cherry picked from commit 754f9586875dd72de367704e42c2121eb60696c3) --- boot/bootutil/src/ed25519_psa.c | 15 ++++++++++++--- boot/zephyr/Kconfig | 11 +++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 3df1acbdd..c7e3910b1 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -25,11 +25,20 @@ BOOT_LOG_MODULE_REGISTER(ed25519_psa); #if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) /* List of KMU stored key ids available for MCUboot */ +#define PSA_KEY_INDEX_SIZE 2 + +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 || \ + defined(CONFIG_NCS_BOOT_SIGNATURE_KMU_UROT_MAPPING) +#define PSA_KEY_STARTING_ID 226 +#else +#define PSA_KEY_STARTING_ID 242 +#endif + #define MAKE_PSA_KMU_KEY_ID(id) PSA_KEY_HANDLE_FROM_CRACEN_KMU_SLOT(CRACEN_KMU_KEY_USAGE_SCHEME_RAW, id) static psa_key_id_t key_ids[] = { - MAKE_PSA_KMU_KEY_ID(226), - MAKE_PSA_KMU_KEY_ID(228), - MAKE_PSA_KMU_KEY_ID(230) + MAKE_PSA_KMU_KEY_ID(PSA_KEY_STARTING_ID), + MAKE_PSA_KMU_KEY_ID(PSA_KEY_STARTING_ID + PSA_KEY_INDEX_SIZE), + MAKE_PSA_KMU_KEY_ID(PSA_KEY_STARTING_ID + (2 * PSA_KEY_INDEX_SIZE)) }; #define KEY_SLOTS_COUNT CONFIG_BOOT_SIGNATURE_KMU_SLOTS diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 4ce3423ce..e4bf00bba 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -421,6 +421,17 @@ config BOOT_SIGNATURE_KMU_SLOTS Selects the number of KMU key slots (also known as generations) to use when verifying an image. +config NCS_BOOT_SIGNATURE_KMU_UROT_MAPPING + bool "Use original mapping [DEPRECATED]" + depends on SOC_SERIES_NRF54LX + depends on MCUBOOT_MCUBOOT_IMAGE_NUMBER = -1 + select DEPRECATED + help + When this option is enabled, it will use the UROT_PUBKEY key slot IDs for the MCUboot + image which are assigned for the non-immutable bootloader IDs, otherwise it will use + the key set for the mode that MCUboot is used in (non-immutable slots when b0 is + enabled, or immutable slots when b0 is not enabled). + endif config BOOT_KEYS_REVOCATION From c9a0ff8c7430ad38bc237d95eb8eab598bd23ee8 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 18 Sep 2025 15:56:42 +0200 Subject: [PATCH 144/149] [nrf noup] boot/zephyr: improve S2RAM resume support using dedicated API nrf-squash! [nrf noup] boot/zephyr: nRF54h20 resume from S2RAM (hardened) CONFIG_ARM_SOC_START_HOOK=y allow to rework the resume from S2RAM code to work without PM_S2RAM mocking. It allows to implement only what really needed from the MCUboot perspective. Signed-off-by: Andrzej Puzdrowski (cherry picked from commit dd353bcef4b90e0aa93cf12b7fec880e048f640e) --- boot/bootutil/src/loader.c | 4 +-- boot/zephyr/CMakeLists.txt | 3 +- boot/zephyr/nrf54h20_custom_s2ram.S | 43 +++++++++++++++++++++++++++++ boot/zephyr/nrf54h20_custom_s2ram.c | 17 ++---------- 4 files changed, 49 insertions(+), 18 deletions(-) create mode 100644 boot/zephyr/nrf54h20_custom_s2ram.S diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 5fe219e3c..7feafbbbe 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -84,7 +84,7 @@ int pcd_version_cmp_net(const struct flash_area *fap, struct image_header *hdr); #include "bootutil/key_revocation.h" #endif -#ifdef CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE +#ifdef CONFIG_SOC_EARLY_RESET_HOOK void s2ram_designate_slot(uint8_t slot); #endif @@ -2904,7 +2904,7 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) } } -#ifdef CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE +#ifdef CONFIG_SOC_EARLY_RESET_HOOK /* Designate the slot to be used by the PM_S2RAM resume module */ s2ram_designate_slot((uint8_t)state->slot_usage[0].active_slot); #endif diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index eb958425e..1b10d65f9 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -518,7 +518,8 @@ if(CONFIG_MCUBOOT_CLEANUP_ARM_CORE) ) endif() -if(CONFIG_SOC_NRF54H20_PM_S2RAM_OVERRIDE) +if(CONFIG_SOC_EARLY_RESET_HOOK) + zephyr_library_sources(${BOOT_DIR}/zephyr/nrf54h20_custom_s2ram.S) zephyr_library_sources(${BOOT_DIR}/zephyr/nrf54h20_custom_s2ram.c) endif() diff --git a/boot/zephyr/nrf54h20_custom_s2ram.S b/boot/zephyr/nrf54h20_custom_s2ram.S new file mode 100644 index 000000000..1ffa17f42 --- /dev/null +++ b/boot/zephyr/nrf54h20_custom_s2ram.S @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief ARM Cortex-M suspend-to-RAM resume intermediary code (S2RAM) + */ + + + +/* + * resume or + * reboot reboot==T + *[S2RAM sleep]---------->[ boot (reset.S) ]---->[soc_early_reset_hook]---------->[regular boot] + * | + * | resume==T + * \/ + * [jump to well-known] + * [ App reset vector ] + */ + + + +#include +#include + +GTEXT(pm_s2ram_mark_check_and_mediate) + +GTEXT(soc_early_reset_hook) +SECTION_FUNC(TEXT, soc_early_reset_hook) +#if DT_NODE_EXISTS(DT_NODELABEL(pm_s2ram_stack)) &&\ + DT_NODE_HAS_COMPAT(DT_NODELABEL(pm_s2ram_stack), zephyr_memory_region) + ldr r0, =DT_REG_ADDR(DT_NODELABEL(pm_s2ram_stack)) + DT_REG_SIZE(DT_NODELABEL(pm_s2ram_stack)) +#else +#error "The support of bridge for S2RAM resume requires dedicated small stack" +#endif + msr msp, r0 + push {r0, lr} + bl pm_s2ram_mark_check_and_mediate + pop {r0, pc} diff --git a/boot/zephyr/nrf54h20_custom_s2ram.c b/boot/zephyr/nrf54h20_custom_s2ram.c index 51146e7b3..faa8d9b46 100644 --- a/boot/zephyr/nrf54h20_custom_s2ram.c +++ b/boot/zephyr/nrf54h20_custom_s2ram.c @@ -45,17 +45,6 @@ void s2ram_designate_slot(uint8_t slot) } #endif -int soc_s2ram_suspend(pm_s2ram_system_off_fn_t system_off) -{ - (void)(system_off); - return -1; -} - -void pm_s2ram_mark_set(void) -{ - /* empty */ -} - struct arm_vector_table { uint32_t msp; uint32_t reset; @@ -66,13 +55,13 @@ struct arm_vector_table { */ #define APP_EXE_START_OFFSET 0x800 /* nRF54H20 */ -bool pm_s2ram_mark_check_and_clear(void) +void pm_s2ram_mark_check_and_mediate(void) { uint32_t reset_reason = nrf_resetinfo_resetreas_local_get(NRF_RESETINFO); if (reset_reason != NRF_RESETINFO_RESETREAS_LOCAL_UNRETAINED_MASK) { /* Normal boot */ - return false; + return; } /* S2RAM resume expected, do doublecheck */ @@ -120,6 +109,4 @@ bool pm_s2ram_mark_check_and_clear(void) resume_failed: FIH_PANIC; - - return true; } From 5f8a387a0800eba0bbc4e8edf5482354fa373992 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Mon, 13 Oct 2025 15:38:41 +0200 Subject: [PATCH 145/149] [nrf noup] boards/thingy53_nrf5340_cpuapp: defaulat to LTO make linking time optimization default for the target. Signed-off-by: Andrzej Puzdrowski (cherry picked from commit 473f7d775201ad1f7276330f206cd1823eb9149c) --- boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf index bbef18460..4c27c5da6 100644 --- a/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy53_nrf5340_cpuapp.conf @@ -73,3 +73,6 @@ CONFIG_FLASH_SIMULATOR_STATS=n # Enable custom command to erase settings partition. CONFIG_ENABLE_MGMT_PERUSER=y CONFIG_BOOT_MGMT_CUSTOM_STORAGE_ERASE=y + +CONFIG_ISR_TABLES_LOCAL_DECLARATION=y +CONFIG_LTO=y From 148d7d5ede874def01b43b03fc8b9032240191d2 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Mon, 27 Oct 2025 13:42:34 +0100 Subject: [PATCH 146/149] [nrf noup] Handle pending confirm requests fixup! [nrf noup] bootloader: Add bootloader requests Interpret pending bootloader requests while investigating the confirm flag. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 484a6f30394abbc2b9f404e715e99271fcf926aa) --- boot/bootutil/src/bootutil_public.c | 91 ++++++++++--------- .../zephyr/src/boot_request_retention.c | 2 - boot/zephyr/Kconfig | 11 --- 3 files changed, 50 insertions(+), 54 deletions(-) diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index f54dd6151..7365eac5b 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -398,9 +398,59 @@ boot_write_image_ok(const struct flash_area *fap) return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET); } +#if defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) +static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) +{ + int id = flash_area_get_id(fa); +#if BOOT_IMAGE_NUMBER > 1 + uint8_t i = 0; + + for (i = 0; i < BOOT_IMAGE_NUMBER; i++) { + if (FLASH_AREA_IMAGE_PRIMARY(i) == id) { + if (slot != NULL) { + *slot = 0; + } + return i; + } else if (FLASH_AREA_IMAGE_SECONDARY(i) == id) { + if (slot != NULL) { + *slot = 1; + } + return i; + } + } + + /* Image not found */ + *slot = UINT32_MAX; +#else + (void)fa; + if (slot != NULL) { + if (FLASH_AREA_IMAGE_PRIMARY(0) == id) { + *slot = 0; + } else if (FLASH_AREA_IMAGE_SECONDARY(0) == id) { + *slot = 1; + } else { + *slot = UINT32_MAX; + } + } +#endif + return 0; +} +#endif /* SEND_BOOT_REQUEST || !MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP */ + int boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok) { +#ifdef SEND_BOOT_REQUEST + enum boot_slot slot_id = BOOT_SLOT_NONE; + int image_id = flash_area_to_image_slot(fap, &slot_id); + bool confirm_pending = boot_request_check_confirmed_slot(image_id, slot_id); + + if (confirm_pending) { + BOOT_LOG_DBG("Image confirmation pending for image %d slot %d", image_id, slot_id); + *image_ok = BOOT_FLAG_SET; + return 0; + } +#endif /* SEND_BOOT_REQUEST */ return boot_read_flag(fap, image_ok, boot_image_ok_off(fap)); } @@ -541,47 +591,6 @@ send_boot_request(uint8_t magic, uint8_t image_ok, bool confirm, int image_id, } #endif /* SEND_BOOT_REQUEST */ -#if defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) -static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) -{ - int id = flash_area_get_id(fa); -#if BOOT_IMAGE_NUMBER > 1 - uint8_t i = 0; - - while (i < BOOT_IMAGE_NUMBER) { - if (FLASH_AREA_IMAGE_PRIMARY(i) == id) { - if (slot != NULL) { - *slot = 0; - } - return i; - } else if (FLASH_AREA_IMAGE_SECONDARY(i) == id) { - if (slot != NULL) { - *slot = 1; - } - return i; - } - - ++i; - } - - /* Image not found */ - *slot = UINT32_MAX; -#else - (void)fa; - if (slot != NULL) { - if (FLASH_AREA_IMAGE_PRIMARY(0) == id) { - *slot = 0; - } else if (FLASH_AREA_IMAGE_SECONDARY(0) == id) { - *slot = 1; - } else { - *slot = UINT32_MAX; - } - } -#endif - return 0; -} -#endif /* defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) */ - #ifndef MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP int boot_set_next(const struct flash_area *fa, bool active, bool confirm) diff --git a/boot/bootutil/zephyr/src/boot_request_retention.c b/boot/bootutil/zephyr/src/boot_request_retention.c index e7fc393a0..9cde6da04 100644 --- a/boot/bootutil/zephyr/src/boot_request_retention.c +++ b/boot/bootutil/zephyr/src/boot_request_retention.c @@ -236,7 +236,6 @@ int boot_request_set_preferred_slot(uint8_t image, enum boot_slot slot) sizeof(value)); } -#ifdef CONFIG_FIND_NEXT_SLOT_HOOKS enum boot_slot boot_request_get_preferred_slot(uint8_t image) { uint8_t value = BOOT_REQUEST_SLOT_INVALID; @@ -265,7 +264,6 @@ enum boot_slot boot_request_get_preferred_slot(uint8_t image) return BOOT_SLOT_NONE; } -#endif /* CONFIG_FIND_NEXT_SLOT_HOOKS */ int boot_request_enter_recovery(void) { diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index e4bf00bba..6cd1fbb08 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1477,15 +1477,4 @@ config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS Time between image validation attempts, in milliseconds. Allows for recovery from transient bit flips or similar situations. -config NCS_MCUBOOT_BOOT_REQUEST_TEST_SETS_BOOT_PREFERENCE - bool "Set boot preference if a slot is marked for test" - help - This option allows to verify boot preference requests through issuing - the image test. - Using this option is not recommended in production systems, because - it will boot any newly transferred image, even if it has a lower - version than the current one. - The rollback protection (using security counters) will still be - effective. - source "Kconfig.zephyr" From 14de127b909856611d486a8011c8b70e95c13b4c Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Fri, 31 Oct 2025 09:09:21 +0100 Subject: [PATCH 147/149] [nrf noup] bootutil: Fix ITS key locking compile error nrf-squash! [nrf noup] bootutil: Locking KMU keys KMU key locking is not available in case ITS is used. Old code cause compilation errors when build for signature using ITS. Signed-off-by: Artur Hadasz (cherry picked from commit 459288d6a13cede9fa09e314b21a979a6cc6e3f2) --- boot/bootutil/src/ed25519_psa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index c7e3910b1..541fc0155 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -187,6 +187,7 @@ int exec_revoke(void) } #endif /* CONFIG_BOOT_KMU_KEYS_REVOCATION */ +#if defined(CONFIG_BOOT_SIGNATURE_USING_KMU) void nrf_crypto_keys_housekeeping(void) { psa_status_t status; @@ -212,5 +213,6 @@ void nrf_crypto_keys_housekeeping(void) key_ids[i], i, status); } } +#endif #endif From 317fabeac87abbdb13c7cee5a886b0f2a364c7cf Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 4 Nov 2025 17:17:07 +0100 Subject: [PATCH 148/149] [nrf noup] Add routines for application Adapt manifest headers, so they can be used by the main application. Signed-off-by: Tomasz Chyrowicz --- .../include/bootutil/mcuboot_manifest.h | 22 ++++ boot/bootutil/src/bootutil_public.c | 100 +++++++++++------- 2 files changed, 82 insertions(+), 40 deletions(-) diff --git a/boot/bootutil/include/bootutil/mcuboot_manifest.h b/boot/bootutil/include/bootutil/mcuboot_manifest.h index 2f0100640..923df39b8 100644 --- a/boot/bootutil/include/bootutil/mcuboot_manifest.h +++ b/boot/bootutil/include/bootutil/mcuboot_manifest.h @@ -15,7 +15,29 @@ #include #include "bootutil/bootutil.h" +#ifdef CONFIG_MCUBOOT #include "bootutil/crypto/sha.h" +#elif defined(CONFIG_MCUBOOT_BOOTLOADER_USES_SHA512) + #define IMAGE_HASH_SIZE (64) +#else + #define IMAGE_HASH_SIZE (32) +#endif + +#ifndef MCUBOOT_MANIFEST_IMAGE_NUMBER +#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER +#define MCUBOOT_MANIFEST_IMAGE_NUMBER CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER +#else +#error "MCUBOOT_MANIFEST_IMAGE_NUMBER must be defined when MCUBOOT_MANIFEST_UPDATES is enabled" +#endif +#endif + +#ifndef MCUBOOT_IMAGE_NUMBER +#ifdef CONFIG_UPDATEABLE_IMAGE_NUMBER +#define MCUBOOT_IMAGE_NUMBER CONFIG_UPDATEABLE_IMAGE_NUMBER +#else +#error "MCUBOOT_IMAGE_NUMBER must be defined when MCUBOOT_MANIFEST_UPDATES is enabled" +#endif +#endif #ifndef __packed #define __packed __attribute__((__packed__)) diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index 7365eac5b..40755a347 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -56,6 +56,10 @@ #define SEND_BOOT_REQUEST #endif /* CONFIG_NRF_MCUBOOT_BOOT_REQUEST && !CONFIG_MCUBOOT */ +#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES +#include +#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */ + #ifdef CONFIG_MCUBOOT BOOT_LOG_MODULE_DECLARE(mcuboot); #else @@ -243,6 +247,45 @@ boot_read_copy_done(const struct flash_area *fap, uint8_t *copy_done) return boot_read_flag(fap, copy_done, boot_copy_done_off(fap)); } +#if defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) || \ + defined(CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES) +static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) +{ + int id = flash_area_get_id(fa); +#if BOOT_IMAGE_NUMBER > 1 + uint8_t i = 0; + + for (i = 0; i < BOOT_IMAGE_NUMBER; i++) { + if (FLASH_AREA_IMAGE_PRIMARY(i) == id) { + if (slot != NULL) { + *slot = 0; + } + return i; + } else if (FLASH_AREA_IMAGE_SECONDARY(i) == id) { + if (slot != NULL) { + *slot = 1; + } + return i; + } + } + + /* Image not found */ + *slot = UINT32_MAX; +#else + (void)fa; + if (slot != NULL) { + if (FLASH_AREA_IMAGE_PRIMARY(0) == id) { + *slot = 0; + } else if (FLASH_AREA_IMAGE_SECONDARY(0) == id) { + *slot = 1; + } else { + *slot = UINT32_MAX; + } + } +#endif + return 0; +} +#endif /* SEND_BOOT_REQUEST || !MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP || CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */ int boot_read_swap_state(const struct flash_area *fap, @@ -251,7 +294,23 @@ boot_read_swap_state(const struct flash_area *fap, uint8_t magic[BOOT_MAGIC_SZ]; uint32_t off; uint8_t swap_info; - int rc; + int rc = -1; +#ifdef CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES + enum boot_slot slot_id = BOOT_SLOT_NONE; + int image_id = flash_area_to_image_slot(fap, &slot_id); + + /* If manifest-based updates are used, only the manifest image is considered. */ + image_id = CONFIG_NCS_MCUBOOT_MANIFEST_IMAGE_NUMBER; + if (slot_id == BOOT_SLOT_PRIMARY) { + rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_id), &fap); + } else if (slot_id == BOOT_SLOT_SECONDARY) { + rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_id), &fap); + } + + if (rc != 0) { + return rc; + } +#endif /* CONFIG_NCS_MCUBOOT_MANIFEST_UPDATES */ off = boot_magic_off(fap); rc = flash_area_read(fap, off, magic, BOOT_MAGIC_SZ); @@ -398,45 +457,6 @@ boot_write_image_ok(const struct flash_area *fap) return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET); } -#if defined(SEND_BOOT_REQUEST) || (!defined(MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP)) -static int flash_area_to_image_slot(const struct flash_area *fa, uint32_t *slot) -{ - int id = flash_area_get_id(fa); -#if BOOT_IMAGE_NUMBER > 1 - uint8_t i = 0; - - for (i = 0; i < BOOT_IMAGE_NUMBER; i++) { - if (FLASH_AREA_IMAGE_PRIMARY(i) == id) { - if (slot != NULL) { - *slot = 0; - } - return i; - } else if (FLASH_AREA_IMAGE_SECONDARY(i) == id) { - if (slot != NULL) { - *slot = 1; - } - return i; - } - } - - /* Image not found */ - *slot = UINT32_MAX; -#else - (void)fa; - if (slot != NULL) { - if (FLASH_AREA_IMAGE_PRIMARY(0) == id) { - *slot = 0; - } else if (FLASH_AREA_IMAGE_SECONDARY(0) == id) { - *slot = 1; - } else { - *slot = UINT32_MAX; - } - } -#endif - return 0; -} -#endif /* SEND_BOOT_REQUEST || !MCUBOOT_BOOTUTIL_LIB_FOR_DIRECT_XIP */ - int boot_read_image_ok(const struct flash_area *fap, uint8_t *image_ok) { From 49908e88d5ea3d18029f3fdde58a5054aac30ad3 Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Mon, 3 Nov 2025 09:55:26 +0100 Subject: [PATCH 149/149] [nrf noup] bootutil: ed25519_psa: multi verification revocation take into account multiple verification done in one boot. Make sure only unused keys are revoked. Signed-off-by: Mateusz Michalek (cherry picked from commit 0d263faf6e55a697ee336f2fbef0af095802f979) --- boot/bootutil/src/ed25519_psa.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 541fc0155..87097f36c 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -45,7 +45,8 @@ static psa_key_id_t key_ids[] = { #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) #include -static psa_key_id_t *validated_with = NULL; +#define VALIDATED_WITH_UNINITIALIZED INT32_MAX +static int32_t validated_with = VALIDATED_WITH_UNINITIALIZED; #endif BUILD_ASSERT(CONFIG_BOOT_SIGNATURE_KMU_SLOTS <= ARRAY_SIZE(key_ids), @@ -142,7 +143,9 @@ int ED25519_verify(const uint8_t *message, size_t message_len, EDDSA_SIGNAGURE_LENGTH); if (status == PSA_SUCCESS) { #if defined(CONFIG_BOOT_KMU_KEYS_REVOCATION) - validated_with = key_ids + i; + if(i < validated_with) { + validated_with = i; + } #endif return 1; } @@ -159,7 +162,7 @@ int exec_revoke(void) int ret = BOOT_KEY_REVOKE_OK; psa_status_t status = psa_crypto_init(); - if (!validated_with) { + if (validated_with == VALIDATED_WITH_UNINITIALIZED) { ret = BOOT_KEY_REVOKE_INVALID; goto out; } @@ -170,7 +173,7 @@ int exec_revoke(void) goto out; } for (int i = 0; i < CONFIG_BOOT_SIGNATURE_KMU_SLOTS; i++) { - if ((key_ids + i) == validated_with) { + if ( i == validated_with) { break; } BOOT_LOG_DBG("Invalidating key ID %d", i); @@ -179,7 +182,7 @@ int exec_revoke(void) if (status == PSA_SUCCESS) { BOOT_LOG_DBG("Success on key ID %d", i); } else { - BOOT_LOG_ERR("Key invalidation failed with: %d", status); + BOOT_LOG_DBG("Key invalidation failed with: %d", status); } } out: