From ba56472ac54b08aefb50ff45bb1377105ece1099 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 29 May 2025 13:43:14 +0000 Subject: [PATCH 001/125] [nrf fromlist] bootutil: Move all encryption TLV helper identifiers into one place Make enc_key_public.h single point of definitions for key sizes, TLV indexes and so on. Upstream PR #: 2327 Signed-off-by: Dominik Ermel (cherry picked from commit 2d9395822dcd0ed6fff7a85fc32da489eb49f491) --- .../include/bootutil/bootutil_macros.h | 19 +++++ boot/bootutil/include/bootutil/crypto/rsa.h | 4 +- boot/bootutil/include/bootutil/enc_key.h | 2 - .../include/bootutil/enc_key_public.h | 77 +++++++++++++++---- boot/bootutil/src/encrypted.c | 32 ++------ boot/bootutil/src/encrypted_psa.c | 10 --- 6 files changed, 86 insertions(+), 58 deletions(-) create mode 100644 boot/bootutil/include/bootutil/bootutil_macros.h diff --git a/boot/bootutil/include/bootutil/bootutil_macros.h b/boot/bootutil/include/bootutil/bootutil_macros.h new file mode 100644 index 000000000..e8d27b792 --- /dev/null +++ b/boot/bootutil/include/bootutil/bootutil_macros.h @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2025 Nordic Semiconductor ASA + * + */ + +#ifndef H_BOOTUTIL_MACROS +#define H_BOOTUTIL_MACROS + +#ifndef ALIGN_UP +#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) +#endif + +#ifndef ALIGN_DOWN +#define ALIGN_DOWN(num, align) ((num) & ~((align) - 1)) +#endif + +#endif diff --git a/boot/bootutil/include/bootutil/crypto/rsa.h b/boot/bootutil/include/bootutil/crypto/rsa.h index 581e4ec9b..87ab1de56 100644 --- a/boot/bootutil/include/bootutil/crypto/rsa.h +++ b/boot/bootutil/include/bootutil/crypto/rsa.h @@ -100,12 +100,12 @@ static int bootutil_rsa_oaep_decrypt( return -1; } size_t input_size = PSA_BITS_TO_BYTES(psa_get_key_bits(&key_attr)); - if (input_size != TLV_ENC_RSA_SZ) { + if (input_size != BOOT_ENC_TLV_SIZE) { return -1; } status = psa_asymmetric_decrypt(ctx->key_id, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256), - input, TLV_ENC_RSA_SZ, NULL, 0, + input, BOOT_ENC_TLV_SIZE, NULL, 0, output, output_max_len, olen); return (int)status; } diff --git a/boot/bootutil/include/bootutil/enc_key.h b/boot/bootutil/include/bootutil/enc_key.h index 9240d699d..85cb7e1b9 100644 --- a/boot/bootutil/include/bootutil/enc_key.h +++ b/boot/bootutil/include/bootutil/enc_key.h @@ -39,8 +39,6 @@ extern "C" { #endif -#define BOOT_ENC_TLV_ALIGN_SIZE ALIGN_UP(BOOT_ENC_TLV_SIZE, BOOT_MAX_ALIGN) - struct enc_key_data { uint8_t valid; bootutil_aes_ctr_context aes_ctr; diff --git a/boot/bootutil/include/bootutil/enc_key_public.h b/boot/bootutil/include/bootutil/enc_key_public.h index 6874cfbc8..55b06b025 100644 --- a/boot/bootutil/include/bootutil/enc_key_public.h +++ b/boot/bootutil/include/bootutil/enc_key_public.h @@ -28,37 +28,80 @@ #ifndef BOOTUTIL_ENC_KEY_PUBLIC_H #define BOOTUTIL_ENC_KEY_PUBLIC_H #include +#include + #ifdef __cplusplus extern "C" { #endif -#ifndef ALIGN_UP -#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) -#endif +/* The unit provides following system wide definitions: + * BOOT_ENC_TLV_SIZE -- is the complete size of TLV with encryption data. + * BOOT_ENC_TLV -- is the encryption TLV type, should be given value + * of one of IMAGE_TVL_ENC_ identifiers. + * BOOT_ENC_KEY_SIZE -- is the encryption key size; this includes portion + * of TLV data stream taken by key. + * + * For ECIES based key exchange there is additionally provided: + * EC_PUBK_LEN -- is the length, in bytes, of a public key; depends + * selected key exchange. + * EC_PRIVK_LEN -- is the length, in bytes, of a private key; depends + * on selected key exchange. + * EC_SHARED_LEN -- is the length, in bytes, of a shared key resulting + * from processing of private and public key; depends + * on selected key exchange parameters. + * + * ECIES TLV processing uses following TLVs, from this header: + * EC_TAG_INDEX -- is the HMAC tag of encryption key index within TLV data + * stream. + * EC_TAG_LEN -- is the HMAC tag length. + * EC_PUBK_INDEX -- is the index of shared public key within TLV data stream; + * EC_PUBK_LEN represents length in bytes. + * EC_CIPHERKEY_INDEX -- is the encryption key index within TLV data stream. + * EC_CIPHERKEY_LEN -- is the length of an encryption key; depends on selected + * encryption. + * + * Note that in case of ECIES, the BOOT_ENC_TLV_SIZE will be defined as + * a sum of EC_*_LEN TLV components, defined for selected key exchange. + */ #ifdef MCUBOOT_AES_256 -#define BOOT_ENC_KEY_SIZE 32 +# define BOOT_ENC_KEY_SIZE 32 #else -#define BOOT_ENC_KEY_SIZE 16 +# define BOOT_ENC_KEY_SIZE 16 #endif -#define BOOT_ENC_KEY_ALIGN_SIZE ALIGN_UP(BOOT_ENC_KEY_SIZE, BOOT_MAX_ALIGN) - -#define TLV_ENC_RSA_SZ 256 -#define TLV_ENC_KW_SZ (BOOT_ENC_KEY_SIZE + 8) -#define TLV_ENC_EC256_SZ (65 + 32 + BOOT_ENC_KEY_SIZE) -#define TLV_ENC_X25519_SZ (32 + 32 + BOOT_ENC_KEY_SIZE) - #if defined(MCUBOOT_ENCRYPT_RSA) -#define BOOT_ENC_TLV_SIZE TLV_ENC_RSA_SZ +# define BOOT_ENC_TLV_SIZE (256) +# define BOOT_ENC_TLV IMAGE_TLV_ENC_RSA2048 #elif defined(MCUBOOT_ENCRYPT_EC256) -#define BOOT_ENC_TLV_SIZE TLV_ENC_EC256_SZ +# define EC_PUBK_LEN (65) +# define EC_PRIVK_LEN (32) +# define EC_SHARED_LEN (32) +# define BOOT_ENC_TLV IMAGE_TLV_ENC_EC256 #elif defined(MCUBOOT_ENCRYPT_X25519) -#define BOOT_ENC_TLV_SIZE TLV_ENC_X25519_SZ -#else -#define BOOT_ENC_TLV_SIZE TLV_ENC_KW_SZ +# define EC_PUBK_LEN (32) +# define EC_PRIVK_LEN (32) +# define EC_SHARED_LEN (32) +# define BOOT_ENC_TLV IMAGE_TLV_ENC_X25519 +#elif defined(MCUBOOT_ENCRYPT_KW) +# define BOOT_ENC_TLV_SIZE (BOOT_ENC_KEY_SIZE + 8) +# define BOOT_ENC_TLV IMAGE_TLV_ENC_KW #endif +/* Common ECIES definitions */ +#if defined(EC_PUBK_LEN) +# define EC_PUBK_INDEX (0) +# define EC_TAG_LEN (32) +# define EC_TAG_INDEX (EC_PUBK_INDEX + EC_PUBK_LEN) +# define EC_CIPHERKEY_INDEX (EC_TAG_INDEX + EC_TAG_LEN) +# define EC_CIPHERKEY_LEN BOOT_ENC_KEY_SIZE +# define EC_SHARED_KEY_LEN (32) +# define BOOT_ENC_TLV_SIZE (EC_PUBK_LEN + EC_TAG_LEN + EC_CIPHERKEY_LEN) +#endif + +#define BOOT_ENC_KEY_ALIGN_SIZE ALIGN_UP(BOOT_ENC_KEY_SIZE, BOOT_MAX_ALIGN) +#define BOOT_ENC_TLV_ALIGN_SIZE ALIGN_UP(BOOT_ENC_TLV_SIZE, BOOT_MAX_ALIGN) + #ifdef __cplusplus } #endif diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index bbe40751f..f64493656 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -46,28 +46,6 @@ #include "bootutil_priv.h" -#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE - -#if defined(MCUBOOT_ENCRYPT_RSA) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048 -#elif defined(MCUBOOT_ENCRYPT_KW) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW -#elif defined(MCUBOOT_ENCRYPT_EC256) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256 -# define EC_PUBK_INDEX (0) -# define EC_TAG_INDEX (65) -# define EC_CIPHERKEY_INDEX (65 + 32) -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-P256 component indexes"); -#elif defined(MCUBOOT_ENCRYPT_X25519) -# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519 -# define EC_PUBK_INDEX (0) -# define EC_TAG_INDEX (32) -# define EC_CIPHERKEY_INDEX (32 + 32) -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-X25519 component indexes"); -#endif - /* NOUP Fixme: */ #if !defined(CONFIG_BOOT_ED25519_PSA) #if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519) @@ -104,7 +82,7 @@ key_unwrap(const uint8_t *wrapped, uint8_t *enckey, struct bootutil_key *bootuti if (rc != 0) { goto done; } - rc = bootutil_aes_kw_unwrap(&aes_kw, wrapped, TLV_ENC_KW_SZ, enckey, BOOT_ENC_KEY_SIZE); + rc = bootutil_aes_kw_unwrap(&aes_kw, wrapped, BOOT_ENC_TLV_SIZE, enckey, BOOT_ENC_KEY_SIZE); if (rc != 0) { goto done; } @@ -621,7 +599,7 @@ boot_enc_load(struct boot_loader_state *state, int slot, #if MCUBOOT_SWAP_SAVE_ENCTLV uint8_t *buf; #else - uint8_t buf[EXPECTED_ENC_LEN]; + uint8_t buf[BOOT_ENC_TLV_SIZE]; #endif int rc; @@ -641,7 +619,7 @@ boot_enc_load(struct boot_loader_state *state, int slot, #endif #endif - rc = bootutil_tlv_iter_begin(&it, hdr, fap, EXPECTED_ENC_TLV, false); + rc = bootutil_tlv_iter_begin(&it, hdr, fap, BOOT_ENC_TLV, false); if (rc) { return -1; } @@ -651,7 +629,7 @@ boot_enc_load(struct boot_loader_state *state, int slot, return rc; } - if (len != EXPECTED_ENC_LEN) { + if (len != BOOT_ENC_TLV_SIZE) { return -1; } @@ -660,7 +638,7 @@ boot_enc_load(struct boot_loader_state *state, int slot, memset(buf, 0xff, BOOT_ENC_TLV_ALIGN_SIZE); #endif - rc = flash_area_read(fap, off, buf, EXPECTED_ENC_LEN); + rc = flash_area_read(fap, off, buf, BOOT_ENC_TLV_SIZE); if (rc) { return -1; } diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c index 313372fb1..d604df201 100644 --- a/boot/bootutil/src/encrypted_psa.c +++ b/boot/bootutil/src/encrypted_psa.c @@ -27,16 +27,6 @@ BOOT_LOG_MODULE_DECLARE(mcuboot_psa_enc); -#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE -#define EC_PUBK_INDEX (0) -#define EC_PUBK_LEN (32) -#define EC_TAG_INDEX (EC_PUBK_INDEX + EC_PUBK_LEN) -#define EC_TAG_LEN (32) -#define EC_CIPHERKEY_INDEX (EC_TAG_INDEX + EC_TAG_LEN) -#define EC_CIPHERKEY_LEN BOOT_ENC_KEY_SIZE -_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN, - "Please fix ECIES-X25519 component indexes"); - #define X25519_OID "\x6e" static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \ MBEDTLS_OID_ORG_GOV X25519_OID; From 4fb63a68022b62451bdcca2b2c25a3968eaaedbc Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 29 May 2025 16:14:33 +0000 Subject: [PATCH 002/125] [nrf fromlist] bootutil: Remove redundant ALIGN definitions Use bootutil_macros.h instead. Upstream PR #: 2327 Signed-off-by: Dominik Ermel (cherry picked from commit c1bb3a34cf3d0d6ed612b15716946dfdd59132d7) --- boot/bootutil/include/bootutil/bootutil_public.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/boot/bootutil/include/bootutil/bootutil_public.h b/boot/bootutil/include/bootutil/bootutil_public.h index e2795ab3e..933553f9f 100644 --- a/boot/bootutil/include/bootutil/bootutil_public.h +++ b/boot/bootutil/include/bootutil/bootutil_public.h @@ -43,20 +43,13 @@ #include #include #include +#include #include #ifdef __cplusplus extern "C" { #endif -#ifndef ALIGN_UP -#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) -#endif - -#ifndef ALIGN_DOWN -#define ALIGN_DOWN(num, align) ((num) & ~((align) - 1)) -#endif - /** Attempt to boot the contents of the primary slot. */ #define BOOT_SWAP_TYPE_NONE 1 From 6e4285ae3e5c759082c8c7e0c067efb012a4b9bc Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 30 May 2025 17:01:49 +0000 Subject: [PATCH 003/125] [nrf fromlist] bootutil: Replace local identifiers with common definitions Cleanup. Upstream PR #: 2327 Signed-off-by: Dominik Ermel (cherry picked from commit f4a50814f17d26da4208b62d2f14ec09c5b67d64) --- boot/bootutil/src/encrypted.c | 21 +++++++++------------ boot/bootutil/src/encrypted_psa.c | 8 +++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index f64493656..e0078a7be 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -97,9 +97,6 @@ key_unwrap(const uint8_t *wrapped, uint8_t *enckey, struct bootutil_key *bootuti static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED; static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1; -#define SHARED_KEY_LEN NUM_ECC_BYTES -#define PRIV_KEY_LEN NUM_ECC_BYTES - /* * Parses the output of `imgtool keygen`, which produces a PKCS#8 elliptic * curve keypair. See RFC5208 and RFC5915. @@ -179,9 +176,6 @@ parse_ec256_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \ MBEDTLS_OID_ORG_GOV X25519_OID; -#define SHARED_KEY_LEN 32 -#define PRIV_KEY_LEN 32 - static int parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) { @@ -221,11 +215,11 @@ parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) return -7; } - if (len != PRIV_KEY_LEN) { + if (len != EC_PRIVK_LEN) { return -8; } - memcpy(private_key, *p, PRIV_KEY_LEN); + memcpy(private_key, *p, EC_PRIVK_LEN); return 0; } #endif /* defined(MCUBOOT_ENCRYPT_X25519) */ @@ -399,11 +393,11 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) bootutil_hmac_sha256_context hmac; bootutil_aes_ctr_context aes_ctr; uint8_t tag[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; - uint8_t shared[SHARED_KEY_LEN]; + uint8_t shared[EC_SHARED_LEN]; uint8_t derived_key[BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE]; uint8_t *cp; uint8_t *cpend; - uint8_t private_key[PRIV_KEY_LEN]; + uint8_t private_key[EC_PRIVK_LEN]; uint8_t counter[BOOT_ENC_BLOCK_SIZE]; uint16_t len; #endif @@ -509,7 +503,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) */ len = BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE; - rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16, + rc = hkdf(shared, EC_SHARED_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16, derived_key, &len); if (rc != 0 || len != (BOOT_ENC_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)) { return -1; @@ -521,6 +515,9 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) bootutil_hmac_sha256_init(&hmac); + /* First BOOT_ENC_KEY_SIZE are used for decryption, remaining 32 bytes are used + * for MAC tag key + */ rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[BOOT_ENC_KEY_SIZE], 32); if (rc != 0) { (void)bootutil_hmac_sha256_drop(&hmac); @@ -540,7 +537,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) return -1; } - if (bootutil_constant_time_compare(tag, &buf[EC_TAG_INDEX], 32) != 0) { + if (bootutil_constant_time_compare(tag, &buf[EC_TAG_INDEX], EC_TAG_LEN) != 0) { (void)bootutil_hmac_sha256_drop(&hmac); return -1; } diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c index d604df201..04b5fbee4 100644 --- a/boot/bootutil/src/encrypted_psa.c +++ b/boot/bootutil/src/encrypted_psa.c @@ -31,8 +31,6 @@ BOOT_LOG_MODULE_DECLARE(mcuboot_psa_enc); static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \ MBEDTLS_OID_ORG_GOV X25519_OID; -#define PRIV_KEY_LEN 32 - /* Partitioning of HKDF derived material, from the exchange derived key */ /* AES key encryption key */ #define HKDF_AES_KEY_INDEX 0 @@ -83,11 +81,11 @@ parse_x25519_enckey(uint8_t **p, uint8_t *end, uint8_t *private_key) return -7; } - if (len != PRIV_KEY_LEN) { + if (len != EC_PRIVK_LEN) { return -8; } - memcpy(private_key, *p, PRIV_KEY_LEN); + memcpy(private_key, *p, EC_PRIVK_LEN); return 0; } @@ -117,7 +115,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) uint8_t derived_key[HKDF_SIZE]; uint8_t *cp; uint8_t *cpend; - uint8_t private_key[PRIV_KEY_LEN]; + uint8_t private_key[EC_PRIVK_LEN]; size_t len; psa_status_t psa_ret = PSA_ERROR_BAD_STATE; psa_status_t psa_cleanup_ret = PSA_ERROR_BAD_STATE; From 884efcadeffbf61483f9ee1c9171b0e1806ba704 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 11 Jun 2025 14:14:43 +0000 Subject: [PATCH 004/125] [nrf fromlist] bootutil: Fix boot_scramble_region escaping flash area Incorrect range check fix. Upstream PR #: 2337 Signed-off-by: Dominik Ermel (cherry picked from commit fa17bc97c594bc4c2178d53a83f48fbcc244ed47) --- boot/bootutil/src/loader.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index ffd2456a7..44275fcb9 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1274,7 +1274,7 @@ boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size, b end_offset = ALIGN_DOWN((off + size), write_block); } - while (true) { + 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) { @@ -1291,12 +1291,12 @@ boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size, b off -= write_block; } else { - if (end_offset < off) { + off += write_block; + + if (end_offset <= off) { /* Reached the end offset in range and already scrambled it */ break; } - - off += write_block; } } } From 46980ce0bf11ad8966783c2bfe53a6223c332066 Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Mon, 9 Jun 2025 17:14:47 +0200 Subject: [PATCH 005/125] [nrf fromtree] scripts: imgtool: Compression of no header-padded images This fixes issues when trying to compress images with no header padding requested. Upstream PR #: 2334 Signed-off-by: Michal Kozikowski (cherry picked from commit 9e0bebc8c3cf984e4d12182a9390275521fe54d6) --- scripts/imgtool/image.py | 24 +++++++++++++++--------- scripts/imgtool/main.py | 8 +++++--- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index 566a47e00..c7fb9e553 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -348,7 +348,6 @@ def load(self, path): self.payload = copy.copy(self.infile_data) except FileNotFoundError: raise click.UsageError("Input file not found") - self.image_size = len(self.payload) # Add the image header if needed. if self.pad_header and self.header_size > 0: @@ -358,6 +357,8 @@ def load(self, path): self.payload = bytes([self.erased_val] * self.header_size) + \ self.payload + self.image_size = len(self.payload) - self.header_size + self.check_header() def load_compressed(self, data, compression_header): @@ -366,14 +367,19 @@ def load_compressed(self, data, compression_header): self.image_size = len(self.payload) # Add the image header if needed. - if self.pad_header and self.header_size > 0: - if self.base_addr: - # Adjust base_addr for new header - self.base_addr -= self.header_size - self.payload = bytes([self.erased_val] * self.header_size) + \ - self.payload - - self.check_header() + if self.header_size > 0: + if self.pad_header: + if self.base_addr: + # Adjust base_addr for new header + self.base_addr -= self.header_size + self.payload = bytes([self.erased_val] * self.header_size) + \ + self.payload + else: + # Fill header padding with zeros to align with what is expected + # for uncompressed images when no pad_header is requested + # (see self.check_header()) + self.payload = bytes([0] * self.header_size) + \ + self.payload def save(self, path, hex_addr=None): """Save an image from a given file""" diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index 1cdb792a5..78f2e77ec 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -542,9 +542,11 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, ] if compression == "lzma2armthumb": compression_filters.insert(0, {"id":lzma.FILTER_ARMTHUMB}) - compressed_data = lzma.compress(img.get_infile_data(),filters=compression_filters, - format=lzma.FORMAT_RAW) - uncompressed_size = len(img.get_infile_data()) + + infile_offset = 0 if pad_header else header_size + compressed_data = lzma.compress(img.get_infile_data()[infile_offset:], + filters=compression_filters, format=lzma.FORMAT_RAW) + uncompressed_size = len(img.get_infile_data()[infile_offset:]) compressed_size = len(compressed_data) print(f"compressed image size: {compressed_size} bytes") print(f"original image size: {uncompressed_size} bytes") From 6a4025b10a7901c20d08814dd6ed228a0ee01a2f Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Mon, 16 Jun 2025 16:26:16 +0200 Subject: [PATCH 006/125] [nrf fromlist] zephyr: Fix pinreset trigger The hfwinfo returns bitmask, not single values. Upstream PR #: 2342 Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 18e3bc8b261b018983e2300ec4e68e027c863a14) --- boot/zephyr/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/zephyr/io.c b/boot/zephyr/io.c index 309f1ab94..f2342c1ad 100644 --- a/boot/zephyr/io.c +++ b/boot/zephyr/io.c @@ -181,7 +181,7 @@ bool io_detect_pin_reset(void) rc = hwinfo_get_reset_cause(&reset_cause); - if (rc == 0 && reset_cause == RESET_PIN) { + if (rc == 0 && (reset_cause & RESET_PIN)) { (void)hwinfo_clear_reset_cause(); return true; } From 57ceb536003462cbed6dde26221667d64fbbbc0e Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Mon, 16 Jun 2025 11:41:28 +0200 Subject: [PATCH 007/125] [nrf fromtree] bootutil: loader: overwrite-only mode fix for trailer erase This fixes issues when trying to erase secondary slot trailer for platforms with MCUBOOT_SUPPORT_DEV_WITHOUT_ERASE set from flash driver. Calling explicitly to 'scramble' region ensures we delete the trailer. Upstream PR #: 2341 Signed-off-by: Michal Kozikowski (cherry picked from commit bb644c7c41b84aebe0e6456099598cef776e7142) --- boot/bootutil/src/loader.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 44275fcb9..62f980b69 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1687,19 +1687,19 @@ boot_copy_image(struct boot_loader_state *state, struct boot_status *bs) * trailer that was left might trigger a new upgrade. */ BOOT_LOG_DBG("erasing secondary header"); - rc = boot_erase_region(fap_secondary_slot, - boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0), - boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0), false); + rc = boot_scramble_region(fap_secondary_slot, + boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0), + boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0), false); assert(rc == 0); #endif last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1; BOOT_LOG_DBG("erasing secondary trailer"); - rc = boot_erase_region(fap_secondary_slot, - boot_img_sector_off(state, BOOT_SECONDARY_SLOT, - last_sector), - boot_img_sector_size(state, BOOT_SECONDARY_SLOT, - last_sector), false); + rc = boot_scramble_region(fap_secondary_slot, + boot_img_sector_off(state, BOOT_SECONDARY_SLOT, + last_sector), + boot_img_sector_size(state, BOOT_SECONDARY_SLOT, + last_sector), false); assert(rc == 0); /* TODO: Perhaps verify the primary slot's signature again? */ From 657e048b0f4b043893a48704bab23afe5f4b2221 Mon Sep 17 00:00:00 2001 From: Sayooj K Karun Date: Wed, 23 Apr 2025 18:13:11 +0530 Subject: [PATCH 008/125] [nrf fromtree] boot: zephyr: Refactor DFU entry logic Consolidates USB DFU entry logic by unifying GPIO and timeout-based DFU triggers under a common flag. This avoids code duplication and improves maintainability. Also improves log clarity for different DFU exit conditions. Signed-off-by: Sayooj K Karun (cherry picked from commit 402d3f7ff11973577f1bc966151fccf53192f32b) Signed-off-by: Dominik Ermel --- boot/zephyr/main.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 4ecf191e7..ddea864de 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -2,6 +2,7 @@ * Copyright (c) 2012-2014 Wind River Systems, Inc. * Copyright (c) 2020 Arm Limited * Copyright (c) 2021-2023 Nordic Semiconductor ASA + * Copyright (c) 2025 Aerlync Labs Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -434,6 +435,9 @@ int main(void) { struct boot_rsp rsp; int rc; +#if defined(CONFIG_BOOT_USB_DFU_GPIO) || defined(CONFIG_BOOT_USB_DFU_WAIT) + bool usb_dfu_requested = false; +#endif FIH_DECLARE(fih_rc, FIH_FAILURE); MCUBOOT_WATCHDOG_SETUP(); @@ -473,35 +477,37 @@ int main(void) #if defined(CONFIG_BOOT_USB_DFU_GPIO) if (io_detect_pin()) { + usb_dfu_requested = true; + #ifdef CONFIG_MCUBOOT_INDICATION_LED io_led_set(1); #endif mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_ENTERED); + } +#elif defined(CONFIG_BOOT_USB_DFU_WAIT) + usb_dfu_requested = true; +#endif +#if defined(CONFIG_BOOT_USB_DFU_GPIO) || defined(CONFIG_BOOT_USB_DFU_WAIT) + if (usb_dfu_requested) { rc = usb_enable(NULL); if (rc) { - BOOT_LOG_ERR("Cannot enable USB"); + BOOT_LOG_ERR("Cannot enable USB: %d", rc); } else { BOOT_LOG_INF("Waiting for USB DFU"); - wait_for_usb_dfu(K_FOREVER); + +#if defined(CONFIG_BOOT_USB_DFU_WAIT) + mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_WAITING); + wait_for_usb_dfu(K_MSEC(CONFIG_BOOT_USB_DFU_WAIT_DELAY_MS)); BOOT_LOG_INF("USB DFU wait time elapsed"); + mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_TIMED_OUT); +#else + wait_for_usb_dfu(K_FOREVER); + BOOT_LOG_INF("USB DFU wait terminated"); +#endif } } -#elif defined(CONFIG_BOOT_USB_DFU_WAIT) - rc = usb_enable(NULL); - if (rc) { - BOOT_LOG_ERR("Cannot enable USB"); - } else { - BOOT_LOG_INF("Waiting for USB DFU"); - - mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_WAITING); - - wait_for_usb_dfu(K_MSEC(CONFIG_BOOT_USB_DFU_WAIT_DELAY_MS)); - BOOT_LOG_INF("USB DFU wait time elapsed"); - - mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_TIMED_OUT); - } #endif #ifdef CONFIG_BOOT_SERIAL_WAIT_FOR_DFU From b7f129b42e6ee98b18c1fbe2ac0ea59109663e57 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 15 May 2025 15:43:57 +0000 Subject: [PATCH 009/125] [nrf fromtree] bootutil: Improve logging coverage Add additional log lines to allow easier tracking potential failures in image validation. Signed-off-by: Dominik Ermel (cherry picked from commit 11f9c6f2fa5cba2ca42e6371c42786bd43a4837e) --- boot/bootutil/src/bootutil_misc.c | 17 ++++++++++++++++ boot/bootutil/src/bootutil_public.c | 22 +++++++++++++++++---- boot/bootutil/src/ed25519_psa.c | 2 ++ boot/bootutil/src/encrypted.c | 8 ++++++++ boot/bootutil/src/encrypted_psa.c | 4 +++- boot/bootutil/src/image_ecdsa.c | 7 +++++++ boot/bootutil/src/image_ed25519.c | 17 +++++++++++++++- boot/bootutil/src/image_rsa.c | 5 +++++ boot/bootutil/src/image_validate.c | 23 +++++++++++++++++++++- boot/bootutil/src/loader.c | 30 +++++++++++++++++++++++++++++ boot/bootutil/src/swap_misc.c | 2 +- boot/bootutil/src/tlv.c | 14 ++++++++++++++ 12 files changed, 143 insertions(+), 8 deletions(-) diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 0091165d5..56e791043 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -155,6 +155,9 @@ int boot_trailer_scramble_offset(const struct flash_area *fa, size_t alignment, { 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); @@ -176,6 +179,9 @@ int boot_trailer_scramble_offset(const struct flash_area *fa, size_t alignment, *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; } @@ -187,6 +193,8 @@ int boot_header_scramble_off_sz(const struct flash_area *fa, int slot, size_t *o 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 @@ -215,6 +223,8 @@ int boot_header_scramble_off_sz(const struct flash_area *fa, int slot, size_t *o } *off = loff; + BOOT_LOG_DBG("boot_header_scramble_off_sz: size %u", (unsigned int)*size); + return ret; } @@ -601,6 +611,9 @@ boot_erase_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool { 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; @@ -608,6 +621,8 @@ boot_erase_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool 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); @@ -681,6 +696,8 @@ boot_erase_region(const struct flash_area *fa, uint32_t off, uint32_t size, bool off += 1; } } + } else { + BOOT_LOG_DBG("boot_erase_region: device without erase"); } end: diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c index 102118864..8860fca41 100644 --- a/boot/bootutil/src/bootutil_public.c +++ b/boot/bootutil/src/bootutil_public.c @@ -324,7 +324,7 @@ boot_write_magic(const struct flash_area *fap) memset(&magic[0], erased_val, sizeof(magic)); memcpy(&magic[BOOT_MAGIC_ALIGN_SIZE - BOOT_MAGIC_SZ], BOOT_IMG_MAGIC, BOOT_MAGIC_SZ); - BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%lx (0x%lx)", + BOOT_LOG_DBG("boot_write_magic: fa_id=%d off=0x%lx (0x%lx)", flash_area_get_id(fap), (unsigned long)off, (unsigned long)(flash_area_get_off(fap) + off)); rc = flash_area_write(fap, pad_off, &magic[0], BOOT_MAGIC_ALIGN_SIZE); @@ -350,9 +350,14 @@ boot_write_trailer(const struct flash_area *fap, uint32_t off, uint32_t align; int rc; + BOOT_LOG_DBG("boot_write_trailer: for %p at %d, size = %d", + fap, off, inlen); + align = flash_area_align(fap); align = ALIGN_UP(inlen, align); if (align > BOOT_MAX_ALIGN) { + /* This should never happen */ + assert(0); return -1; } erased_val = flash_area_erased_val(fap); @@ -596,6 +601,9 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) struct boot_swap_state slot_state; int rc; + BOOT_LOG_DBG("boot_set_next: fa %p active == %d, confirm == %d", + fa, (int)active, (int)confirm); + if (active) { /* The only way to set active slot for next boot is to confirm it, * as DirectXIP will conclude that, since slot has not been confirmed @@ -606,6 +614,7 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm) rc = boot_read_swap_state(fa, &slot_state); if (rc != 0) { + BOOT_LOG_DBG("boot_set_next: error %d reading state", rc); return rc; } @@ -733,6 +742,8 @@ boot_set_confirmed_multi(int image_index) rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap); if (rc != 0) { + BOOT_LOG_DBG("boot_set_confirmed_multi: error %d opening image %d", + rc, image_index); return BOOT_EFLASH; } @@ -760,13 +771,14 @@ int boot_image_load_header(const struct flash_area *fa_p, struct image_header *hdr) { - uint32_t size; + uint32_t size = 0; int rc = flash_area_read(fa_p, 0, hdr, sizeof *hdr); + BOOT_LOG_DBG("boot_image_load_header: from %p, result %d", fa_p, rc); + if (rc != 0) { - rc = BOOT_EFLASH; BOOT_LOG_ERR("Failed reading image header"); - return BOOT_EFLASH; + return BOOT_EFLASH; } if (hdr->ih_magic != IMAGE_MAGIC) { @@ -783,6 +795,8 @@ boot_image_load_header(const struct flash_area *fa_p, if (!boot_u32_safe_add(&size, hdr->ih_img_size, hdr->ih_hdr_size) || size >= flash_area_get_size(fa_p)) { + BOOT_LOG_ERR("Image size bigger than designated area: %lu > %lu", + (unsigned long)size, (unsigned long)flash_area_get_size(fa_p)); return BOOT_EBADIMAGE; } diff --git a/boot/bootutil/src/ed25519_psa.c b/boot/bootutil/src/ed25519_psa.c index 12ba20ac1..5b8a4ed7c 100644 --- a/boot/bootutil/src/ed25519_psa.c +++ b/boot/bootutil/src/ed25519_psa.c @@ -29,6 +29,8 @@ int ED25519_verify(const uint8_t *message, size_t message_len, psa_key_id_t kid; int ret = 0; /* Fail by default */ + BOOT_LOG_DBG("ED25519_verify: PSA implementation"); + /* Initialize PSA Crypto */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c index e0078a7be..cf6f380e2 100644 --- a/boot/bootutil/src/encrypted.c +++ b/boot/bootutil/src/encrypted.c @@ -43,6 +43,9 @@ #include "bootutil/enc_key.h" #include "bootutil/sign_key.h" #include "bootutil/crypto/common.h" +#include "bootutil/bootutil_log.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); #include "bootutil_priv.h" @@ -383,6 +386,8 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) uint8_t *cpend; size_t olen; #endif + + BOOT_LOG_DBG("boot_decrypt_key"); #if defined(MCUBOOT_ENCRYPT_EC256) bootutil_ecdh_p256_context ecdh_p256; #endif @@ -600,8 +605,11 @@ boot_enc_load(struct boot_loader_state *state, int slot, #endif int rc; + BOOT_LOG_DBG("boot_enc_load: slot %d", slot); + /* Already loaded... */ if (enc_state[slot].valid) { + BOOT_LOG_DBG("boot_enc_load: already loaded"); return 1; } diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c index 04b5fbee4..6f60a1955 100644 --- a/boot/bootutil/src/encrypted_psa.c +++ b/boot/bootutil/src/encrypted_psa.c @@ -134,9 +134,11 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) uint8_t iv_and_key[PSA_CIPHER_IV_LENGTH(PSA_KEY_TYPE_AES, PSA_ALG_CTR) + BOOT_ENC_KEY_SIZE]; + BOOT_LOG_DBG("boot_decrypt_key: PSA ED25519"); + psa_ret = psa_crypto_init(); if (psa_ret != PSA_SUCCESS) { - BOOT_LOG_ERR("AES crypto init failed %d", psa_ret); + BOOT_LOG_ERR("PSA crypto init failed %d", psa_ret); return -1; } diff --git a/boot/bootutil/src/image_ecdsa.c b/boot/bootutil/src/image_ecdsa.c index 4604913b4..30c7d0d0f 100644 --- a/boot/bootutil/src/image_ecdsa.c +++ b/boot/bootutil/src/image_ecdsa.c @@ -28,6 +28,9 @@ #include #include "mcuboot_config/mcuboot_config.h" +#include "bootutil/bootutil_log.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); #if defined(MCUBOOT_SIGN_EC256) || defined(MCUBOOT_SIGN_EC384) @@ -46,6 +49,8 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, uint8_t *pubkey; uint8_t *end; + BOOT_LOG_DBG("bootutil_verify_sig: ECDSA builtin key %d", key_id); + pubkey = (uint8_t *)bootutil_keys[key_id].key; end = pubkey + *bootutil_keys[key_id].len; bootutil_ecdsa_init(&ctx); @@ -75,6 +80,8 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, bootutil_ecdsa_context ctx; FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("bootutil_verify_sig: ECDSA embedded key %hhd", key_id); + /* Use builtin key for image verification, no key parsing is required. */ ctx.key_id = key_id; bootutil_ecdsa_init(&ctx); diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c index ffb8cec3b..4d83bb3d7 100644 --- a/boot/bootutil/src/image_ed25519.c +++ b/boot/bootutil/src/image_ed25519.c @@ -21,8 +21,11 @@ #include "bootutil/crypto/common.h" #endif -#include "bootutil_priv.h" +#include "bootutil/bootutil_log.h" #include "bootutil/crypto/sha.h" +#include "bootutil_priv.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); #define EDDSA_SIGNATURE_LENGTH 64 #define NUM_ED25519_BYTES 32 @@ -90,7 +93,11 @@ bootutil_verify(uint8_t *buf, uint32_t blen, uint8_t *pubkey; uint8_t *end; + BOOT_LOG_DBG("bootutil_verify: ED25519 key_id %d", (int)key_id); + if (slen != EDDSA_SIGNATURE_LENGTH) { + BOOT_LOG_DBG("bootutil_verify: expected slen %d, got %u", + EDDSA_SIGNATURE_LENGTH, (unsigned int)slen); FIH_SET(fih_rc, FIH_FAILURE); goto out; } @@ -101,6 +108,7 @@ bootutil_verify(uint8_t *buf, uint32_t blen, #if !defined(MCUBOOT_KEY_IMPORT_BYPASS_ASN) rc = bootutil_import_key(&pubkey, end); if (rc) { + BOOT_LOG_DBG("bootutil_verify: import key failed %d", rc); FIH_SET(fih_rc, FIH_FAILURE); goto out; } @@ -110,6 +118,7 @@ bootutil_verify(uint8_t *buf, uint32_t blen, * There is no check whether this is the correct key, * here, by the algorithm selected. */ + BOOT_LOG_DBG("bootutil_verify: bypass ASN1"); if (*bootutil_keys[key_id].len < NUM_ED25519_BYTES) { FIH_SET(fih_rc, FIH_FAILURE); goto out; @@ -144,7 +153,11 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, { FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("bootutil_verify_sig: ED25519 key_id %d", (int)key_id); + if (hlen != IMAGE_HASH_SIZE) { + BOOT_LOG_DBG("bootutil_verify_sig: expected hlen %d, got %d", + IMAGE_HASH_SIZE, hlen); FIH_SET(fih_rc, FIH_FAILURE); goto out; } @@ -167,6 +180,8 @@ bootutil_verify_img(uint8_t *img, uint32_t size, { FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("bootutil_verify_img: ED25519 key_id %d", (int)key_id); + FIH_CALL(bootutil_verify, fih_rc, img, size, sig, slen, key_id); diff --git a/boot/bootutil/src/image_rsa.c b/boot/bootutil/src/image_rsa.c index 778a92b46..5479b75eb 100644 --- a/boot/bootutil/src/image_rsa.c +++ b/boot/bootutil/src/image_rsa.c @@ -28,6 +28,9 @@ #include #include "mcuboot_config/mcuboot_config.h" +#include "bootutil/bootutil_log.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); #ifdef MCUBOOT_SIGN_RSA #include "bootutil_priv.h" @@ -267,6 +270,8 @@ bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen, uint8_t *cp; uint8_t *end; + BOOT_LOG_DBG("bootutil_verify_sig: RSA key_id %d", key_id); + bootutil_rsa_init(&ctx); cp = (uint8_t *)bootutil_keys[key_id].key; diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 521251a40..eec678724 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -41,6 +41,9 @@ #include "bootutil/fault_injection_hardening.h" #include "mcuboot_config/mcuboot_config.h" +#include "bootutil/bootutil_log.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" @@ -107,6 +110,7 @@ bootutil_img_hash(struct boot_loader_state *state, (void)tmp_buf_sz; #endif #endif + BOOT_LOG_DBG("bootutil_img_hash"); #ifdef MCUBOOT_ENC_IMAGES if (state == NULL) { @@ -120,6 +124,7 @@ bootutil_img_hash(struct boot_loader_state *state, /* Encrypted images only exist in the secondary slot */ if (MUST_DECRYPT(fap, image_index, hdr) && !boot_enc_valid(enc_state, 1)) { + BOOT_LOG_DBG("bootutil_img_hash: error encrypted image found in primary slot"); return -1; } #endif @@ -187,6 +192,8 @@ bootutil_img_hash(struct boot_loader_state *state, #endif if (rc) { bootutil_sha_drop(&sha_ctx); + BOOT_LOG_DBG("bootutil_img_validate Error %d reading data chunk %p %u %u", + rc, fap, off, blk_sz); return rc; } #ifdef MCUBOOT_ENC_IMAGES @@ -280,6 +287,8 @@ bootutil_find_key(uint8_t *keyhash, uint8_t keyhash_len) 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; } @@ -308,6 +317,8 @@ bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) 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); @@ -518,6 +529,8 @@ bootutil_img_validate(struct boot_loader_state *state, FIH_DECLARE(security_counter_valid, FIH_FAILURE); #endif + BOOT_LOG_DBG("bootutil_img_validate: flash area %p", fap); + #if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) #if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_SERIAL_RECOVERY) rc = bootutil_img_hash(state, hdr, fap, tmp_buf, tmp_buf_sz, hash, seed, seed_len, @@ -538,7 +551,8 @@ bootutil_img_validate(struct boot_loader_state *state, /* If Pure type signature is expected then it has to be there */ rc = bootutil_check_for_pure(hdr, fap); if (rc != 0) { - goto out; + BOOT_LOG_DBG("bootutil_img_validate: pure expected"); + goto out; } #endif @@ -552,6 +566,7 @@ bootutil_img_validate(struct boot_loader_state *state, rc = bootutil_tlv_iter_begin(&it, hdr, fap, IMAGE_TLV_ANY, false); if (rc) { + BOOT_LOG_DBG("bootutil_img_validate: TLV iteration failed %d", rc); goto out; } @@ -560,9 +575,11 @@ bootutil_img_validate(struct boot_loader_state *state, #else img_sz = it.tlv_end; #endif + BOOT_LOG_DBG("bootutil_img_validate: TLV off %u, end %u", it.tlv_off, it.tlv_end); if (img_sz > bootutil_max_image_size(state, fap)) { rc = -1; + BOOT_LOG_DBG("bootutil_img_validate: TLV beyond image size"); goto out; } @@ -593,6 +610,7 @@ bootutil_img_validate(struct boot_loader_state *state, } } if (!found) { + BOOT_LOG_DBG("bootutil_img_validate: TLV %d not permitted", type); FIH_SET(fih_rc, FIH_FAILURE); goto out; } @@ -602,6 +620,7 @@ bootutil_img_validate(struct boot_loader_state *state, #if defined(EXPECTED_HASH_TLV) && !defined(MCUBOOT_SIGN_PURE) case EXPECTED_HASH_TLV: { + BOOT_LOG_DBG("bootutil_img_validate: EXPECTED_HASH_TLV == %d", EXPECTED_HASH_TLV); /* Verify the image hash. This must always be present. */ if (len != sizeof(hash)) { rc = -1; @@ -625,6 +644,7 @@ bootutil_img_validate(struct boot_loader_state *state, #ifdef EXPECTED_KEY_TLV case EXPECTED_KEY_TLV: { + BOOT_LOG_DBG("bootutil_img_validate: EXPECTED_KEY_TLV == %d", EXPECTED_KEY_TLV); /* * Determine which key we should be checking. */ @@ -655,6 +675,7 @@ bootutil_img_validate(struct boot_loader_state *state, #ifdef EXPECTED_SIG_TLV case EXPECTED_SIG_TLV: { + BOOT_LOG_DBG("bootutil_img_validate: EXPECTED_SIG_TLV == %d", EXPECTED_SIG_TLV); /* Ignore this signature if it is out of bounds. */ if (key_id < 0 || key_id >= bootutil_key_cnt) { key_id = -1; diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 62f980b69..6654245ad 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -283,6 +283,19 @@ static int boot_version_cmp(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; } @@ -554,6 +567,7 @@ boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot) fap = BOOT_IMG_AREA(state, slot); assert(fap != NULL); + BOOT_LOG_DBG("boot_verify_slot_dependencies"); #if defined(MCUBOOT_SWAP_USING_OFFSET) it.start_off = boot_get_state_secondary_offset(state, fap); #endif @@ -581,6 +595,8 @@ boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot) rc = LOAD_IMAGE_DATA(boot_img_hdr(state, slot), fap, off, &dep, len); if (rc != 0) { + BOOT_LOG_DBG("boot_verify_slot_dependencies: error %d reading dependency %p %d %d", + rc, fap, off, len); rc = BOOT_EFLASH; goto done; } @@ -593,6 +609,7 @@ boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot) /* Verify dependency and modify the swap type if not satisfied. */ rc = boot_verify_slot_dependency(state, &dep); if (rc != 0) { + BOOT_LOG_DBG("boot_verify_slot_dependencies: not satisfied"); /* Dependency not satisfied */ goto done; } @@ -1005,6 +1022,9 @@ boot_validate_slot(struct boot_loader_state *state, int slot, 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); + #if !defined(MCUBOOT_SWAP_USING_OFFSET) (void)expected_swap_type; #endif @@ -1250,6 +1270,8 @@ boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size, b { int rc = 0; + BOOT_LOG_DBG("boot_scramble_region: %p %d %d %d", fa, off, size, (int)backwards); + if (size == 0) { goto done; } @@ -1264,6 +1286,7 @@ boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size, b 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) { @@ -1273,11 +1296,14 @@ boot_scramble_region(const struct flash_area *fa, uint32_t off, uint32_t size, b } 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; } @@ -2348,6 +2374,8 @@ context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp) bool has_upgrade; volatile int fih_cnt; + BOOT_LOG_DBG("context_boot_go"); + #if defined(__BOOTSIM__) /* The array of slot sectors are defined here (as opposed to file scope) so * that they don't get allocated for non-boot-loader apps. This is @@ -3216,6 +3244,8 @@ static void boot_fetch_slot_state_sizes(void) assert(rc == 0); if (rc != 0) { + BOOT_LOG_DBG("boot_fetch_slot_state_sizes: error %d for %d", + rc, fa_id); goto finish; } } diff --git a/boot/bootutil/src/swap_misc.c b/boot/bootutil/src/swap_misc.c index ac9412b0f..a4c39c20a 100644 --- a/boot/bootutil/src/swap_misc.c +++ b/boot/bootutil/src/swap_misc.c @@ -80,7 +80,7 @@ swap_scramble_trailer_sectors(const struct boot_loader_state *state, size_t off; int rc; - BOOT_LOG_DBG("Scrambling trailer; fa_id=%d", flash_area_get_id(fap)); + BOOT_LOG_DBG("swap_scramble_trailer_sectors: fa_id=%d", flash_area_get_id(fap)); /* Delete starting from last sector and moving to beginning */ rc = boot_trailer_scramble_offset(fap, BOOT_WRITE_SZ(state), &off); diff --git a/boot/bootutil/src/tlv.c b/boot/bootutil/src/tlv.c index 629bc235d..a69b3d8bd 100644 --- a/boot/bootutil/src/tlv.c +++ b/boot/bootutil/src/tlv.c @@ -21,9 +21,12 @@ #include #include "bootutil/bootutil.h" +#include "bootutil/bootutil_log.h" #include "bootutil/image.h" #include "bootutil_priv.h" +BOOT_LOG_MODULE_DECLARE(mcuboot); + /* * Initialize a TLV iterator. * @@ -43,6 +46,8 @@ bootutil_tlv_iter_begin(struct image_tlv_iter *it, const struct image_header *hd uint32_t off_; struct image_tlv_info info; + BOOT_LOG_DBG("bootutil_tlv_iter_begin: type %d, prot == %d", type, (int)prot); + if (it == NULL || hdr == NULL || fap == NULL) { return -1; } @@ -108,6 +113,9 @@ bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off, uint16_t *len, return -1; } + BOOT_LOG_DBG("bootutil_tlv_iter_next: searching for %d (%d is any) starting at %d ending at %d", + it->type, IMAGE_TLV_ANY, it->tlv_off, it->tlv_end); + while (it->tlv_off < it->tlv_end) { if (it->hdr->ih_protect_tlv_size > 0 && it->tlv_off == it->prot_end) { it->tlv_off += sizeof(struct image_tlv_info); @@ -115,11 +123,14 @@ bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off, uint16_t *len, rc = LOAD_IMAGE_DATA(it->hdr, it->fap, it->tlv_off, &tlv, sizeof tlv); if (rc) { + BOOT_LOG_DBG("bootutil_tlv_iter_next: load failed with %d for %p %d", + rc, it->fap, it->tlv_off); return -1; } /* No more TLVs in the protected area */ if (it->prot && it->tlv_off >= it->prot_end) { + BOOT_LOG_DBG("bootutil_tlv_iter_next: protected TLV %d not found", it->type); return 1; } @@ -130,12 +141,15 @@ bootutil_tlv_iter_next(struct image_tlv_iter *it, uint32_t *off, uint16_t *len, *off = it->tlv_off + sizeof(tlv); *len = tlv.it_len; it->tlv_off += sizeof(tlv) + tlv.it_len; + BOOT_LOG_DBG("bootutil_tlv_iter_next: TLV %d found at %d (size %d)", + *type, *off, *len); return 0; } it->tlv_off += sizeof(tlv) + tlv.it_len; } + BOOT_LOG_DBG("bootutil_tlv_iter_next: TLV %d not found", it->type); return 1; } From eaa6a90bce63822bfb2e3691681e39abe739dcd8 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 15 May 2025 15:45:44 +0000 Subject: [PATCH 010/125] [nrf fromtree] zephyr: Improve logging Improve logging to make it easier to track image validation failures in development. Signed-off-by: Dominik Ermel (cherry picked from commit c5011f2b75ebdf3327a6530b38ab9f9f3ff7a0f7) --- boot/zephyr/firmware_loader.c | 8 ++++++++ boot/zephyr/main.c | 8 ++++++++ boot/zephyr/single_loader.c | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/boot/zephyr/firmware_loader.c b/boot/zephyr/firmware_loader.c index d0f70af4a..1df848634 100644 --- a/boot/zephyr/firmware_loader.c +++ b/boot/zephyr/firmware_loader.c @@ -40,6 +40,8 @@ boot_image_validate(const struct flash_area *fa_p, static uint8_t tmpbuf[BOOT_TMPBUF_SZ]; FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("boot_image_validate: encrypted == %d", (int)IS_ENCRYPTED(hdr)); + /* NOTE: The first argument to boot_image_validate, for enc_state pointer, * is allowed to be NULL only because the single image loader compiles * with BOOT_IMAGE_NUMBER == 1, which excludes the code that uses @@ -71,6 +73,8 @@ boot_image_validate_once(const struct flash_area *fa_p, int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("boot_image_validate_once: flash area %p", fap_p); + memset(&state, 0, sizeof(struct boot_swap_state)); rc = boot_read_swap_state(fa_p, &state); if (rc != 0) @@ -108,6 +112,8 @@ static fih_ret validate_image_slot(int slot, struct boot_rsp *rsp) int rc = -1; FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("validate_image_slot: slot %d", slot); + rc = flash_area_open(slot, &_fa_p); assert(rc == 0); @@ -156,6 +162,8 @@ boot_go(struct boot_rsp *rsp) bool boot_firmware_loader = false; FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("boot_go: firmware loader"); + #ifdef CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO if (io_detect_pin() && !io_boot_skip_serial_recovery()) { diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index ddea864de..2e57bd999 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -463,6 +463,7 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_STARTUP); #ifdef CONFIG_BOOT_SERIAL_ENTRANCE_GPIO + BOOT_LOG_DBG("Checking GPIO for serial recovery"); if (io_detect_pin() && !io_boot_skip_serial_recovery()) { boot_serial_enter(); @@ -470,13 +471,17 @@ int main(void) #endif #ifdef CONFIG_BOOT_SERIAL_PIN_RESET + BOOT_LOG_DBG("Checking RESET pin for serial recovery"); if (io_detect_pin_reset()) { boot_serial_enter(); } #endif #if defined(CONFIG_BOOT_USB_DFU_GPIO) + BOOT_LOG_DBG("Checking GPIO for USB DFU request"); if (io_detect_pin()) { + BOOT_LOG_DBG("Entering USB DFU"); + usb_dfu_requested = true; #ifdef CONFIG_MCUBOOT_INDICATION_LED @@ -498,6 +503,7 @@ int main(void) BOOT_LOG_INF("Waiting for USB DFU"); #if defined(CONFIG_BOOT_USB_DFU_WAIT) + BOOT_LOG_DBG("Waiting for USB DFU for %dms", CONFIG_BOOT_USB_DFU_WAIT_DELAY_MS); mcuboot_status_change(MCUBOOT_STATUS_USB_DFU_WAITING); wait_for_usb_dfu(K_MSEC(CONFIG_BOOT_USB_DFU_WAIT_DELAY_MS)); BOOT_LOG_INF("USB DFU wait time elapsed"); @@ -529,12 +535,14 @@ int main(void) if (FIH_EQ(fih_rc, FIH_BOOT_HOOK_REGULAR)) { FIH_CALL(boot_go, fih_rc, &rsp); } + BOOT_LOG_DBG("Left boot_go with success == %d", FIH_EQ(fih_rc, FIH_SUCCESS) ? 1 : 0); #ifdef CONFIG_BOOT_SERIAL_BOOT_MODE if (io_detect_boot_mode()) { /* Boot mode to stay in bootloader, clear status and enter serial * recovery mode */ + BOOT_LOG_DBG("Staying in serial recovery"); boot_serial_enter(); } #endif diff --git a/boot/zephyr/single_loader.c b/boot/zephyr/single_loader.c index 28e9cdf15..31c4a8bf7 100644 --- a/boot/zephyr/single_loader.c +++ b/boot/zephyr/single_loader.c @@ -44,6 +44,8 @@ boot_image_validate(const struct flash_area *fa_p, static uint8_t tmpbuf[BOOT_TMPBUF_SZ]; FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("boot_image_validate: encrypted == %d", (int)IS_ENCRYPTED(hdr)); + /* NOTE: The first argument to boot_image_validate, for enc_state pointer, * is allowed to be NULL only because the single image loader compiles * with BOOT_IMAGE_NUMBER == 1, which excludes the code that uses @@ -75,6 +77,8 @@ boot_image_validate_once(const struct flash_area *fa_p, int rc; FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("boot_image_validate_once: flash area %p", fap_p); + memset(&state, 0, sizeof(struct boot_swap_state)); rc = boot_read_swap_state(fa_p, &state); if (rc != 0) @@ -112,6 +116,8 @@ boot_go(struct boot_rsp *rsp) int rc = -1; FIH_DECLARE(fih_rc, FIH_FAILURE); + BOOT_LOG_DBG("boot_go: Single loader"); + rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(0), &_fa_p); assert(rc == 0); From 0529cbe7a955f006b5f5f2b7e22788cdde541483 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 28 May 2025 17:01:17 +0000 Subject: [PATCH 011/125] [nrf fromtree] bootutil: Small cleanup in image.h Fixed comments indentation. Signed-off-by: Dominik Ermel (cherry picked from commit e56cecc45b70e596052bf3bb0440601e366199f5) --- boot/bootutil/include/bootutil/image.h | 105 ++++++++++++------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h index 15de3e01a..f49eab347 100644 --- a/boot/bootutil/include/bootutil/image.h +++ b/boot/bootutil/include/bootutil/image.h @@ -46,8 +46,6 @@ extern "C" { #define STRUCT_PACKED struct __attribute__((__packed__)) #endif -struct flash_area; - #define IMAGE_MAGIC 0x96f3b83d #define IMAGE_MAGIC_V1 0x96f3b83c #define IMAGE_MAGIC_NONE 0xffffffff @@ -98,50 +96,50 @@ struct flash_area; * 1st on identifies the public key which should be used to verify it. * 2nd one is the actual signature. */ -#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */ -#define IMAGE_TLV_PUBKEY 0x02 /* public key */ -#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ -#define IMAGE_TLV_SHA384 0x11 /* SHA384 of image hdr and body */ -#define IMAGE_TLV_SHA512 0x12 /* SHA512 of image hdr and body */ -#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */ -#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output - Not supported anymore */ -#define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */ -#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */ -#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */ -#define IMAGE_TLV_SIG_PURE 0x25 /* Indicator that attached signature has been prepared - * over image rather than its digest. - */ -#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */ -#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW 128 or 256*/ -#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */ -#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */ -#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */ -#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */ -#define IMAGE_TLV_BOOT_RECORD 0x60 /* measured boot record */ +#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */ +#define IMAGE_TLV_PUBKEY 0x02 /* public key */ +#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */ +#define IMAGE_TLV_SHA384 0x11 /* SHA384 of image hdr and body */ +#define IMAGE_TLV_SHA512 0x12 /* SHA512 of image hdr and body */ +#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */ +#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output - Not supported anymore */ +#define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */ +#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */ +#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */ +#define IMAGE_TLV_SIG_PURE 0x25 /* Indicator that attached signature has been prepared + * over image rather than its digest. + */ +#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */ +#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW 128 or 256*/ +#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */ +#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */ +#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */ +#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */ +#define IMAGE_TLV_BOOT_RECORD 0x60 /* measured boot record */ /* The following flags relate to compressed images and are for the decompressed image data */ -#define IMAGE_TLV_DECOMP_SIZE 0x70 /* Decompressed image size excluding header/TLVs */ -#define IMAGE_TLV_DECOMP_SHA 0x71 /* - * Decompressed image shaX hash, this field must match - * the format and size of the raw slot (compressed) - * shaX hash - */ -#define IMAGE_TLV_DECOMP_SIGNATURE 0x72 /* - * Decompressed image signature, this field must match - * the format and size of the raw slot (compressed) - * signature - */ -#define IMAGE_TLV_COMP_DEC_SIZE 0x73 /* Compressed decrypted image size */ - /* - * vendor reserved TLVs at xxA0-xxFF, - * where xx denotes the upper byte - * range. Examples: - * 0x00a0 - 0x00ff - * 0x01a0 - 0x01ff - * 0x02a0 - 0x02ff - * ... - * 0xffa0 - 0xfffe - */ -#define IMAGE_TLV_ANY 0xffff /* Used to iterate over all TLV */ +#define IMAGE_TLV_DECOMP_SIZE 0x70 /* Decompressed image size excluding header/TLVs */ +#define IMAGE_TLV_DECOMP_SHA 0x71 /* + * Decompressed image shaX hash, this field must match + * the format and size of the raw slot (compressed) + * shaX hash + */ +#define IMAGE_TLV_DECOMP_SIGNATURE 0x72 /* + * Decompressed image signature, this field must match + * the format and size of the raw slot (compressed) + * signature + */ +#define IMAGE_TLV_COMP_DEC_SIZE 0x73 /* Compressed decrypted image size */ + /* + * vendor reserved TLVs at xxA0-xxFF, + * where xx denotes the upper byte + * range. Examples: + * 0x00a0 - 0x00ff + * 0x01a0 - 0x01ff + * 0x02a0 - 0x02ff + * ... + * 0xffa0 - 0xfffe + */ +#define IMAGE_TLV_ANY 0xffff /* Used to iterate over all TLV */ STRUCT_PACKED image_version { uint8_t iv_major; @@ -164,10 +162,10 @@ struct image_dependency { STRUCT_PACKED image_header { uint32_t ih_magic; uint32_t ih_load_addr; - uint16_t ih_hdr_size; /* Size of image header (bytes). */ - uint16_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */ - uint32_t ih_img_size; /* Does not include header. */ - uint32_t ih_flags; /* IMAGE_F_[...]. */ + uint16_t ih_hdr_size; /* Size of image header (bytes). */ + uint16_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */ + uint32_t ih_img_size; /* Does not include header. */ + uint32_t ih_flags; /* IMAGE_F_[...]. */ struct image_version ih_ver; uint32_t _pad1; }; @@ -175,13 +173,13 @@ STRUCT_PACKED image_header { /** Image TLV header. All fields in little endian. */ STRUCT_PACKED image_tlv_info { uint16_t it_magic; - uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */ + uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */ }; /** Image trailer TLV format. All fields in little endian. */ STRUCT_PACKED image_tlv { - uint16_t it_type; /* IMAGE_TLV_[...]. */ - uint16_t it_len; /* Data length (not including TLV header). */ + uint16_t it_type; /* IMAGE_TLV_[...]. */ + uint16_t it_len; /* Data length (not including TLV header). */ }; #define ENCRYPTIONFLAGS (IMAGE_F_ENCRYPTED_AES128 | IMAGE_F_ENCRYPTED_AES256) @@ -199,8 +197,9 @@ STRUCT_PACKED image_tlv { _Static_assert(sizeof(struct image_header) == IMAGE_HEADER_SIZE, "struct image_header not required size"); -struct enc_key_data; struct boot_loader_state; +struct flash_area; + fih_ret bootutil_img_validate(struct boot_loader_state *state, struct image_header *hdr, const struct flash_area *fap, From 860d366a4b150918b7abf27df20d5246eb4cb235 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 7 May 2025 16:01:02 +0000 Subject: [PATCH 012/125] [nrf fromtree] doc: Add information on supporting SHA512 with ECIES-X25519 Information on TLV and format. Signed-off-by: Dominik Ermel (cherry picked from commit e542295f266a63657f18a2e6a77723941cc8d0b3) --- docs/encrypted_images.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/encrypted_images.md b/docs/encrypted_images.md index ebc4f46ed..5f775ef18 100644 --- a/docs/encrypted_images.md +++ b/docs/encrypted_images.md @@ -92,24 +92,33 @@ libraries. The whole key encryption can be summarized as: keypair. Those keys will be our ephemeral keys. * Generate a new secret (DH) using the ephemeral private key and the public key that corresponds to the private key embedded in the HW. -* Derive the new keys from the secret using HKDF (built on HMAC-SHA256). We - are not using a `salt` and using an `info` of `MCUBoot_ECIES_v1`, generating - 48 bytes of key material. +* Derive the new keys from the secret using HKDF. We are not using a `salt` + and using an `info` of `MCUBoot_ECIES_v1`, generating 48 bytes of key material. * A new random encryption key is generated (for AES). This is the AES key used to encrypt the images. * The key is encrypted with AES-128-CTR or AES-256-CTR and a `nonce` of 0 using the first 16 bytes of key material generated previously by the HKDF. -* The encrypted key now goes through a HMAC-SHA256 using the remaining 32 +* The encrypted key now goes through a HMAC using the remaining 32 bytes of key material from the HKDF. +There are different TLVs for ECIES-P256, ECIES-X25519 with SHA256 HKDF/HMAC +and ECIES-X25519 with SHA512 HKDF/HMAC. The final TLV is built from the 65 bytes for ECIES-P256 or 32 bytes for ECIES-X25519, which correspond to the ephemeral public key, followed by the -32 bytes of MAC tag and the 16 or 32 bytes of the encrypted key, resulting in -a TLV of 113 or 129 bytes for ECIES-P256 and 80 or 96 bytes for ECIES-X25519. +MAC tag and the 16 or 32 bytes of the encrypted key, resulting in final TLV +length: + * ECIES-P256 has TLV length 113 to 129 bytes, depending on AES key length. + * ECIES-X25519 on SHA256 TLV length is 80 or 96 bytes, depending on AES key + length. + * ECIES-X25519 on SHA512 TLV length is 112 or 128, depending on AES key + length. The implemenation of ECIES-P256 is named ENC_EC256 in the source code and artifacts while ECIES-X25519 is named ENC_X25519. +Note that MCUboot is built to support only one ECIES and HMAC SHA at once, +and truncated HMAC is not supported at this time + ## [Upgrade process](#upgrade-process) When starting a new upgrade process, `MCUboot` checks that the image in the From 736d33ee0e557481df17bec4ecfe9990f562340c Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 8 May 2025 19:38:29 +0000 Subject: [PATCH 013/125] [nrf fromtree] bootutil: Add support for HAMC-SHA512 with ECIES-X25519 Add support for HKDF/HMAC based on SHA512 for ECIES-X25519 key exchange. The commit adds MCUBOOT_HMAC_SHA512 that enables new TLV IMAGE_TLV_ENC_X25519_SHA512. Encryption code has been altered to support the MCUBOOT_HMAC_SHA512. Signed-off-by: Dominik Ermel (cherry picked from commit 1d83177ca286122395b105bfddbaa854aae20748) --- boot/bootutil/include/bootutil/enc_key_public.h | 17 +++++++++++++++-- boot/bootutil/include/bootutil/image.h | 3 +++ boot/bootutil/src/encrypted_psa.c | 12 +++++++++--- boot/bootutil/src/image_validate.c | 4 ++++ 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/boot/bootutil/include/bootutil/enc_key_public.h b/boot/bootutil/include/bootutil/enc_key_public.h index 55b06b025..4582dfcf7 100644 --- a/boot/bootutil/include/bootutil/enc_key_public.h +++ b/boot/bootutil/include/bootutil/enc_key_public.h @@ -70,10 +70,19 @@ extern "C" { # define BOOT_ENC_KEY_SIZE 16 #endif +#ifdef MCUBOOT_HMAC_SHA512 +# define BOOT_HMAC_SIZE 64 +#else +# define BOOT_HMAC_SIZE 32 +#endif + #if defined(MCUBOOT_ENCRYPT_RSA) # define BOOT_ENC_TLV_SIZE (256) # define BOOT_ENC_TLV IMAGE_TLV_ENC_RSA2048 #elif defined(MCUBOOT_ENCRYPT_EC256) +# if defined(MCUBOOT_HMAC_SHA512) +# error "ECIES-P256 does not support HMAC-SHA512" +# endif # define EC_PUBK_LEN (65) # define EC_PRIVK_LEN (32) # define EC_SHARED_LEN (32) @@ -82,7 +91,11 @@ extern "C" { # define EC_PUBK_LEN (32) # define EC_PRIVK_LEN (32) # define EC_SHARED_LEN (32) -# define BOOT_ENC_TLV IMAGE_TLV_ENC_X25519 +# if !defined(MCUBOOT_HMAC_SHA512) +# define BOOT_ENC_TLV IMAGE_TLV_ENC_X25519 +# else +# define BOOT_ENC_TLV IMAGE_TLV_ENC_X25519_SHA512 +# endif #elif defined(MCUBOOT_ENCRYPT_KW) # define BOOT_ENC_TLV_SIZE (BOOT_ENC_KEY_SIZE + 8) # define BOOT_ENC_TLV IMAGE_TLV_ENC_KW @@ -91,7 +104,7 @@ extern "C" { /* Common ECIES definitions */ #if defined(EC_PUBK_LEN) # define EC_PUBK_INDEX (0) -# define EC_TAG_LEN (32) +# define EC_TAG_LEN (BOOT_HMAC_SIZE) # define EC_TAG_INDEX (EC_PUBK_INDEX + EC_PUBK_LEN) # define EC_CIPHERKEY_INDEX (EC_TAG_INDEX + EC_TAG_LEN) # define EC_CIPHERKEY_LEN BOOT_ENC_KEY_SIZE diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h index f49eab347..11c54b633 100644 --- a/boot/bootutil/include/bootutil/image.h +++ b/boot/bootutil/include/bootutil/image.h @@ -113,6 +113,9 @@ extern "C" { #define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW 128 or 256*/ #define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */ #define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */ +#define IMAGE_TLV_ENC_X25519_SHA512 0x34 /* Key exchange using ECIES-X25519 and SHA512 for MAC + * tag and HKDF in key derivation process + */ #define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */ #define IMAGE_TLV_SEC_CNT 0x50 /* security counter */ #define IMAGE_TLV_BOOT_RECORD 0x60 /* measured boot record */ diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c index 6f60a1955..0cfdc9768 100644 --- a/boot/bootutil/src/encrypted_psa.c +++ b/boot/bootutil/src/encrypted_psa.c @@ -27,6 +27,12 @@ BOOT_LOG_MODULE_DECLARE(mcuboot_psa_enc); +#if defined(MCUBOOT_HMAC_SHA512) +#define PSA_HMAC_HKDF_SHA PSA_ALG_SHA_512 +#else +#define PSA_HMAC_HKDF_SHA PSA_ALG_SHA_256 +#endif + #define X25519_OID "\x6e" static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \ MBEDTLS_OID_ORG_GOV X25519_OID; @@ -162,7 +168,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) return -1; } - key_do_alg = PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + key_do_alg = PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_HMAC_HKDF_SHA)); psa_ret = psa_key_derivation_setup(&key_do, key_do_alg); if (psa_ret != PSA_SUCCESS) { @@ -225,7 +231,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) */ psa_set_key_type(&kattr, PSA_KEY_TYPE_HMAC); psa_set_key_usage_flags(&kattr, PSA_KEY_USAGE_VERIFY_MESSAGE); - psa_set_key_algorithm(&kattr, PSA_ALG_HMAC(PSA_ALG_SHA_256)); + psa_set_key_algorithm(&kattr, PSA_ALG_HMAC(PSA_HMAC_HKDF_SHA)); /* Import the MAC tag key part of derived key */ psa_ret = psa_import_key(&kattr, @@ -239,7 +245,7 @@ boot_decrypt_key(const uint8_t *buf, uint8_t *enckey) } /* Verify the MAC tag of the random encryption key */ - psa_ret = psa_mac_verify(kid, PSA_ALG_HMAC(PSA_ALG_SHA_256), + psa_ret = psa_mac_verify(kid, PSA_ALG_HMAC(PSA_HMAC_HKDF_SHA), &buf[EC_CIPHERKEY_INDEX], EC_CIPHERKEY_LEN, &buf[EC_TAG_INDEX], EC_TAG_LEN); diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index eec678724..f6d4ba224 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -474,7 +474,11 @@ static const uint16_t allowed_unprot_tlvs[] = { IMAGE_TLV_ENC_RSA2048, IMAGE_TLV_ENC_KW, IMAGE_TLV_ENC_EC256, +#if !defined(MCUBOOT_HMAC_SHA512) IMAGE_TLV_ENC_X25519, +#else + IMAGE_TLV_ENC_X25519_SHA512, +#endif /* Mark end with ANY. */ IMAGE_TLV_ANY, }; From 1a457e304f3c879db9a5a170992a3af376b1d430 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 8 May 2025 19:45:39 +0000 Subject: [PATCH 014/125] [nrf fromtree] zephyr: Support for HKDF/HMAC with SHA512 The commit adds CONFIG_BOOT_HMAC_SHA512 that enables MCUboot configuration option MCUBOOT_HMAC_SHA512, that is used for switching HKDF/HMAC in ECIES key exchange to SHA512, from default SHA256. This option, currently, is only available for ECIES-X25519 with PSA as crypto backend. Signed-off-by: Dominik Ermel (cherry picked from commit 377191693ca934a1791fe76011dc589454138ca7) --- boot/zephyr/Kconfig | 9 +++++++++ boot/zephyr/include/mcuboot_config/mcuboot_config.h | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index acc0314a6..dc445b4ed 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -601,6 +601,15 @@ config BOOT_ENCRYPT_X25519 help Hidden option selecting x25519 encryption. +config BOOT_HMAC_SHA512 + bool "Use SHA512 for HMAC/HKDF" + depends on BOOT_ENCRYPT_X25519 + depends on BOOT_USE_PSA_CRYPTO + help + By default SHA256 is used for HKDF/HMAC in key exchange expansion + and verification. This options switches to SHA512. The option is + mainly useful to reduce numer of compiled in SHA algorithms. + config BOOT_ENCRYPTION_KEY_FILE string "Encryption key file" depends on BOOT_ENCRYPT_IMAGE diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index fd003565a..820ffd752 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -153,6 +153,13 @@ #define MCUBOOT_ENCRYPT_X25519 #endif +/* Support for HMAC/HKDF using SHA512; this is used in key exchange where + * HKDF is used for key expansion and HMAC is used for key verification. + */ +#ifdef CONFIG_BOOT_HMAC_SHA512 +#define MCUBOOT_HMAC_SHA512 +#endif + #ifdef CONFIG_BOOT_DECOMPRESSION #define MCUBOOT_DECOMPRESS_IMAGES #endif From c4c82e20aed038dc62fef8d2499afa162d3d8e9d Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 9 May 2025 15:28:47 +0000 Subject: [PATCH 015/125] [nrf fromtree] imgtool: Add support for HMAC/HKDF-SHA512 with ECIES-X25519 Commit adds imgtool command line option --hmac-sha allowing to select between SHA256 and SHA512 for HMAC/HKDF. Signed-off-by: Dominik Ermel (cherry picked from commit a36f951307dbb170d5e6a1f23603dc8edd6af80d) --- scripts/imgtool/image.py | 37 +++++++++++++++++++++++++++---------- scripts/imgtool/main.py | 11 +++++++---- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index c7fb9e553..03e2cbb62 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -88,6 +88,7 @@ 'ENCKW': 0x31, 'ENCEC256': 0x32, 'ENCX25519': 0x33, + 'ENCX25519_SHA512': 0x34, 'DEPENDENCY': 0x40, 'SEC_CNT': 0x50, 'BOOT_RECORD': 0x60, @@ -435,7 +436,7 @@ def check_trailer(self): len(self.payload), tsize, self.slot_size) raise click.UsageError(msg) - def ecies_hkdf(self, enckey, plainkey): + def ecies_hkdf(self, enckey, plainkey, hmac_sha_alg): if isinstance(enckey, ecdsa.ECDSA256P1Public): newpk = ec.generate_private_key(ec.SECP256R1(), default_backend()) shared = newpk.exchange(ec.ECDH(), enckey._get_public()) @@ -443,13 +444,13 @@ def ecies_hkdf(self, enckey, plainkey): newpk = X25519PrivateKey.generate() shared = newpk.exchange(enckey._get_public()) derived_key = HKDF( - algorithm=hashes.SHA256(), length=48, salt=None, + algorithm=hmac_sha_alg, length=48, salt=None, info=b'MCUBoot_ECIES_v1', backend=default_backend()).derive(shared) encryptor = Cipher(algorithms.AES(derived_key[:16]), modes.CTR(bytes([0] * 16)), backend=default_backend()).encryptor() cipherkey = encryptor.update(plainkey) + encryptor.finalize() - mac = hmac.HMAC(derived_key[16:], hashes.SHA256(), + mac = hmac.HMAC(derived_key[16:], hmac_sha_alg, backend=default_backend()) mac.update(cipherkey) ciphermac = mac.finalize() @@ -467,7 +468,8 @@ def create(self, key, public_key_format, enckey, dependencies=None, sw_type=None, custom_tlvs=None, compression_tlvs=None, compression_type=None, encrypt_keylen=128, clear=False, fixed_sig=None, pub_key=None, vector_to_sign=None, - user_sha='auto', is_pure=False, keep_comp_size=False, dont_encrypt=False): + user_sha='auto', hmac_sha='auto', is_pure=False, keep_comp_size=False, + dont_encrypt=False): self.enckey = enckey # key decides on sha, then pub_key; of both are none default is used @@ -674,6 +676,17 @@ def create(self, key, public_key_format, enckey, dependencies=None, else: plainkey = os.urandom(16) + if not isinstance(enckey, rsa.RSAPublic): + if hmac_sha == 'auto' or hmac_sha == '256': + hmac_sha = '256' + hmac_sha_alg = hashes.SHA256() + elif hmac_sha == '512': + if not isinstance(enckey, x25519.X25519Public): + raise click.UsageError("Currently only ECIES-X25519 supports HMAC-SHA512") + hmac_sha_alg = hashes.SHA512() + else: + raise click.UsageError("Unsupported HMAC-SHA") + if isinstance(enckey, rsa.RSAPublic): cipherkey = enckey._get_public().encrypt( plainkey, padding.OAEP( @@ -682,15 +695,19 @@ def create(self, key, public_key_format, enckey, dependencies=None, label=None)) self.enctlv_len = len(cipherkey) tlv.add('ENCRSA2048', cipherkey) - elif isinstance(enckey, (ecdsa.ECDSA256P1Public, - x25519.X25519Public)): - cipherkey, mac, pubk = self.ecies_hkdf(enckey, plainkey) + elif isinstance(enckey, ecdsa.ECDSA256P1Public): + cipherkey, mac, pubk = self.ecies_hkdf(enckey, plainkey, hmac_sha_alg) enctlv = pubk + mac + cipherkey self.enctlv_len = len(enctlv) - if isinstance(enckey, ecdsa.ECDSA256P1Public): - tlv.add('ENCEC256', enctlv) - else: + tlv.add('ENCEC256', enctlv) + elif isinstance(enckey, x25519.X25519Public): + cipherkey, mac, pubk = self.ecies_hkdf(enckey, plainkey, hmac_sha_alg) + enctlv = pubk + mac + cipherkey + self.enctlv_len = len(enctlv) + if (hmac_sha == '256'): tlv.add('ENCX25519', enctlv) + else: + tlv.add('ENCX25519_SHA512', enctlv) if not clear: nonce = bytes([0] * 16) diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index 78f2e77ec..5ff1f8f9f 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -84,6 +84,7 @@ def gen_x25519(keyfile, passwd): } valid_formats = ['openssl', 'pkcs8'] valid_sha = [ 'auto', '256', '384', '512' ] +valid_hmac_sha = [ 'auto', '256', '512' ] def load_signature(sigfile): @@ -437,6 +438,8 @@ def convert(self, value, param, ctx): @click.option('--sha', 'user_sha', type=click.Choice(valid_sha), default='auto', help='selected sha algorithm to use; defaults to "auto" which is 256 if ' 'no cryptographic signature is used, or default for signature type') +@click.option('--hmac-sha', 'hmac_sha', type=click.Choice(valid_hmac_sha), default='auto', + help='sha algorithm used in HKDF/HMAC in ECIES key exchange TLV') @click.option('--vector-to-sign', type=click.Choice(['payload', 'digest']), help='send to OUTFILE the payload or payload''s digest instead ' 'of complied image. These data can be used for external image ' @@ -449,7 +452,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, 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, is_pure, + clear, fix_sig, fix_sig_pubkey, sig_out, user_sha, hmac_sha, is_pure, vector_to_sign, non_bootable): if confirm: @@ -526,7 +529,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, img.create(key, public_key_format, enckey, dependencies, boot_record, custom_tlvs, compression_tlvs, None, int(encrypt_keylen), clear, baked_signature, pub_key, vector_to_sign, user_sha=user_sha, - is_pure=is_pure, keep_comp_size=False, dont_encrypt=True) + hmac_sha=hmac_sha, is_pure=is_pure, keep_comp_size=False, dont_encrypt=True) compressed_img = image.Image(version=decode_version(version), header_size=header_size, pad_header=pad_header, pad=pad, confirm=confirm, align=int(align), @@ -570,14 +573,14 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, compressed_img.create(key, public_key_format, enckey, dependencies, boot_record, custom_tlvs, compression_tlvs, compression, int(encrypt_keylen), clear, baked_signature, - pub_key, vector_to_sign, user_sha=user_sha, + pub_key, vector_to_sign, user_sha=user_sha, hmac_sha=hmac_sha, is_pure=is_pure, keep_comp_size=keep_comp_size) img = compressed_img else: img.create(key, public_key_format, enckey, dependencies, boot_record, custom_tlvs, compression_tlvs, None, int(encrypt_keylen), clear, baked_signature, pub_key, vector_to_sign, user_sha=user_sha, - is_pure=is_pure) + hmac_sha=hmac_sha, is_pure=is_pure) img.save(outfile, hex_addr) if sig_out is not None: new_signature = img.get_signature() From 80f8e8c926b6e4c7e8a3fca4e97867575ed39300 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Tue, 1 Jul 2025 16:43:52 +0200 Subject: [PATCH 016/125] [nrf fromtree] bootutil: Use flash base address for direct hash Fetch the flash base address if direct hash calculation is performed. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 6a178d29f98ff5288c9534474ae72fe1ab499e1f) --- boot/bootutil/src/image_validate.c | 11 ++++++++++- docs/release-notes.d/fix-direct-hash-base-address.md | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 docs/release-notes.d/fix-direct-hash-base-address.md diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index f6d4ba224..17193a63d 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -87,6 +87,10 @@ bootutil_img_hash(struct boot_loader_state *state, uint32_t off; uint32_t blk_sz; #endif +#ifdef MCUBOOT_HASH_STORAGE_DIRECTLY + uintptr_t base = 0; + int fa_ret; +#endif #if defined(MCUBOOT_ENC_IMAGES) struct enc_key_data *enc_state; int image_index; @@ -160,7 +164,12 @@ bootutil_img_hash(struct boot_loader_state *state, /* No chunk loading, storage is mapped to address space and can * be directly given to hashing function. */ - bootutil_sha_update(&sha_ctx, (void *)flash_area_get_off(fap), size); + fa_ret = flash_device_base(flash_area_get_device_id(fap), &base); + if (fa_ret != 0) { + base = 0; + } + + bootutil_sha_update(&sha_ctx, (void *)(base + flash_area_get_off(fap)), size); #else /* MCUBOOT_HASH_STORAGE_DIRECTLY */ #ifdef MCUBOOT_RAM_LOAD bootutil_sha_update(&sha_ctx, diff --git a/docs/release-notes.d/fix-direct-hash-base-address.md b/docs/release-notes.d/fix-direct-hash-base-address.md new file mode 100644 index 000000000..041a45134 --- /dev/null +++ b/docs/release-notes.d/fix-direct-hash-base-address.md @@ -0,0 +1,2 @@ + - Fixed issue in image_validate when `MCUBOOT_HASH_STORAGE_DIRECTLY` is enabled + for platforms with NVM memory that does not start at 0x00. From 22199979e37e55cbf37053fa099baf29550967e1 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 8 Jul 2025 08:52:19 +0100 Subject: [PATCH 017/125] [nrf fromlist] boot: zephyr: boards: Remove outdated nrf54l15pdk board config This board has not been supported in a long time, remove it Upstream PR #: 2380 Signed-off-by: Jamie McCrae (cherry picked from commit 78ad12e17024b8c56ee6c828d3a9851a191a729e) --- boot/zephyr/boards/nrf54l15pdk_nrf54l15_cpuapp.conf | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 boot/zephyr/boards/nrf54l15pdk_nrf54l15_cpuapp.conf diff --git a/boot/zephyr/boards/nrf54l15pdk_nrf54l15_cpuapp.conf b/boot/zephyr/boards/nrf54l15pdk_nrf54l15_cpuapp.conf deleted file mode 100644 index 43d8cebe3..000000000 --- a/boot/zephyr/boards/nrf54l15pdk_nrf54l15_cpuapp.conf +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2024 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 -# -CONFIG_BOOT_MAX_IMG_SECTORS=256 - -# Ensure that the SPI NOR driver is disabled by default -CONFIG_SPI_NOR=n - -CONFIG_BOOT_WATCHDOG_FEED=n From 422c6370ef884e9953b41662f6e51147ff14bea0 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Fri, 23 May 2025 13:26:51 +0200 Subject: [PATCH 018/125] [nrf fromlist] bootutil: Unify app_max_size() implementations Remove redundant application size calculations in favor of a swap-specific function, implemented inside swap_.c. In this way, slot sizes use the same restrictions as image validation. Upstream PR #: 2318 Signed-off-by: Tomasz Chyrowicz (cherry picked from commit cf1f76cfb843f790e89fe33204fe52d48f4950b9) --- .../include/bootutil/bootutil_public.h | 6 + boot/bootutil/src/bootutil_misc.c | 102 +----------- boot/bootutil/src/bootutil_priv.h | 18 +-- boot/bootutil/src/swap_move.c | 55 +++---- boot/bootutil/src/swap_offset.c | 64 +++----- boot/bootutil/src/swap_scratch.c | 146 +++++++++++++++++- 6 files changed, 202 insertions(+), 189 deletions(-) diff --git a/boot/bootutil/include/bootutil/bootutil_public.h b/boot/bootutil/include/bootutil/bootutil_public.h index 933553f9f..421d854b1 100644 --- a/boot/bootutil/include/bootutil/bootutil_public.h +++ b/boot/bootutil/include/bootutil/bootutil_public.h @@ -295,6 +295,12 @@ boot_set_next(const struct flash_area *fa, bool active, bool confirm); /** * Attempts to load image header from flash; verifies flash header fields. * + * The selected update method (i.e. swap move) may impose additional restrictions + * on the image size (i.e. due to the presence of the image trailer). + * Such restrictions are not verified by this function. + * These checks are implemented as part of the boot_image_validate(..) that uses + * sizes from the bootutil_max_image_size(..). + * * @param[in] fa_p flash area pointer * @param[out] hdr buffer for image header * diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c index 56e791043..17ed4c616 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -42,6 +42,10 @@ #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif +#if defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET) || \ + defined(MCUBOOT_SWAP_USING_SCRATCH) +#include "swap_priv.h" +#endif BOOT_LOG_MODULE_DECLARE(mcuboot); @@ -235,8 +239,7 @@ int boot_header_scramble_off_sz(const struct flash_area *fa, int slot, size_t *o * 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. */ -static uint32_t -boot_scratch_trailer_sz(uint32_t min_write_sz) +uint32_t boot_scratch_trailer_sz(uint32_t min_write_sz) { return boot_status_entry_sz(min_write_sz) + boot_trailer_info_sz(); } @@ -422,44 +425,6 @@ boot_write_enc_key(const struct flash_area *fap, uint8_t slot, } #endif -#ifdef MCUBOOT_SWAP_USING_SCRATCH -size_t -boot_get_first_trailer_sector(struct boot_loader_state *state, size_t slot, size_t trailer_sz) -{ - size_t first_trailer_sector = boot_img_num_sectors(state, slot) - 1; - size_t sector_sz = boot_img_sector_size(state, slot, first_trailer_sector); - size_t trailer_sector_sz = sector_sz; - - while (trailer_sector_sz < trailer_sz) { - /* Consider that the image trailer may span across sectors of different sizes */ - --first_trailer_sector; - sector_sz = boot_img_sector_size(state, slot, first_trailer_sector); - - trailer_sector_sz += sector_sz; - } - - return first_trailer_sector; -} - -/** - * Returns the offset to the end of the first sector of a given slot that holds image trailer data. - * - * @param state Current bootloader's state. - * @param slot The index of the slot to consider. - * @param trailer_sz The size of the trailer, in bytes. - * - * @return The offset to the end of the first sector of the slot that holds image trailer data. - */ -static uint32_t -get_first_trailer_sector_end_off(struct boot_loader_state *state, size_t slot, size_t trailer_sz) -{ - size_t first_trailer_sector = boot_get_first_trailer_sector(state, slot, trailer_sz); - - return boot_img_sector_off(state, slot, first_trailer_sector) + - boot_img_sector_size(state, slot, first_trailer_sector); -} -#endif /* MCUBOOT_SWAP_USING_SCRATCH */ - uint32_t bootutil_max_image_size(struct boot_loader_state *state, const struct flash_area *fap) { #if defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \ @@ -467,61 +432,10 @@ uint32_t bootutil_max_image_size(struct boot_loader_state *state, const struct f defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD) (void) state; return boot_status_off(fap); -#elif defined(MCUBOOT_SWAP_USING_SCRATCH) - size_t slot_trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); - size_t slot_trailer_off = flash_area_get_size(fap) - slot_trailer_sz; - - /* If the trailer doesn't fit in the last sector of the primary or secondary slot, some padding - * might have to be inserted between the end of the firmware image and the beginning of the - * trailer to ensure there is enough space for the trailer in the scratch area when the last - * sector of the secondary will be copied to the scratch area. - * - * The value of the padding depends on the amount of trailer data that is contained in the first - * trailer containing part of the trailer in the primary and secondary slot. - */ - size_t trailer_sector_primary_end_off = - get_first_trailer_sector_end_off(state, BOOT_PRIMARY_SLOT, slot_trailer_sz); - size_t trailer_sector_secondary_end_off = - get_first_trailer_sector_end_off(state, BOOT_SECONDARY_SLOT, slot_trailer_sz); - - size_t trailer_sz_in_first_sector; - - if (trailer_sector_primary_end_off > trailer_sector_secondary_end_off) { - trailer_sz_in_first_sector = trailer_sector_primary_end_off - slot_trailer_off; - } else { - trailer_sz_in_first_sector = trailer_sector_secondary_end_off - slot_trailer_off; - } - - size_t trailer_padding = 0; - size_t scratch_trailer_sz = boot_scratch_trailer_sz(BOOT_WRITE_SZ(state)); - - if (scratch_trailer_sz > trailer_sz_in_first_sector) { - trailer_padding = scratch_trailer_sz - trailer_sz_in_first_sector; - } - - return slot_trailer_off - trailer_padding; -#elif defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET) +#elif defined(MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_OFFSET) \ + || defined(MCUBOOT_SWAP_USING_SCRATCH) (void) fap; - - /* The slot whose size is used to compute the maximum image size must be the one containing the - * padding required for the swap. */ -#ifdef MCUBOOT_SWAP_USING_MOVE - size_t slot = BOOT_PRIMARY_SLOT; -#else - size_t slot = BOOT_SECONDARY_SLOT; -#endif - - const struct flash_area *fap_padded_slot = BOOT_IMG_AREA(state, slot); - assert(fap_padded_slot != NULL); - - size_t trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); - size_t sector_sz = boot_img_sector_size(state, slot, 0); - size_t padding_sz = sector_sz; - - /* The trailer size needs to be sector-aligned */ - trailer_sz = ALIGN_UP(trailer_sz, sector_sz); - - return flash_area_get_size(fap_padded_slot) - trailer_sz - padding_sz; + return app_max_size(state); #elif defined(MCUBOOT_OVERWRITE_ONLY) (void) state; return boot_swap_info_off(fap); diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h index 72e94aee9..5d5a58a04 100644 --- a/boot/bootutil/src/bootutil_priv.h +++ b/boot/bootutil/src/bootutil_priv.h @@ -363,18 +363,14 @@ int boot_read_enc_key(const struct flash_area *fap, uint8_t slot, struct boot_status *bs); #endif -#ifdef MCUBOOT_SWAP_USING_SCRATCH -/** - * Finds the first sector of a given slot that holds image trailer data. - * - * @param state Current bootloader's state. - * @param slot The index of the slot to consider. - * @param trailer_sz The size of the trailer, in bytes. - * - * @return The index of the first sector of the slot that holds image trailer data. +#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. */ -size_t -boot_get_first_trailer_sector(struct boot_loader_state *state, size_t slot, size_t trailer_sz); +uint32_t boot_scratch_trailer_sz(uint32_t min_write_sz); #endif /** diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index 9349cde37..8b7bcab13 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -227,29 +227,6 @@ boot_status_internal_off(const struct boot_status *bs, int elem_sz) return off; } -static int app_max_sectors(struct boot_loader_state *state) -{ - uint32_t sz = 0; - uint32_t sector_sz; - uint32_t trailer_sz; - uint32_t first_trailer_idx; - - sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0); - trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); - /* subtract 1 for swap and at least 1 for trailer */ - first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 2; - - while (1) { - sz += sector_sz; - if (sz >= trailer_sz) { - break; - } - first_trailer_idx--; - } - - return first_trailer_idx; -} - int boot_slots_compatible(struct boot_loader_state *state) { @@ -258,19 +235,16 @@ boot_slots_compatible(struct boot_loader_state *state) size_t sector_sz_pri = 0; size_t sector_sz_sec = 0; size_t i; - size_t num_usable_sectors_pri; num_sectors_pri = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT); num_sectors_sec = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT); - num_usable_sectors_pri = app_max_sectors(state); if ((num_sectors_pri != num_sectors_sec) && - (num_sectors_pri != (num_sectors_sec + 1)) && - (num_usable_sectors_pri != (num_sectors_sec + 1))) { + (num_sectors_pri != (num_sectors_sec + 1))) { BOOT_LOG_WRN("Cannot upgrade: not a compatible amount of sectors"); BOOT_LOG_DBG("slot0 sectors: %d, slot1 sectors: %d, usable slot0 sectors: %d", (int)num_sectors_pri, (int)num_sectors_sec, - (int)(num_usable_sectors_pri - 1)); + (int)(num_sectors_pri - 1)); return 0; } else if (num_sectors_pri > BOOT_MAX_IMG_SECTORS) { BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed"); @@ -280,7 +254,7 @@ boot_slots_compatible(struct boot_loader_state *state) /* Optimal says primary has one more than secondary. Always. Both have trailers. */ if (num_sectors_pri != (num_sectors_sec + 1)) { BOOT_LOG_DBG("Non-optimal sector distribution, slot0 has %d usable sectors (%d assigned) " - "but slot1 has %d assigned", (int)num_usable_sectors_pri, + "but slot1 has %d assigned", (int)(num_sectors_pri - 1), (int)num_sectors_pri, (int)num_sectors_sec); } @@ -340,7 +314,6 @@ swap_status_source(struct boot_loader_state *state) struct boot_swap_state state_primary_slot; struct boot_swap_state state_secondary_slot; int rc; - uint8_t source; uint8_t image_index; #if (BOOT_IMAGE_NUMBER == 1) @@ -365,10 +338,8 @@ swap_status_source(struct boot_loader_state *state) state_primary_slot.copy_done == BOOT_FLAG_UNSET && state_secondary_slot.magic != BOOT_MAGIC_GOOD) { - source = BOOT_STATUS_SOURCE_PRIMARY_SLOT; - BOOT_LOG_INF("Boot source: primary slot"); - return source; + return BOOT_STATUS_SOURCE_PRIMARY_SLOT; } BOOT_LOG_INF("Boot source: none"); @@ -590,11 +561,23 @@ swap_run(struct boot_loader_state *state, struct boot_status *bs, int app_max_size(struct boot_loader_state *state) { - uint32_t sector_sz_primary; + uint32_t available_pri_sz; + uint32_t available_sec_sz; + + size_t trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); + size_t sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0); + size_t padding_sz = sector_sz; - sector_sz_primary = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0); + /* The trailer size needs to be sector-aligned */ + trailer_sz = ALIGN_UP(trailer_sz, sector_sz); + + /* The slot whose size is used to compute the maximum image size must be the one containing the + * padding required for the swap. + */ + available_pri_sz = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) * sector_sz - trailer_sz - padding_sz; + available_sec_sz = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) * sector_sz - trailer_sz; - return app_max_sectors(state) * sector_sz_primary; + return (available_pri_sz < available_sec_sz ? available_pri_sz : available_sec_sz); } #endif diff --git a/boot/bootutil/src/swap_offset.c b/boot/bootutil/src/swap_offset.c index 8bc6e760a..d8bfac318 100644 --- a/boot/bootutil/src/swap_offset.c +++ b/boot/bootutil/src/swap_offset.c @@ -302,33 +302,6 @@ uint32_t boot_status_internal_off(const struct boot_status *bs, int elem_sz) return off; } -static int app_max_sectors(struct boot_loader_state *state) -{ - uint32_t sz = 0; - uint32_t sector_sz; - uint32_t trailer_sz; - uint32_t available_sectors_pri; - uint32_t available_sectors_sec; - uint32_t trailer_sectors = 0; - - sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0); - trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); - - while (1) { - sz += sector_sz; - ++trailer_sectors; - - if (sz >= trailer_sz) { - break; - } - } - - available_sectors_pri = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - trailer_sectors; - available_sectors_sec = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1; - - return (available_sectors_pri < available_sectors_sec ? available_sectors_pri : available_sectors_sec); -} - int boot_slots_compatible(struct boot_loader_state *state) { size_t num_sectors_pri; @@ -336,32 +309,30 @@ int boot_slots_compatible(struct boot_loader_state *state) size_t sector_sz_pri = 0; size_t sector_sz_sec = 0; size_t i; - size_t num_usable_sectors; num_sectors_pri = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT); num_sectors_sec = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT); - num_usable_sectors = app_max_sectors(state); if (num_sectors_pri != num_sectors_sec && - (num_sectors_pri + 1) != num_sectors_sec && - num_usable_sectors != (num_sectors_sec - 1)) { + (num_sectors_pri + 1) != num_sectors_sec) { BOOT_LOG_WRN("Cannot upgrade: not a compatible amount of sectors"); BOOT_LOG_DBG("slot0 sectors: %d, slot1 sectors: %d, usable sectors: %d", (int)num_sectors_pri, (int)num_sectors_sec, - (int)(num_usable_sectors)); + (int)(num_sectors_sec - 1)); return 0; } else if (num_sectors_pri > BOOT_MAX_IMG_SECTORS) { BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed"); return 0; } - if ((num_usable_sectors + 1) != num_sectors_sec) { + /* Optimal says secondary has one more than primary. Always. Both have trailers. */ + if ((num_sectors_pri + 1) != num_sectors_sec) { BOOT_LOG_DBG("Non-optimal sector distribution, slot0 has %d usable sectors " - "but slot1 has %d usable sectors", (int)(num_usable_sectors), + "but slot1 has %d usable sectors", (int)(num_sectors_pri), ((int)num_sectors_sec - 1)); } - for (i = 0; i < num_usable_sectors; i++) { + for (i = 0; i < (num_sectors_sec - 1); i++) { sector_sz_pri = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i); sector_sz_sec = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, i); @@ -417,7 +388,6 @@ int swap_status_source(struct boot_loader_state *state) struct boot_swap_state state_primary_slot; struct boot_swap_state state_secondary_slot; int rc; - uint8_t source; uint8_t image_index; #if (BOOT_IMAGE_NUMBER == 1) @@ -439,10 +409,8 @@ int swap_status_source(struct boot_loader_state *state) state_primary_slot.copy_done == BOOT_FLAG_UNSET && state_secondary_slot.magic != BOOT_MAGIC_GOOD) { - source = BOOT_STATUS_SOURCE_PRIMARY_SLOT; - BOOT_LOG_INF("Boot source: primary slot"); - return source; + return BOOT_STATUS_SOURCE_PRIMARY_SLOT; } BOOT_LOG_INF("Boot source: none"); @@ -729,11 +697,23 @@ void swap_run(struct boot_loader_state *state, struct boot_status *bs, int app_max_size(struct boot_loader_state *state) { - uint32_t sector_sz_primary; + uint32_t available_pri_sz; + uint32_t available_sec_sz; + + size_t trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); + size_t sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0); + size_t padding_sz = sector_sz; + + /* The trailer size needs to be sector-aligned */ + trailer_sz = ALIGN_UP(trailer_sz, sector_sz); - sector_sz_primary = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0); + /* The slot whose size is used to compute the maximum image size must be the one containing the + * padding required for the swap. + */ + available_pri_sz = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) * sector_sz - trailer_sz; + available_sec_sz = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) * sector_sz - trailer_sz - padding_sz; - return app_max_sectors(state) * sector_sz_primary; + return (available_pri_sz < available_sec_sz ? available_pri_sz : available_sec_sz); } /* Compute the total size of the given image. Includes the size of the TLVs. */ diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c index f9dbb7103..e1d49de49 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -47,6 +47,136 @@ int boot_status_fails = 0; #define BOOT_STATUS_ASSERT(x) ASSERT(x) #endif +#if MCUBOOT_SWAP_USING_SCRATCH +/** + * Finds the first sector of a given slot that holds image trailer data. + * + * @param state Current bootloader's state. + * @param slot The index of the slot to consider. + * @param trailer_sz The size of the trailer, in bytes. + * + * @return The index of the first sector of the slot that holds image trailer data. + */ +static size_t +boot_get_first_trailer_sector(struct boot_loader_state *state, size_t slot, size_t trailer_sz) +{ + size_t first_trailer_sector = boot_img_num_sectors(state, slot) - 1; + size_t sector_sz = boot_img_sector_size(state, slot, first_trailer_sector); + size_t trailer_sector_sz = sector_sz; + + while (trailer_sector_sz < trailer_sz) { + /* Consider that the image trailer may span across sectors of different sizes */ + --first_trailer_sector; + sector_sz = boot_img_sector_size(state, slot, first_trailer_sector); + + trailer_sector_sz += sector_sz; + } + + return first_trailer_sector; +} + +/** + * Returns the offset to the end of the first sector of a given slot that holds image trailer data. + * + * @param state Current bootloader's state. + * @param slot The index of the slot to consider. + * @param trailer_sz The size of the trailer, in bytes. + * + * @return The offset to the end of the first sector of the slot that holds image trailer data. + */ +static uint32_t +get_first_trailer_sector_end_off(struct boot_loader_state *state, size_t slot, size_t trailer_sz) +{ + size_t first_trailer_sector = boot_get_first_trailer_sector(state, slot, trailer_sz); + + return boot_img_sector_off(state, slot, first_trailer_sector) + + boot_img_sector_size(state, slot, first_trailer_sector); +} + +/** + * Returns the size of the part of the slot that can be used for storing image data. + * + * @param state Current bootloader's state. + * @param slot_size The size of the slot partition. + * + * @return The offset to the end of the first sector of the slot that holds image trailer data. + */ +static size_t app_max_size_adjust_to_trailer(struct boot_loader_state *state, size_t slot_size) +{ + size_t slot_trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state)); + size_t slot_trailer_off = slot_size - slot_trailer_sz; + size_t trailer_sz_in_first_sector; + size_t trailer_sector_end_off; + + + size_t trailer_sector_primary_end_off = + get_first_trailer_sector_end_off(state, BOOT_PRIMARY_SLOT, slot_trailer_sz); + size_t trailer_sector_secondary_end_off = + get_first_trailer_sector_end_off(state, BOOT_SECONDARY_SLOT, slot_trailer_sz); + + /* If slots have sectors of different sizes, we need to find the "common" sector + * boundary (slot compatibility checks ensure that the larger sector contains a multiple + * of the smaller sector size). This will be the larger of the + * trailer_sector_primary_end_off/trailer_sector_secondary_end_off. + * + * <-------copy size-------> <--------copy size------> <----copy size---> + * v v v v + * +------------+------------+-------------------------+------------------+ + * | sector | sector | sector | sector | + * +------------+------------+------------+------------+------------------+ + * | sector | sector | sector | sector | + * +-------------------------+------------+------------+------------------+ + * + * The swap logic always uses the common boundary when performing the copy. + * Hence, the first trailer sector used for calculation is the larger + * sector from the two slots. + * + * <-----------copy size---------------> + * | sector | sector | + * +-----------------------------------+ + * | sector | + * +-----------------------------------+ + * |Image->| |<-trailer------------| + * +-----------------------------------+ + * | |<-scratch trailer>| + * +-----------------------------------+ + */ + if (trailer_sector_primary_end_off > trailer_sector_secondary_end_off) { + trailer_sector_end_off = trailer_sector_primary_end_off; + } else { + trailer_sector_end_off = trailer_sector_secondary_end_off; + } + + trailer_sz_in_first_sector = trailer_sector_end_off - slot_trailer_off; + + size_t trailer_padding = 0; + size_t scratch_trailer_sz = boot_scratch_trailer_sz(BOOT_WRITE_SZ(state)); + + /* Some padding might have to be inserted between the end of the firmware image and the + * beginning of the trailer to ensure there is enough space for the trailer in the scratch area + * when the last sector of the secondary will be copied to the scratch area. + * + * +-----------------------------------+-----------------------------------+ + * | sector | sector | + * +-----------------------------------+-----------------------------------+ + * |Image->| |<--trailer---|-----------trailer (cont.)-------->| + * +-----------------------------------+-----------------------------------+ + * | |<----scratch trailer---->| + * +-----------------------------------+ + * <-padding-> + * <--------scratch area size--------> + * + * The value of the padding depends on the amount of trailer data that is contained in the first + * sector containing part of the trailer in the primary and secondary slot. + */ + if (scratch_trailer_sz > trailer_sz_in_first_sector) { + trailer_padding = scratch_trailer_sz - trailer_sz_in_first_sector; + } + + return slot_trailer_off - trailer_padding; +} +#endif /* MCUBOOT_SWAP_USING_SCRATCH */ + #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) /** * Reads the status of a partially-completed swap, if any. This is necessary @@ -821,8 +951,8 @@ int app_max_size(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 slot_sz; size_t scratch_sz; #endif size_t i, j; @@ -842,8 +972,11 @@ int app_max_size(struct boot_loader_state *state) * number of a slot's sectors are able to fit into another, which only * excludes cases where sector sizes are not a multiple of each other. */ - i = sz0 = primary_slot_sz = 0; - j = sz1 = secondary_slot_sz = 0; +#ifndef MCUBOOT_OVERWRITE_ONLY + slot_sz = 0; +#endif + i = sz0 = 0; + j = sz1 = 0; smaller = 0; while (i < num_sectors_primary || j < num_sectors_secondary) { if (sz0 == sz1) { @@ -876,8 +1009,7 @@ int app_max_size(struct boot_loader_state *state) } #ifndef MCUBOOT_OVERWRITE_ONLY if (sz0 == sz1) { - primary_slot_sz += sz0; - secondary_slot_sz += sz1; + slot_sz += sz0; /* Scratch has to fit each swap operation to the size of the larger * sector among the primary slot and the secondary slot. */ @@ -892,8 +1024,10 @@ int app_max_size(struct boot_loader_state *state) #ifdef MCUBOOT_OVERWRITE_ONLY return (sz1 < sz0 ? sz1 : sz0); +#elif MCUBOOT_SWAP_USING_SCRATCH + return app_max_size_adjust_to_trailer(state, slot_sz); #else - return (secondary_slot_sz < primary_slot_sz ? secondary_slot_sz : primary_slot_sz); + return slot_sz; #endif } #else From b0ad970425de01e09370badbc2ab449aa6292649 Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Fri, 4 Jul 2025 11:59:41 +0200 Subject: [PATCH 019/125] [nrf fromlist] zephyr: boards: nrf - remove redundant multithreading configuration Remove configs that enable multithreading just because of SPI/QSPI use. Currently, nrf drivers do not depend on multithreading, so it is not needed and this change can save memory usage. Upstream PR #: 2375 Signed-off-by: Michal Kozikowski (cherry picked from commit dd6b3ac0cab12eebf6420367184ae498faf5e458) --- boot/zephyr/boards/nrf52840dk_qspi_secondary_boot.conf | 1 - boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf | 2 -- 2 files changed, 3 deletions(-) diff --git a/boot/zephyr/boards/nrf52840dk_qspi_secondary_boot.conf b/boot/zephyr/boards/nrf52840dk_qspi_secondary_boot.conf index 9f984be4f..5f3b7808b 100644 --- a/boot/zephyr/boards/nrf52840dk_qspi_secondary_boot.conf +++ b/boot/zephyr/boards/nrf52840dk_qspi_secondary_boot.conf @@ -1,2 +1 @@ -CONFIG_MULTITHREADING=y CONFIG_BOOT_MAX_IMG_SECTORS=256 diff --git a/boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf b/boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf index 50d349255..12c96ff0f 100644 --- a/boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf +++ b/boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf @@ -7,5 +7,3 @@ CONFIG_SPI_NOR=n CONFIG_BOOT_WATCHDOG_FEED=n - -CONFIG_MULTITHREADING=y From cf5187c5df8e1270f66ae48978eeea5be7a4d4ed Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Wed, 2 Jul 2025 11:12:29 +0200 Subject: [PATCH 020/125] [nrf fromtree] boot: zephyr: RAM cleanup debug loop Option to put execution in infinite loop. Meant to be used for debug. Signed-off-by: Mateusz Michalek (cherry picked from commit 5eaf190a8a9d8fc032b989bf96fc56b3b756dd55) --- boot/zephyr/Kconfig | 7 +++++++ boot/zephyr/main.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index dc445b4ed..4b58f3fab 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -364,6 +364,13 @@ config MCUBOOT_CLEANUP_RAM help Sets contents of memory to 0 before jumping to application. +config MCUBOOT_INFINITE_LOOP_AFTER_RAM_CLEANUP + bool "Infinite loop after RAM cleanup" + depends on MCUBOOT_CLEANUP_RAM + help + Verification option that keeps execution in infinite loop after + RAM cleanup has been performed. + 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 diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c index 2e57bd999..0cb793b2d 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -249,6 +249,9 @@ static void do_boot(struct boot_rsp *rsp) " 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" : From edbba12dec2fae0c51c03304c798d4ec0ad35d3a Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 16 Jul 2025 16:01:36 +0000 Subject: [PATCH 021/125] [nrf fromlist] zephyr: Improve SHA support selectors Commit introduces BOOT_SOMETHING_USES_SHA<256,384,512> Kconfig options that can be used to control what algorithms should be compiled in with crypto backends. Upstream PR #: 2390 Signed-off-by: Dominik Ermel (cherry picked from commit 62ee266633a78c40eb8c9ca9dac60588fc1d23c5) --- boot/zephyr/Kconfig | 64 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 4b58f3fab..ef9eb2433 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -70,15 +70,20 @@ if BOOT_USE_PSA_CRYPTO config BOOT_PSA_IMG_HASH_ALG_SHA256_DEPENDENCIES bool - default y if BOOT_IMG_HASH_ALG_SHA256 + default y if BOOT_SOMETHING_USES_SHA256 select PSA_WANT_ALG_SHA_256 help Dependencies for hashing with SHA256 -config BOOT_ED25519_PSA_DEPENDENCIES +config BOOT_PSA_IMG_HASH_ALG_SHA512_DEPENDENCIES bool - select PSA_WANT_ALG_SHA_256 + default y if BOOT_SOMETHING_USES_SHA512 select PSA_WANT_ALG_SHA_512 + help + Dependencies for hashing with SHA512 + +config BOOT_ED25519_PSA_DEPENDENCIES + bool select PSA_WANT_ALG_PURE_EDDSA # Seems that upstream mbedTLS does not have TE #select PSA_WANT_ECC_TWISTED_EDWARDS_255 @@ -129,6 +134,30 @@ config SINGLE_APPLICATION_SLOT uploading a new application overwrites the one that previously occupied the area. +config BOOT_SOMETHING_USES_SHA256 + bool + help + Hidden option that should be selected when something requires + SHA256 implementation in any form. It should be used by crypto + backends to enable support for SHA256 in code and/or hardware + drivers. + +config BOOT_SOMETHING_USES_SHA384 + bool + help + Hidden option that should be selected when something requires + SHA384 implementation in any form. It should be used by crypto + backends to enable support for SHA384 in code and/or hardware + drivers. + +config BOOT_SOMETHING_USES_SHA512 + bool + help + Hidden option that should be selected when something requires + SHA512 implementation in any form. It should be used by crypto + backends to enable support for SHA512 in code and/or hardware + drivers. + config BOOT_IMG_HASH_ALG_SHA256_ALLOW bool help @@ -173,18 +202,21 @@ choice BOOT_IMG_HASH_ALG config BOOT_IMG_HASH_ALG_SHA256 bool "SHA256" depends on BOOT_IMG_HASH_ALG_SHA256_ALLOW + select BOOT_SOMETHING_USES_SHA256 help SHA256 algorithm config BOOT_IMG_HASH_ALG_SHA384 bool "SHA384" depends on BOOT_IMG_HASH_ALG_SHA384_ALLOW + select BOOT_SOMETHING_USES_SHA384 help SHA384 algorithm config BOOT_IMG_HASH_ALG_SHA512 bool "SHA512" depends on BOOT_IMG_HASH_ALG_SHA512_ALLOW + select BOOT_SOMETHING_USES_SHA512 help SHA512 algorithm @@ -608,14 +640,34 @@ config BOOT_ENCRYPT_X25519 help Hidden option selecting x25519 encryption. +if BOOT_ENCRYPT_X25519 && BOOT_USE_PSA_CRYPTO + +choice BOOT_HMAC_SHA + prompt "SHA used for HMAC and HKDF in encryption key exchange" + default BOOT_HMAC_SHA256 + help + HMAC/HKDF sha algorithm may be selected to synchronize sha + usage with other places in code and reduce compiled in + implementations. + +config BOOT_HMAC_SHA256 + bool "Use SHA256 for HMAC/HKDF" + select BOOT_SOMETHING_USES_SHA256 + help + This is default for ED25519. + config BOOT_HMAC_SHA512 bool "Use SHA512 for HMAC/HKDF" depends on BOOT_ENCRYPT_X25519 depends on BOOT_USE_PSA_CRYPTO + select BOOT_SOMETHING_USES_SHA512 help - By default SHA256 is used for HKDF/HMAC in key exchange expansion - and verification. This options switches to SHA512. The option is - mainly useful to reduce numer of compiled in SHA algorithms. + With ED25519, this option is worth selecting when SHA512 is used + for hashing of an image to reduce number of compiled sha algorithms. + +endchoice # BOOT_HMAC_SHA + +endif # BOOT_ENCRYPT_X25519 && BOOT_USE_PSA_CRYPTO config BOOT_ENCRYPTION_KEY_FILE string "Encryption key file" From d8bd9285ea84ab0d71b95c8f02d76844f69a83a6 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Mon, 16 Jun 2025 17:23:23 +0200 Subject: [PATCH 022/125] [nrf fromtree] loader: Allow to specify slot number in version Allow to depend on a specific slot while specifying the version number. This functionality is useful when the Direct XIP mode is used and the booting process of other images is done by the next stage, not the MCUboot itself. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit dce784a2f2a045c3643b9baf02e9f4fc40530b7b) --- boot/bootutil/include/bootutil/image.h | 8 + boot/bootutil/src/loader.c | 167 +++++++++++++++++- boot/zephyr/Kconfig | 9 + .../include/mcuboot_config/mcuboot_config.h | 4 + docs/design.md | 17 ++ docs/imgtool.md | 13 +- scripts/imgtool/image.py | 3 +- scripts/imgtool/main.py | 32 +++- 8 files changed, 247 insertions(+), 6 deletions(-) diff --git a/boot/bootutil/include/bootutil/image.h b/boot/bootutil/include/bootutil/image.h index 11c54b633..52fa6d1bb 100644 --- a/boot/bootutil/include/bootutil/image.h +++ b/boot/bootutil/include/bootutil/image.h @@ -144,6 +144,10 @@ extern "C" { */ #define IMAGE_TLV_ANY 0xffff /* Used to iterate over all TLV */ +#define VERSION_DEP_SLOT_ACTIVE 0x00 /* Check dependency against active slot. */ +#define VERSION_DEP_SLOT_PRIMARY 0x01 /* Check dependency against primary slot. */ +#define VERSION_DEP_SLOT_SECONDARY 0x02 /* Check dependency against secondary slot. */ + STRUCT_PACKED image_version { uint8_t iv_major; uint8_t iv_minor; @@ -153,7 +157,11 @@ STRUCT_PACKED image_version { struct image_dependency { uint8_t image_id; /* Image index (from 0) */ +#ifdef MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER + uint8_t slot; /* Image slot */ +#else uint8_t _pad1; +#endif /* MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER */ uint16_t _pad2; struct image_version image_min_version; /* Indicates at minimum which * version of firmware must be diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 6654245ad..8c73f7652 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -424,6 +424,24 @@ boot_verify_slot_dependency(struct boot_loader_state *state, uint8_t swap_type = state->swap_type[dep->image_id]; dep_slot = BOOT_IS_UPGRADE(swap_type) ? BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT; +#elif defined(MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER) + switch(dep->slot) { + case VERSION_DEP_SLOT_ACTIVE: + dep_slot = state->slot_usage[dep->image_id].active_slot; + break; + case VERSION_DEP_SLOT_PRIMARY: + dep_slot = BOOT_PRIMARY_SLOT; + break; + case VERSION_DEP_SLOT_SECONDARY: + dep_slot = BOOT_SECONDARY_SLOT; + break; + default: + return -1; + } + + if (!state->slot_usage[dep->image_id].slot_available[dep_slot]) { + return -1; + } #else dep_slot = state->slot_usage[dep->image_id].active_slot; #endif @@ -461,7 +479,27 @@ boot_verify_slot_dependency(struct boot_loader_state *state, } #endif - return rc; +#ifdef MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER + if (rc == 0) { + switch(dep->slot) { + case VERSION_DEP_SLOT_PRIMARY: + state->slot_usage[dep->image_id].slot_available[BOOT_PRIMARY_SLOT] = true; + state->slot_usage[dep->image_id].slot_available[BOOT_SECONDARY_SLOT] = false; + state->slot_usage[dep->image_id].active_slot = BOOT_PRIMARY_SLOT; + break; + case VERSION_DEP_SLOT_SECONDARY: + state->slot_usage[dep->image_id].slot_available[BOOT_PRIMARY_SLOT] = false; + state->slot_usage[dep->image_id].slot_available[BOOT_SECONDARY_SLOT] = true; + state->slot_usage[dep->image_id].active_slot = BOOT_SECONDARY_SLOT; + break; + case VERSION_DEP_SLOT_ACTIVE: + default: + break; + } + } +#endif /* MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER */ + +return rc; } #if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD) @@ -606,6 +644,19 @@ boot_verify_slot_dependencies(struct boot_loader_state *state, uint32_t slot) goto done; } +#ifdef MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER + /* Validate against possible dependency slot values. */ + switch(dep->slot) { + case VERSION_DEP_SLOT_ACTIVE: + case VERSION_DEP_SLOT_PRIMARY: + case VERSION_DEP_SLOT_SECONDARY: + break; + default: + rc = BOOT_EBADARGS; + goto done; + } +#endif /* MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER */ + /* Verify dependency and modify the swap type if not satisfied. */ rc = boot_verify_slot_dependency(state, &dep); if (rc != 0) { @@ -2932,6 +2983,119 @@ boot_select_or_erase(struct boot_loader_state *state) } #endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */ +#ifdef MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER +/** + * 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; + uint32_t slot; + + /* Go over all the images and all slots and validate them */ + IMAGES_ITER(BOOT_CURR_IMG(state)) { + for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) { +#if BOOT_IMAGE_NUMBER > 1 + if (state->img_mask[BOOT_CURR_IMG(state)]) { + continue; + } +#endif + + /* Save the number of the active slot. */ + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = slot; + +#ifdef MCUBOOT_DIRECT_XIP + rc = boot_rom_address_check(state); + if (rc != 0) { + /* The image is placed in an unsuitable slot. */ + state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false; + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT; + continue; + } + +#ifdef MCUBOOT_DIRECT_XIP_REVERT + rc = boot_select_or_erase(state); + if (rc != 0) { + /* The selected image slot has been erased. */ + state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false; + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT; + continue; + } +#endif /* MCUBOOT_DIRECT_XIP_REVERT */ +#endif /* MCUBOOT_DIRECT_XIP */ + +#ifdef MCUBOOT_RAM_LOAD + /* Image is first loaded to RAM and authenticated there in order to + * prevent TOCTOU attack during image copy. This could be applied + * when loading images from external (untrusted) flash to internal + * (trusted) RAM and image is authenticated before copying. + */ + rc = boot_load_image_to_sram(state); + if (rc != 0 ) { + /* Image cannot be ramloaded. */ + boot_remove_image_from_flash(state, slot); + state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false; + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT; + continue; + } +#endif /* MCUBOOT_RAM_LOAD */ + + FIH_CALL(boot_validate_slot, fih_rc, state, slot, NULL, 0); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + /* Image is invalid. */ +#ifdef MCUBOOT_RAM_LOAD + boot_remove_image_from_sram(state); +#endif /* MCUBOOT_RAM_LOAD */ + state->slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false; + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT; + continue; + } + + /* Valid image loaded from a slot, go to the next slot. */ + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT; + } + } + + /* Go over all the images and all slots and validate them */ + IMAGES_ITER(BOOT_CURR_IMG(state)) { + /* All slots tried until a valid image found. Breaking from this loop + * means that a valid image found or already loaded. If no slot is + * found the function returns with error code. */ + while (true) { + /* Go over all the slots and try to load one */ + active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot; + if (active_slot != NO_ACTIVE_SLOT){ + /* A slot is already active, go to next image. */ + break; + } + + active_slot = find_slot_with_highest_version(state); + if (active_slot == NO_ACTIVE_SLOT) { + BOOT_LOG_INF("No slot to load for image %d", + BOOT_CURR_IMG(state)); + FIH_RET(FIH_FAILURE); + } + + /* Save the number of the active slot. */ + state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot; + + /* Valid image loaded from a slot, go to the next image. */ + break; + } + } + + FIH_RET(FIH_SUCCESS); +} + +#else /* MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER */ + /** * Tries to load a slot for all the images with validation. * @@ -3029,6 +3193,7 @@ boot_load_and_validate_images(struct boot_loader_state *state) FIH_RET(FIH_SUCCESS); } +#endif /* MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER */ /** * Updates the security counter for the current image. diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index ef9eb2433..fcd9f5d35 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -949,6 +949,15 @@ config BOOT_VERSION_CMP_USE_BUILD_NUMBER minor and revision. Enable this option to take into account the build number as well. +config BOOT_VERSION_CMP_USE_SLOT_NUMBER + bool "Use slot number while comparing image version" + depends on (UPDATEABLE_IMAGE_NUMBER > 1) || BOOT_DIRECT_XIP || \ + BOOT_RAM_LOAD || MCUBOOT_DOWNGRADE_PREVENTION + help + By default, the image slot comparison relies only on active slot. + Enable this option to take into account the specified slot number + instead. + choice BOOT_DOWNGRADE_PREVENTION_CHOICE prompt "Downgrade prevention" optional diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 820ffd752..f0dc214b6 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -120,6 +120,10 @@ #define MCUBOOT_VERSION_CMP_USE_BUILD_NUMBER #endif +#ifdef CONFIG_BOOT_VERSION_CMP_USE_SLOT_NUMBER +#define MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER +#endif + #ifdef CONFIG_BOOT_SWAP_SAVE_ENCTLV #define MCUBOOT_SWAP_SAVE_ENCTLV 1 #endif diff --git a/docs/design.md b/docs/design.md index 66fcd45f9..c080b2b82 100755 --- a/docs/design.md +++ b/docs/design.md @@ -890,6 +890,23 @@ process is presented below. + Boot into image in the primary slot of the 0th image position\ (other image in the boot chain is started by another image). +By enabling the `MCUBOOT_VERSION_CMP_USE_SLOT_NUMBER` configuration option, +the dependency check may be extended to match for a specified slot of a specific +image. This functionality is useful in a multi-core system when Direct XIP mode +is used. +In this case, the main image can be started from one of the two (primary or +secondary) slots. +If there is a fixed connection between the slots of two different images, +e.g. if the main image always chainloads a companion image from the same slot, +the check must take this into account and only consider a matching slot when +resolving dependencies. + +There are three values that can be passed when specifying dependencies: + +1. ``active``: the dependency should be checked against either primary or secondary slot. +2. ``primary``: the dependency should be checked only against primary slot. +3. ``secondary``: the dependency should be checked only against secondary slot. + ### [Multiple image boot for RAM loading and direct-xip](#multiple-image-boot-for-ram-loading-and-direct-xip) The operation of the bootloader is different when the ram-load or the diff --git a/docs/imgtool.md b/docs/imgtool.md index 958e1af15..c68652dca 100644 --- a/docs/imgtool.md +++ b/docs/imgtool.md @@ -91,7 +91,8 @@ primary slot and adds a header and trailer that the bootloader is expecting: the `auto` keyword to automatically generate it from the image version. -d, --dependencies TEXT Add dependence on another image, format: - "(,), ... " + "(,[,] + ), ... " --pad-sig Add 0-2 bytes of padding to ECDSA signature (for mcuboot <1.5) -H, --header-size INTEGER [required] @@ -182,6 +183,16 @@ which the current image depends on. The `image_version` is the minimum version of that image to satisfy compliance. For example `-d "(1, 1.2.3+0)"` means this image depends on Image 1 which version has to be at least 1.2.3+0. +In addition, a dependency can specify the slot as follows: +`-d "(image_id, slot, image_version)"`. The `image_id` is the number of the +image on which the current image depends. +The slot specifies which slots of the image are to be taken into account +(`active`: primary or secondary, `primary`: only primary `secondary`: only +secondary slot). The `image_version` is the minimum version of that image to +fulfill the requirements. +For example `-d "(1, primary, 1.2.3+0)"` means that this image depends on the +primary slot of the Image 1, whose version must be at least 1.2.3+0. + The `--public-key-format` argument can be used to distinguish where the public key is stored for image authentication. The `hash` option is used by default, in which case only the hash of the public key is added to the TLV area (the full diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index 03e2cbb62..4e2830370 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -589,8 +589,9 @@ def create(self, key, public_key_format, enckey, dependencies=None, if dependencies is not None: for i in range(dependencies_num): payload = struct.pack( - e + 'B3x' + 'BBHI', + e + 'BB2x' + 'BBHI', int(dependencies[DEP_IMAGES_KEY][i]), + dependencies[DEP_VERSIONS_KEY][i].slot, dependencies[DEP_VERSIONS_KEY][i].major, dependencies[DEP_VERSIONS_KEY][i].minor, dependencies[DEP_VERSIONS_KEY][i].revision, diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index 5ff1f8f9f..7f9a53657 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -27,6 +27,7 @@ import lzma import hashlib import base64 +from collections import namedtuple from imgtool import image, imgtool_version from imgtool.version import decode_version from imgtool.dumpinfo import dump_imginfo @@ -45,6 +46,14 @@ sys.exit("Python %s.%s or newer is required by imgtool." % MIN_PYTHON_VERSION) +SlottedSemiSemVersion = namedtuple('SemiSemVersion', ['major', 'minor', 'revision', + 'build', 'slot']) + +DEPENDENCY_SLOT_VALUES = { + 'active': 0x00, + 'primary': 0x01, + 'secondary': 0x02 +} def gen_rsa2048(keyfile, passwd): keys.RSA.generate().export_private(path=keyfile, passwd=passwd) @@ -301,16 +310,33 @@ def get_dependencies(ctx, param, value): if len(images) == 0: raise click.BadParameter( "Image dependency format is invalid: {}".format(value)) - raw_versions = re.findall(r",\s*([0-9.+]+)\)", value) + raw_versions = re.findall(r",\s*((active|primary|secondary)\s*,)?\s*([0-9.+]+)\)", value) if len(images) != len(raw_versions): raise click.BadParameter( '''There's a mismatch between the number of dependency images and versions in: {}'''.format(value)) for raw_version in raw_versions: try: - versions.append(decode_version(raw_version)) + decoded_version = decode_version(raw_version[2]) + if len(raw_version[1]) > 0: + slotted_version = SlottedSemiSemVersion( + decoded_version.major, + decoded_version.minor, + decoded_version.revision, + decoded_version.build, + DEPENDENCY_SLOT_VALUES[raw_version[1]] + ) + else: + slotted_version = SlottedSemiSemVersion( + decoded_version.major, + decoded_version.minor, + decoded_version.revision, + decoded_version.build, + 0 + ) except ValueError as e: raise click.BadParameter("{}".format(e)) + versions.append(slotted_version) dependencies = dict() dependencies[image.DEP_IMAGES_KEY] = images dependencies[image.DEP_VERSIONS_KEY] = versions @@ -405,7 +431,7 @@ def convert(self, value, param, ctx): '(for mcuboot <1.5)') @click.option('-d', '--dependencies', callback=get_dependencies, required=False, help='''Add dependence on another image, format: - "(,), ... "''') + "(,[,]), ... "''') @click.option('-s', '--security-counter', callback=validate_security_counter, help='Specify the value of security counter. Use the `auto` ' 'keyword to automatically generate it from the image version.') From 7ad728fef39f60eee0c09e6a2300a17b1ccee212 Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Mon, 21 Jul 2025 15:59:10 +0200 Subject: [PATCH 023/125] [nrf fromtree] zephyr: Enable building ECDSA PSA variant Adds Kconfig option CONFIG_BOOT_ECDSA_PSA that allows to switch ECDSA to PSA backend. Signed-off-by: Artur Hadasz (cherry picked from commit 5ee96f5bc0dc506e56ef348960fae0b8f14b038e) --- boot/zephyr/CMakeLists.txt | 5 ++++- boot/zephyr/Kconfig | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 159962543..76ada498e 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -186,7 +186,10 @@ else() endif() if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) - if(MBEDTLS_ASN1_DIR) + # When ECDSA PSA is used, do not pull in additional ASN.1 include + # directories or sources, as it would cause incorrect header files + # to be included. + if(MBEDTLS_ASN1_DIR AND NOT CONFIG_BOOT_ECDSA_PSA) zephyr_library_include_directories( ${MBEDTLS_ASN1_DIR}/include ) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index fcd9f5d35..0e8265002 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -113,6 +113,14 @@ config BOOT_X25519_PSA_DEPENDENCIES endif # BOOT_ENCRYPT_IMAGE +config BOOT_ECDSA_PSA_DEPENDENCIES + bool + select PSA_WANT_ALG_ECDSA + select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT + select PSA_WANT_ECC_SECP_R1_256 + help + Dependencies for ECDSA signature + if MBEDTLS_ENABLE_HEAP config MBEDTLS_HEAP_SIZE @@ -282,6 +290,16 @@ config BOOT_ECDSA_CC310 select NRF_CC310_BL select NRFXLIB_CRYPTO select BOOT_USE_CC310 + +config BOOT_ECDSA_PSA + bool "Use psa cryptoo" + select BOOT_USE_PSA_CRYPTO + select PSA_CRYPTO_CLIENT + select PSA_CRYPTO_C + select BOOT_IMG_HASH_ALG_SHA256_ALLOW + select BOOT_IMG_HASH_ALG_SHA512_ALLOW + select BOOT_ECDSA_PSA_DEPENDENCIES + endchoice # Ecdsa implementation endif From 727cc28fcc10b78fc2f8b3fb5fd60ea71596160f Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Tue, 10 Oct 2023 15:51:54 +0200 Subject: [PATCH 024/125] [nrf noup] github: Add a commit tags check workflow Use the generic commit-tags action to provide sauce tag checks. Signed-off-by: Carles Cufi (cherry picked from commit 67c4da497005924017ad815d020555f591e2fc38) --- .github/workflows/commit-tags.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/commit-tags.yml diff --git a/.github/workflows/commit-tags.yml b/.github/workflows/commit-tags.yml new file mode 100644 index 000000000..534ed5b58 --- /dev/null +++ b/.github/workflows/commit-tags.yml @@ -0,0 +1,28 @@ +name: Commit tags + +on: + pull_request: + types: [synchronize, opened, reopened, edited, labeled, unlabeled, + milestoned, demilestoned, assigned, unassigned, ready_for_review, + review_requested] + +jobs: + commit_tags: + runs-on: ubuntu-22.04 + name: Run commit tags checks on patch series (PR) + steps: + - name: Update PATH for west + run: | + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Checkout the code + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + + - name: Run the commit tags + uses: nrfconnect/action-commit-tags@main + with: + target: . + upstream: mcu-tools/mcuboot/main From 7ac4eeb0b9ad01f90d002cf34d1e84a6b0e539ab Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Tue, 26 Mar 2019 15:42:38 +0100 Subject: [PATCH 025/125] [nrf noup] zephyr: Remove duplication from cmake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the `add_subdirectory` of nrfxlib it will still check that the nrfxlib is located outside the mcuboot directory. Signed-off-by: Sigvart Hovland Signed-off-by: Andrzej Puzdrowski Signed-off-by: Martí Bolívar Signed-off-by: Emil Obalski Signed-off-by: Andrzej Puzdrowski Signed-off-by: Håkon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 0566363271acec5347e523af62b3d7ddc5e501a2) --- boot/zephyr/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 76ada498e..b0e43cd50 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -50,8 +50,6 @@ if(NOT EXISTS ${NRFXLIB_DIR}) To use the tinycrypt set `CONFIG_BOOT_ECDSA_TINYCRYPT` to y. ------------------------------------------------------------------------") endif() -# Don't include this if we are using west - add_subdirectory(${NRFXLIB_DIR} ${PROJECT_BINARY_DIR}/nrfxlib) endif() zephyr_library_include_directories( From 54f21298ed294b707b5c78f6da81b5e2d262e95b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Fri, 3 Sep 2021 14:38:54 -0700 Subject: [PATCH 026/125] [nrf noup] zephyr: add 'minimal' configuration files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add prj_minimal.conf, a Kconfig fragment to be used for minimally sized image production. The minimal fragment has been simplified for only external crypto. Move partition sizing into Kconfig to be consistent with the method used by b0. Using this fragment with prj_minimal.conf makes MCUboot < 16kB for all nRF devices (9160 still needs 32kB partition). Ref: NCSDK-6704 Signed-off-by: Stephen Stauts Signed-off-by: Martí Bolívar Signed-off-by: Sebastian Bøe Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel Signed-off-by: Andrzej Puzdrowski Signed-off-by: Artur Hadasz (cherry picked from commit 33d3e61f00efdcb606cac25f8b0566123ef3b26f) --- .../nrf5340dk_nrf5340_cpuapp_minimal.conf | 13 ++++++ boot/zephyr/prj_minimal.conf | 41 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf create mode 100644 boot/zephyr/prj_minimal.conf diff --git a/boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf b/boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf new file mode 100644 index 000000000..dd5468106 --- /dev/null +++ b/boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf @@ -0,0 +1,13 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# CC3xx is currently not used for nrf53 +CONFIG_HW_CC3XX=n +CONFIG_NRF_CC3XX_PLATFORM=n + +# Required for kernel operation +CONFIG_CLOCK_CONTROL=y +CONFIG_SYS_CLOCK_EXISTS=y diff --git a/boot/zephyr/prj_minimal.conf b/boot/zephyr/prj_minimal.conf new file mode 100644 index 000000000..91cf1bc96 --- /dev/null +++ b/boot/zephyr/prj_minimal.conf @@ -0,0 +1,41 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_MAIN_STACK_SIZE=10240 +CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" + +CONFIG_FLASH=y +CONFIG_FPROTECT=y +CONFIG_PM=n + +CONFIG_BOOT_SWAP_SAVE_ENCTLV=n +CONFIG_BOOT_ENCRYPT_IMAGE=n + +CONFIG_BOOT_BOOTSTRAP=n +CONFIG_BOOT_UPGRADE_ONLY=n + +### Minimal Configurations ### +CONFIG_BOOT_USE_MIN_PARTITION_SIZE=y +CONFIG_ASSERT=n +CONFIG_BOOT_BANNER=n +CONFIG_NCS_BOOT_BANNER=n +CONFIG_CLOCK_CONTROL=n +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_GPIO=n +CONFIG_KERNEL_MEM_POOL=n +CONFIG_LOG=n +CONFIG_COMMON_LIBC_CALLOC=n +CONFIG_COMMON_LIBC_MALLOC=n +CONFIG_COMMON_LIBC_REALLOCARRAY=n +CONFIG_NCS_SAMPLES_DEFAULTS=n +CONFIG_NO_RUNTIME_CHECKS=y +CONFIG_NRF_RTC_TIMER=n +CONFIG_PRINTK=n +CONFIG_SERIAL=n +CONFIG_SIZE_OPTIMIZATIONS=y +CONFIG_SYS_CLOCK_EXISTS=n +CONFIG_UART_CONSOLE=n From 313de9ca5b4e9015642b100007f4314483121f68 Mon Sep 17 00:00:00 2001 From: Bernt Johan Damslora Date: Fri, 20 Sep 2019 18:25:41 +0200 Subject: [PATCH 027/125] [nrf noup] boards: add support for Thingy:91 Adds project configurations for the two systems on the Thingy:91 (PCA-20035) board. The bootloader that is factory-programmed on thing91 does not support ECDSA signature type. Hence this commit also sets the signature type to RSA for applications built for Thingy:91. Signed-off-by: Bernt Johan Damslora Signed-off-by: Sigvart Hovland Signed-off-by: Jon Helge Nistad Signed-off-by: Balaji Srinivasan Signed-off-by: Robert Lubos Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Marek Pieta Signed-off-by: Dominik Ermel (cherry picked from commit 0512d8dbeaf49330865c9095496814bf5b8fc4ad) --- boot/zephyr/boards/thingy91_nrf52840.conf | 34 +++++++++++++++++++++++ boot/zephyr/boards/thingy91_nrf9160.conf | 13 +++++++++ 2 files changed, 47 insertions(+) create mode 100644 boot/zephyr/boards/thingy91_nrf52840.conf create mode 100644 boot/zephyr/boards/thingy91_nrf9160.conf diff --git a/boot/zephyr/boards/thingy91_nrf52840.conf b/boot/zephyr/boards/thingy91_nrf52840.conf new file mode 100644 index 000000000..c0d183401 --- /dev/null +++ b/boot/zephyr/boards/thingy91_nrf52840.conf @@ -0,0 +1,34 @@ +# Disable Zephyr console +CONFIG_LOG=n +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_UART_CONSOLE=n + +# The build won't fit on the partition allocated for it without size +# optimizations. +CONFIG_SIZE_OPTIMIZATIONS=y +CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x12000 + +# Serial +CONFIG_SERIAL=y +CONFIG_UART_NRFX=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_LINE_CTRL=y + +# MCUboot serial recovery +CONFIG_GPIO=y +CONFIG_MCUBOOT_SERIAL=y +CONFIG_BOOT_SERIAL_CDC_ACM=y + +# Required by USB +CONFIG_MULTITHREADING=y + +# USB +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_PRODUCT="MCUBOOT" +CONFIG_USB_CDC_ACM=y +CONFIG_USB_COMPOSITE_DEVICE=y +CONFIG_USB_MASS_STORAGE=n +CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor" +CONFIG_USB_DEVICE_VID=0x1915 +CONFIG_USB_DEVICE_PID=0x520F diff --git a/boot/zephyr/boards/thingy91_nrf9160.conf b/boot/zephyr/boards/thingy91_nrf9160.conf new file mode 100644 index 000000000..1bf2e424d --- /dev/null +++ b/boot/zephyr/boards/thingy91_nrf9160.conf @@ -0,0 +1,13 @@ +# Disable Zephyr console +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_UART_CONSOLE=n + +# Disable Flash protection +CONFIG_FPROTECT=n + +# MCUBoot settings +CONFIG_BOOT_MAX_IMG_SECTORS=256 + +# MCUboot serial recovery +CONFIG_MCUBOOT_SERIAL=y From abaff579f26f58d9c8969ee5863d5e44d56bcc7e Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Mon, 21 Mar 2022 13:44:27 +0100 Subject: [PATCH 028/125] [nrf noup] zephyr: Restore default RTC user channel count The default value of CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT for nRF52 SOCs has been changed from 0 to 3, but it makes MCUBoot get stuck on erasing flash pages when swapping two images. Restore the previous value until the RTC issue is resolved (see NCSDK-14427) Signed-off-by: Damian Krolik Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 3957a30521a42f1794dca54f3e8f383f8d69ce8a) --- boot/zephyr/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 119e07579..51dc99b27 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -34,3 +34,4 @@ CONFIG_MCUBOOT_LOG_LEVEL_INF=y CONFIG_CBPRINTF_NANO=y ### Use the minimal C library to reduce flash usage CONFIG_MINIMAL_LIBC=y +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 From 19d7a4e5526a1b6d7d9282508d1089add9936df6 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Fri, 8 Dec 2023 13:18:12 +0100 Subject: [PATCH 029/125] [nrf noup] boards: thingy91x: add board config This patch adds board configuration for the Thingy:91 X. Signed-off-by: Maximilian Deubel (cherry picked from commit 1b2d11cfa241f049dac60282de43c17abcf02398) --- .../boards/thingy91x_nrf5340_cpuapp.conf | 54 +++++++++++++++++++ boot/zephyr/boards/thingy91x_nrf9151.conf | 8 +++ 2 files changed, 62 insertions(+) create mode 100644 boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf create mode 100644 boot/zephyr/boards/thingy91x_nrf9151.conf diff --git a/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf new file mode 100644 index 000000000..72dfa7fca --- /dev/null +++ b/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf @@ -0,0 +1,54 @@ +# MCUBoot settings +CONFIG_BOOT_MAX_IMG_SECTORS=110 + +# MCUboot serial recovery +CONFIG_MCUBOOT_SERIAL=y + +# Disable Zephyr console +CONFIG_LOG=n +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_UART_CONSOLE=n + +# Serial +CONFIG_SERIAL=y +CONFIG_UART_NRFX=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_UART_LINE_CTRL=y + +# MCUboot serial recovery +CONFIG_GPIO=y +CONFIG_MCUBOOT_SERIAL=y +CONFIG_BOOT_SERIAL_CDC_ACM=y + +# Required by USB +CONFIG_MULTITHREADING=y + +# USB +CONFIG_USB_DEVICE_STACK=y +CONFIG_USB_DEVICE_PRODUCT="MCUBOOT" +CONFIG_USB_CDC_ACM=y +CONFIG_USB_COMPOSITE_DEVICE=y +CONFIG_USB_MASS_STORAGE=n +CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor" +CONFIG_USB_DEVICE_VID=0x1915 +CONFIG_USB_DEVICE_PID=0x520F + +CONFIG_BOOT_SERIAL_BOOT_MODE=y + +CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x13E00 + +# 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 + +CONFIG_BOOT_IMAGE_ACCESS_HOOKS=y +CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y + +CONFIG_NRF53_RECOVERY_NETWORK_CORE=y diff --git a/boot/zephyr/boards/thingy91x_nrf9151.conf b/boot/zephyr/boards/thingy91x_nrf9151.conf new file mode 100644 index 000000000..33cd3301c --- /dev/null +++ b/boot/zephyr/boards/thingy91x_nrf9151.conf @@ -0,0 +1,8 @@ +# MCUBoot settings +CONFIG_BOOT_MAX_IMG_SECTORS=512 + +CONFIG_SPI=y +CONFIG_SPI_NOR=y +CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 +CONFIG_SPI_NOR_SFDP_DEVICETREE=y +CONFIG_MULTITHREADING=y From 89361bdec45690575952743ef65bc357977ddbb9 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 030/125] [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 (cherry picked from commit 9554013f013d5bc067b41d9ad470bc09c346eb71) --- 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 ++++++++++++++++++++ boot/zephyr/prj.conf | 1 + ext/nrf/cc310_glue.h | 2 +- zephyr/module.yml | 3 +- 12 files changed, 299 insertions(+), 11 deletions(-) create mode 100644 boot/zephyr/pm.yml diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 8c73f7652..d6092d86b 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -145,6 +145,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all, * * Failure to read any headers is a fatal error. */ +#ifdef PM_S1_ADDRESS + /* 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 { @@ -1204,7 +1213,24 @@ boot_validate_slot(struct boot_loader_state *state, int slot, goto out; } - if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) { + 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)) { BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot"); BOOT_LOG_ERR("Erasing image from secondary slot"); @@ -1280,6 +1306,42 @@ 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)) { @@ -2655,15 +2717,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_PRIMARY_SLOT, 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_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; + } } #else /* Even if we're not re-validating the primary slot, we could be booting @@ -2680,11 +2752,16 @@ 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_PRIMARY_SLOT); if (rc != 0) { diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c index 8b7bcab13..ed0947076 100644 --- a/boot/bootutil/src/swap_move.c +++ b/boot/bootutil/src/swap_move.c @@ -230,6 +230,18 @@ 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; @@ -295,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_scratch.c b/boot/bootutil/src/swap_scratch.c index e1d49de49..360dbe88c 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -271,6 +271,18 @@ 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; @@ -368,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) \ diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index b0e43cd50..9424efcc3 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -355,6 +355,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 0e8265002..c37911f8e 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 0cb793b2d..b61b535e0 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -71,6 +71,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" @@ -131,6 +135,11 @@ K_SEM_DEFINE(boot_log_sem, 1, 1); * !defined(ZEPHYR_LOG_MODE_MINIMAL) */ +#if USE_PARTITION_MANAGER && CONFIG_FPROTECT +#include +#include +#endif + BOOT_LOG_MODULE_REGISTER(mcuboot); void os_heap_init(void); @@ -182,6 +191,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_nvic(); /* cleanup NVIC registers */ @@ -606,7 +628,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/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 51dc99b27..6d538d1de 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -18,6 +18,7 @@ CONFIG_BOOT_BOOTSTRAP=n # CONFIG_TINYCRYPT_SHA256 is not set CONFIG_FLASH=y +CONFIG_FPROTECT=y ### Various Zephyr boards enable features that we don't want. # CONFIG_BT is not set 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 d2af55384..b73ae2a0d 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 2cdbcb02a960f625e7a067f37ab573a4ebaa03a7 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Thu, 27 Aug 2020 14:29:31 +0200 Subject: [PATCH 031/125] [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 (cherry picked from commit 3db6eca8c7968a1eb1cb11fda08f763004f8226d) --- boot/bootutil/src/loader.c | 96 ++++++++++++++----- .../boards/thingy53_nrf5340_cpuapp.conf | 74 +++++++++++++- boot/zephyr/include/sysflash/sysflash.h | 23 +++++ boot/zephyr/main.c | 7 ++ boot/zephyr/pm.yml | 13 +++ 5 files changed, 185 insertions(+), 28 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index d6092d86b..9a6f3015c 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -50,6 +50,10 @@ #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 @@ -1306,7 +1310,15 @@ 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_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; /* 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 @@ -1314,34 +1326,36 @@ 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) { - 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; - } - } + 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 */ + } +#endif /* PM_S1_ADDRESS || CONFIG_SOC_NRF5340_CPUAPP */ swap_type = boot_swap_type_multi(BOOT_CURR_IMG(state)); if (BOOT_IS_UPGRADE(swap_type)) { @@ -1355,7 +1369,37 @@ 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 b61b535e0..c243a1ac7 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -93,6 +93,10 @@ 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. */ @@ -648,6 +652,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 0f2061be7ecee80c2b2c6772efc719415e89b880 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 27 Feb 2020 12:48:56 +0100 Subject: [PATCH 032/125] [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 c14ac2bfaa7324a93a0abdb01ea3b96a2589d29d) --- 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 9424efcc3..e19f10455 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -719,3 +719,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 c243a1ac7..d3d88980a 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -144,6 +144,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); @@ -207,7 +211,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_nvic(); /* cleanup NVIC registers */ 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 c9f632d1ddd6774e750577a83b562f5b739249fc Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Fri, 6 Jan 2023 12:24:48 +0100 Subject: [PATCH 033/125] [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 11ea3a21b446f4018ed09c883d56840e20816c80) --- 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, 69 insertions(+), 22 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index e19f10455..424cf1315 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -720,7 +720,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/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/main.c b/boot/zephyr/main.c index d3d88980a..8f846ac05 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -144,7 +144,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 @@ -214,6 +214,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_nvic(); /* cleanup NVIC registers */ diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index 5bab26b24..051705ec9 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 @@ -81,3 +111,12 @@ 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 c1cf5e424057fea8a317bccd88dff62888453ccf Mon Sep 17 00:00:00 2001 From: Christian Taedcke Date: Thu, 10 Feb 2022 15:37:49 +0100 Subject: [PATCH 034/125] [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 (cherry picked from commit 36440318f0e7d7285a8ed89fe445273f294d220f) --- boot/bootutil/src/loader.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 9a6f3015c..3e77a0cfb 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1315,10 +1315,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_SECONDARY_SLOT); - 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_SECONDARY_SLOT); 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 @@ -1328,16 +1327,19 @@ 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_PRIMARY_SLOT), &primary_fa); @@ -1373,16 +1375,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 1ec17e963cb21d6978792e2aaf504838f20b52d8 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 22 Sep 2023 21:31:08 +0000 Subject: [PATCH 035/125] [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 (cherry picked from commit 1e991723c85e8ef8d6df432f196ec75c89caf78c) --- 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 3e77a0cfb..6f33cad72 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1206,6 +1206,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_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); struct image_header *secondary_hdr = boot_img_hdr(state, slot); From c8d8f5a48cf1f17bad6cbc41dfd83a5f584ab005 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 18 Sep 2023 13:47:00 +0100 Subject: [PATCH 036/125] [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 e92f17c3ecc644b2fc813e7440186c95d34aa965) --- boot/zephyr/CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 424cf1315..3a94315f8 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -725,3 +725,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 d07555bf0439aeec7c15609c46a85a06fa9be807 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Tue, 17 Oct 2023 11:28:09 +0200 Subject: [PATCH 037/125] [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 2d5f4f9291d7e70beabd726ba63ab31afd916ce4) --- 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 8f846ac05..72d0e72ff 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -201,13 +201,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 420ac794db054e9a3bae31c6627d5b08920de0ed Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Wed, 27 Sep 2023 15:18:04 +0200 Subject: [PATCH 038/125] =?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 (cherry picked from commit 42e8551d6bdcb50388ab7aac51d44aa12cf8ef55) --- boot/bootutil/src/loader.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 6f33cad72..a14215c28 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -52,6 +52,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 @@ -1159,9 +1163,21 @@ boot_validate_slot(struct boot_loader_state *state, int slot, int rc; /* Check if version of secondary slot is sufficient */ - rc = boot_version_cmp( - &boot_img_hdr(state, BOOT_SECONDARY_SLOT)->ih_ver, - &boot_img_hdr(state, BOOT_PRIMARY_SLOT)->ih_ver); + +#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)) { BOOT_LOG_ERR("insufficient version in secondary slot"); boot_scramble_slot(fap, slot); From 937e0f6d566c43d7b2445bd74b586ef28fb64aff Mon Sep 17 00:00:00 2001 From: Nikodem Kastelik Date: Mon, 9 Oct 2023 09:55:57 +0200 Subject: [PATCH 039/125] [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 87d7d74c0ce9e97fad3e58ade37730e1a1c40348) --- 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 470e7cb53980087f835c81eedd2b4c11180fde41 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Tue, 30 Mar 2021 22:45:17 +0200 Subject: [PATCH 040/125] [nrf noup] loader: work-around for multi-image builds Seems multi-image dependencies are not supported for multi-image in NCS yet. This is a workaround which reverts some lines to restore previous MCUboot behavior, so that Immutable bootloader + MCUBoot type builds will work. Ref. NCSDK-8681 Signed-off-by: Sigvart Hovland (cherry picked from commit 663f42e61280b07dbb9083cb3c6713e15737c502) --- boot/bootutil/src/loader.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index a14215c28..a596f8f56 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -547,7 +547,7 @@ boot_verify_dependencies(struct boot_loader_state *state) if (rc == 0) { /* All dependencies've been satisfied, continue with next image. */ BOOT_CURR_IMG(state)++; - } else { + } else if (rc == BOOT_EBADIMAGE) { /* Cannot upgrade due to non-met dependencies, so disable all * image upgrades. */ @@ -556,7 +556,10 @@ boot_verify_dependencies(struct boot_loader_state *state) BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE; } break; - } + } else { + /* Other error happened, images are inconsistent */ + return rc; + } } return rc; } From 1ca64e93ce9f7484e9033989ff7dbfcacab0864b Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 31 Aug 2023 08:58:31 +0100 Subject: [PATCH 041/125] [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 cd1fe3442bdf141bfe9e8925553aed562173ebb6) --- 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 a596f8f56..301e528c4 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1405,7 +1405,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 @@ -1433,7 +1433,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 75073fd88eca232c350c9a0af3c859815cb1ca4e Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Wed, 31 May 2023 14:41:13 +0200 Subject: [PATCH 042/125] [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 (cherry picked from commit a39070a2e56d9bbdf0772f298253a7b1592c1158) --- boot/bootutil/src/loader.c | 42 +++++++++++++++++++------ boot/zephyr/include/sysflash/sysflash.h | 19 +++++++++-- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 301e528c4..d30470e48 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1256,6 +1256,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 { @@ -1369,18 +1374,37 @@ 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; } - /* 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 bc86df639008e27e8296b9253079944c689eacad Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 10 Aug 2023 17:32:48 +0000 Subject: [PATCH 043/125] [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 8d4a62b09bd2bf155a3ea3ae993743694d5838da) --- 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 3b3298de5dae0055bf95c2bf62a7f45a8c36b950 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 11 Aug 2023 12:29:13 +0000 Subject: [PATCH 044/125] [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 b1ef2487ce616483c914b168595d2188eb2a2bd0) --- 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 bd97f58190446c2a6e6a6e1a273b38a0ae848273 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 15 Feb 2024 16:47:25 +0100 Subject: [PATCH 045/125] [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 (cherry picked from commit 6dca0d27546f4b1e808f82646b77522c57fd6d6f) --- 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 d30470e48..ab26dcdbf 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1329,6 +1329,87 @@ 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 @@ -1367,6 +1448,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) @@ -1401,6 +1485,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)) { @@ -1409,7 +1494,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)); @@ -2682,6 +2769,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 271e50509bfb6d9625f25b4b6f8ccd991799e93e Mon Sep 17 00:00:00 2001 From: Grzegorz Chwierut Date: Fri, 17 May 2024 18:25:07 +0200 Subject: [PATCH 046/125] [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 b525a7791c837e04ebdf3dda67d3741a45a8c550) --- 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 ab26dcdbf..7c379a7b2 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1329,6 +1329,8 @@ 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)) @@ -1410,7 +1412,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 f5f382f4fe888e560e0db125fded0ef49ba6e7a7 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Tue, 12 Mar 2024 12:30:52 +0100 Subject: [PATCH 047/125] [nrf noup] boards: thingy91x: enable serial recovery This patch disbales MCUBoot logging and enables serial recovery for the Thingy:91. Signed-off-by: Maximilian Deubel Signed-off-by: Bernt Johan Damslora (cherry picked from commit 654a1e3143542234c9931cd52b692cab632b1cc1) --- boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf | 10 ++++++++-- boot/zephyr/boards/thingy91x_nrf9151.conf | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf index 72dfa7fca..37c7e95b1 100644 --- a/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf @@ -32,7 +32,7 @@ CONFIG_USB_COMPOSITE_DEVICE=y CONFIG_USB_MASS_STORAGE=n CONFIG_USB_DEVICE_MANUFACTURER="Nordic Semiconductor" CONFIG_USB_DEVICE_VID=0x1915 -CONFIG_USB_DEVICE_PID=0x520F +CONFIG_USB_DEVICE_PID=0x910A CONFIG_BOOT_SERIAL_BOOT_MODE=y @@ -49,6 +49,12 @@ CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y CONFIG_FLASH_SIMULATOR_STATS=n CONFIG_BOOT_IMAGE_ACCESS_HOOKS=y -CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y +# Makes it possible to update the network core using the flash simulator CONFIG_NRF53_RECOVERY_NETWORK_CORE=y + +CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y +CONFIG_BOOT_SERIAL_IMG_GRP_IMAGE_STATE=y + +# Skip checks on the secondary image to make it possible to update MCUBoot on S1/S0 +CONFIG_MCUBOOT_VERIFY_IMG_ADDRESS=n diff --git a/boot/zephyr/boards/thingy91x_nrf9151.conf b/boot/zephyr/boards/thingy91x_nrf9151.conf index 33cd3301c..2efe1e170 100644 --- a/boot/zephyr/boards/thingy91x_nrf9151.conf +++ b/boot/zephyr/boards/thingy91x_nrf9151.conf @@ -6,3 +6,12 @@ CONFIG_SPI_NOR=y CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 CONFIG_SPI_NOR_SFDP_DEVICETREE=y CONFIG_MULTITHREADING=y + +# Disable Zephyr console and use UART for MCUboot serial recovery instead +CONFIG_CONSOLE=n +CONFIG_CONSOLE_HANDLER=n +CONFIG_UART_CONSOLE=n +CONFIG_MCUBOOT_SERIAL=y + +CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y +CONFIG_BOOT_SERIAL_IMG_GRP_IMAGE_STATE=y From b8f6a06206675d1c51009215aeb9c7b1b348d45f Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Fri, 17 May 2024 14:14:54 +0200 Subject: [PATCH 048/125] [nrf noup] boot: zephyr: Disable boot banner if NCS_BOOT_BANNER is used Mcuboot's boot banner should not be used if NCS boot banner is enabled. Signed-off-by: Robert Lubos (cherry picked from commit 86ab04b79ab4494186d2c0b2577d7fd67459f0ce) --- boot/zephyr/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index c37911f8e..c42928d1f 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1078,6 +1078,7 @@ config BOOT_DISABLE_CACHES config MCUBOOT_BOOT_BANNER bool "Use MCUboot boot banner" depends on BOOT_BANNER + depends on !NCS_BOOT_BANNER depends on "$(APP_VERSION_EXTENDED_STRING)" != "" default y help From 8949a6a34d4522447069a6630866f136132e3ac3 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Mon, 27 May 2024 13:59:49 +0200 Subject: [PATCH 049/125] [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 d4e6c3e1b5c9f6a1efcff7a26be1fa7ddeb8fc1b) --- 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 72d0e72ff..64e11c3c6 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -201,7 +201,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 c41b4a88811a7feeefea7146d44da3ecf9bafc24 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 11 Jun 2024 12:32:51 +0100 Subject: [PATCH 050/125] [nrf noup] boot: zephyr: Add NCS boot banner Adds a boot banner which shows as MCUboot Signed-off-by: Jamie McCrae (cherry picked from commit 4b3d6ab014bca42f57b25bfc1843a473f11cb898) --- boot/zephyr/prj.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 6d538d1de..9ff1ba274 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -36,3 +36,6 @@ CONFIG_CBPRINTF_NANO=y ### Use the minimal C library to reduce flash usage CONFIG_MINIMAL_LIBC=y CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 + +# NCS boot banner +CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="MCUboot" From bf143850d06f24d83c51bc904034e3ccdf22290c Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 13 Jun 2024 16:34:55 +0200 Subject: [PATCH 051/125] [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 (cherry picked from commit 101d9c06702a400e5f6522fd49d828476d38d590) --- 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 insertions(+) diff --git a/boot/bootutil/include/bootutil/security_cnt.h b/boot/bootutil/include/bootutil/security_cnt.h index e1562d2e9..7e1389618 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/image_validate.c b/boot/bootutil/src/image_validate.c index 17193a63d..ade67cc4b 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -540,6 +540,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 BOOT_LOG_DBG("bootutil_img_validate: flash area %p", fap); @@ -736,6 +745,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)) { @@ -755,6 +768,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 */ @@ -774,10 +788,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 out: diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 7c379a7b2..355ebf46c 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -71,6 +71,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}; @@ -1290,6 +1293,38 @@ 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 @@ -1311,6 +1346,26 @@ 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); @@ -1427,6 +1482,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 = @@ -1483,6 +1541,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; @@ -1493,6 +1552,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); @@ -2631,6 +2694,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_PRIMARY_SLOT, From 674adc7d3f6508c9bfeb5f8af93ac489f93d25ce Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Tue, 18 Jun 2024 17:35:41 +0200 Subject: [PATCH 052/125] [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 6bb40d3a656aab1d61f222ad751aed49ff7fc5c3) --- 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 355ebf46c..f390d5aee 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -50,6 +50,10 @@ #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 @@ -2926,6 +2930,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 c42928d1f..89cda41bd 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 1f364bf2105226a6a12eb51ef25bce2a7fe1219b Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 29 Aug 2024 12:41:37 +0100 Subject: [PATCH 053/125] [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 71686796e8560f5a62db3cd1e8a03e4ca952beeb) --- 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 f390d5aee..dabb562c9 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -1516,7 +1516,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; @@ -1589,7 +1589,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 62ddef300f7567b43014e8d8e71ca94e6bd4ef5c Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Wed, 18 Sep 2024 12:28:37 +0200 Subject: [PATCH 054/125] [nrf noup] boards: nrf54l15dk: Disable FPROTECT FPROTECT is not suppored for nrf54l15dk. Signed-off-by: Andrzej Puzdrowski (cherry picked from commit 1c8ff2a3089233f4d8b17251f145e9844309ac6b) --- boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf b/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf index c8fcd32c3..1dbd7c1ab 100644 --- a/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf +++ b/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf @@ -7,6 +7,9 @@ CONFIG_BOOT_MAX_IMG_SECTORS=256 # Ensure that the SPI NOR driver is disabled by default CONFIG_SPI_NOR=n +# TODO: below are not yet supported and need fixing +CONFIG_FPROTECT=n + CONFIG_BOOT_WATCHDOG_FEED=n # Ensure the fastest RRAM write operations From 2c64b71cf0f060786b0e821a6b94128d9f8e35e1 Mon Sep 17 00:00:00 2001 From: Sigvart Hovland Date: Thu, 14 Feb 2019 13:20:34 +0100 Subject: [PATCH 055/125] [nrf noup] boot: Add shared crypto for ECDSA and SHA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add functions for ecdsa_verify_secp256r1 and sha256 to use the shared crypto API * Add Kconfig and CMake variables for selecting shared crypto when using ecdsa * Add custom section to project for placing the API section in the correct location in flash * Add kconfig fragment for using external crypto Signed-off-by: Sigvart Hovland Signed-off-by: Martí Bolívar Signed-off-by: Emil Obalski Signed-off-by: Andrzej Puzdrowski Signed-off-by: Håkon Øye Amundsen Signed-off-by: Ioannis Glaropoulos Signed-off-by: Trond Einar Snekvik Signed-off-by: Georgios Vasilakis Signed-off-by: Johann Fischer Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel Signed-off-by: Artur Hadasz (cherry picked from commit d3412b038b6a6195b0d1f5f6e5bdbd94a29f825a) --- boot/bootutil/include/bootutil/crypto/ecdsa.h | 66 +++++++++++++++++-- boot/bootutil/include/bootutil/crypto/sha.h | 32 +++++++++ boot/zephyr/CMakeLists.txt | 2 + boot/zephyr/external_crypto.conf | 20 ++++++ .../include/mcuboot_config/mcuboot_config.h | 2 + 5 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 boot/zephyr/external_crypto.conf diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index 3b0541072..a5d0f8b1b 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -34,6 +34,7 @@ #if (defined(MCUBOOT_USE_TINYCRYPT) + \ defined(MCUBOOT_USE_CC310) + \ + defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \ defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1 #error "One crypto backend must be defined: either CC310/TINYCRYPT/MBED_TLS/PSA_CRYPTO" #endif @@ -70,12 +71,18 @@ #include "bootutil/sign_key.h" #include "common.h" +#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + #include + #define NUM_ECC_BYTES (256 / 8) +#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ + #ifdef __cplusplus extern "C" { #endif #if (defined(MCUBOOT_USE_TINYCRYPT) || defined(MCUBOOT_USE_MBED_TLS) || \ - defined(MCUBOOT_USE_CC310)) && !defined(MCUBOOT_USE_PSA_CRYPTO) + defined(MCUBOOT_USE_CC310) || defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO)) \ + && !defined(MCUBOOT_USE_PSA_CRYPTO) /* * Declaring these like this adds NULL termination. */ @@ -127,8 +134,7 @@ static int bootutil_import_key(uint8_t **cp, uint8_t *end) } #endif /* (MCUBOOT_USE_TINYCRYPT || MCUBOOT_USE_MBED_TLS || MCUBOOT_USE_CC310) && !MCUBOOT_USE_PSA_CRYPTO */ -#if defined(MCUBOOT_USE_TINYCRYPT) -#ifndef MCUBOOT_ECDSA_NEED_ASN1_SIG +#ifndef MCUBOOT_USE_PSA_CRYPTO /* * cp points to ASN1 string containing an integer. * Verify the tag, and that the length is 32 bytes. Helper function. @@ -178,8 +184,9 @@ static int bootutil_decode_sig(uint8_t signature[NUM_ECC_BYTES * 2], uint8_t *cp } return 0; } -#endif /* not MCUBOOT_ECDSA_NEED_ASN1_SIG */ +#endif /* !MCUBOOT_USE_PSA_CRYPTO */ +#if defined(MCUBOOT_USE_TINYCRYPT) typedef uintptr_t bootutil_ecdsa_context; static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx) { @@ -248,8 +255,12 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, { (void)ctx; (void)pk_len; - (void)sig_len; (void)hash_len; + uint8_t dsig[2 * NUM_ECC_BYTES]; + + if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { + return -1; + } /* Only support uncompressed keys. */ if (pk[0] != 0x04) { @@ -257,7 +268,7 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, } pk++; - return cc310_ecdsa_verify_secp256r1(hash, pk, sig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE); + return cc310_ecdsa_verify_secp256r1(hash, pk, dsig, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE); } static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, @@ -613,6 +624,49 @@ static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, #endif /* MCUBOOT_USE_MBED_TLS */ +#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) +typedef uintptr_t bootutil_ecdsa_context; +static inline void bootutil_ecdsa_init(bootutil_ecdsa_context *ctx) +{ + (void)ctx; +} + +static inline void bootutil_ecdsa_drop(bootutil_ecdsa_context *ctx) +{ + (void)ctx; +} + +static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, + uint8_t *pk, size_t pk_len, + uint8_t *hash, size_t hash_len, + uint8_t *sig, size_t sig_len) +{ + (void)ctx; + (void)pk_len; + (void)hash_len; + uint8_t dsig[2 * NUM_ECC_BYTES]; + + if (bootutil_decode_sig(dsig, sig, sig + sig_len)) { + return -1; + } + + /* Only support uncompressed keys. */ + if (pk[0] != 0x04) { + return -1; + } + pk++; + + return bl_secp256r1_validate(hash, BOOTUTIL_CRYPTO_ECDSA_P256_HASH_SIZE, pk, dsig); +} + +static inline int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, + uint8_t **cp,uint8_t *end) +{ + (void)ctx; + return bootutil_import_key(cp, end); +} +#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ + #ifdef __cplusplus } #endif diff --git a/boot/bootutil/include/bootutil/crypto/sha.h b/boot/bootutil/include/bootutil/crypto/sha.h index 6a009ff95..b83a3ec40 100644 --- a/boot/bootutil/include/bootutil/crypto/sha.h +++ b/boot/bootutil/include/bootutil/crypto/sha.h @@ -30,6 +30,7 @@ #if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS) + \ defined(MCUBOOT_USE_TINYCRYPT) + \ + defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + \ defined(MCUBOOT_USE_CC310)) != 1 #error "One crypto backend must be defined: either CC310/MBED_TLS/TINYCRYPT/PSA_CRYPTO" #endif @@ -270,6 +271,37 @@ static inline int bootutil_sha_finish(bootutil_sha_context *ctx, } #endif /* MCUBOOT_USE_CC310 */ +#if defined(MCUBOOT_USE_NRF_EXTERNAL_CRYPTO) + +#include + +typedef bl_sha256_ctx_t bootutil_sha_context; + +static inline void bootutil_sha_init(bootutil_sha_context *ctx) +{ + bl_sha256_init(ctx); +} + +static inline void bootutil_sha_drop(bootutil_sha_context *ctx) +{ + (void)ctx; +} + +static inline int bootutil_sha_update(bootutil_sha_context *ctx, + const void *data, + uint32_t data_len) +{ + return bl_sha256_update(ctx, data, data_len); +} + +static inline int bootutil_sha_finish(bootutil_sha_context *ctx, + uint8_t *output) +{ + bl_sha256_finalize(ctx, output); + return 0; +} +#endif /* MCUBOOT_USE_NRF_EXTERNAL_CRYPTO */ + #ifdef __cplusplus } #endif diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 3a94315f8..1db4ed270 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -215,6 +215,8 @@ if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) zephyr_library_sources(${NRF_DIR}/cc310_glue.c) zephyr_library_include_directories(${NRF_DIR}) zephyr_link_libraries(nrfxlib_crypto) + elseif(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) + zephyr_include_directories(${BL_CRYPTO_DIR}/../include) endif() if(CONFIG_MBEDTLS_CFG_FILE) diff --git a/boot/zephyr/external_crypto.conf b/boot/zephyr/external_crypto.conf new file mode 100644 index 000000000..8181ad51c --- /dev/null +++ b/boot/zephyr/external_crypto.conf @@ -0,0 +1,20 @@ +# +# Copyright (c) 2021 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +# These configurations should be used when using nrf/samples/bootloader +# as the immutable bootloader (B0), and MCUBoot as the second stage updateable +# bootloader. + +# Set ECDSA as signing mechanism +CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y + +# Use crypto backend from B0 +CONFIG_BOOT_NRF_EXTERNAL_CRYPTO=y +CONFIG_SECURE_BOOT_CRYPTO=y +CONFIG_SB_CRYPTO_CLIENT_ECDSA_SECP256R1=y +CONFIG_SB_CRYPTO_CLIENT_SHA256=y +CONFIG_BL_SHA256_EXT_API_REQUIRED=y +CONFIG_BL_SECP256R1_EXT_API_REQUIRED=y diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index f0dc214b6..ae9571100 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -49,6 +49,8 @@ #endif #elif defined(CONFIG_BOOT_USE_PSA_CRYPTO) #define MCUBOOT_USE_PSA_CRYPTO +#elif defined(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) +#define MCUBOOT_USE_NRF_EXTERNAL_CRYPTO #endif #ifdef CONFIG_BOOT_IMG_HASH_ALG_SHA512 From 599a1b9b55e61e17e1f9f95e1d8b136d0d5a3751 Mon Sep 17 00:00:00 2001 From: Markus Lassila Date: Fri, 30 Aug 2024 13:10:05 +0300 Subject: [PATCH 056/125] [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 d43ef93d466921cb225b2b15f7cb8e2a63f40770) --- 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 64e11c3c6..c51616dda 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -672,7 +672,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 352b2a4a9cdd531cb3a1401f100e7d82e7434958 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 10 Sep 2024 13:41:30 +0100 Subject: [PATCH 057/125] [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 (cherry picked from commit 99601b60adeb6707952665e3a708ae461ff48194) --- 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, 241 insertions(+), 105 deletions(-) create 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 17ed4c616..a88ad0dad 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -427,6 +427,18 @@ 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 dabb562c9..a75d1a911 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -160,15 +160,15 @@ boot_read_image_headers(struct boot_loader_state *state, bool require_all, * * Failure to read any headers is a fatal error. */ -#ifdef PM_S1_ADDRESS +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 /* Patch needed for NCS. The primary slot of the second image * (image 1) will not contain a valid image header until an upgrade * of mcuboot has happened (filling S1 with the new version). */ - if (BOOT_CURR_IMG(state) == 1 && i == 0) { + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER && i == 0) { continue; } -#endif /* PM_S1_ADDRESS */ +#endif /* CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 */ if (i > 0 && !require_all) { return 0; } else { @@ -1176,7 +1176,7 @@ boot_validate_slot(struct boot_loader_state *state, int slot, #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) \ && defined(CONFIG_PCD_APP) && defined(CONFIG_PCD_READ_NETCORE_APP_VERSION) - if (BOOT_CURR_IMG(state) == 1) { + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { rc = pcd_version_cmp_net(fap, boot_img_hdr(state, BOOT_SECONDARY_SLOT)); } else { rc = boot_version_cmp( @@ -1247,35 +1247,54 @@ 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) == 1) { + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_NETWORK_CORE_IMAGE_NUMBER) { min_addr = PM_CPUNET_APP_ADDRESS; max_addr = PM_CPUNET_APP_ADDRESS + PM_CPUNET_APP_SIZE; -#ifdef PM_S1_ADDRESS - } else if (BOOT_CURR_IMG(state) == 0) { + check_addresses = true; + } else +#endif +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER) { +#if (CONFIG_NCS_IS_VARIANT_IMAGE) min_addr = PM_S0_ADDRESS; - max_addr = pri_fa->fa_off + pri_fa->fa_size; + max_addr = (PM_S0_ADDRESS + PM_S0_SIZE); +#else + min_addr = PM_S1_ADDRESS; + max_addr = (PM_S1_ADDRESS + PM_S1_SIZE); #endif + check_addresses = true; } else #endif - { + if (BOOT_CURR_IMG(state) == CONFIG_MCUBOOT_APPLICATION_IMAGE_NUMBER) { +#if CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1 +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + min_addr = MIN(pri_fa->fa_off, PM_S0_ADDRESS); + max_addr = MAX((pri_fa->fa_off + pri_fa->fa_size), (PM_S0_ADDRESS + PM_S0_SIZE)); +#else + min_addr = MIN(pri_fa->fa_off, PM_S1_ADDRESS); + max_addr = MAX((pri_fa->fa_off + pri_fa->fa_size), (PM_S1_ADDRESS + PM_S1_SIZE)); +#endif +#else min_addr = pri_fa->fa_off; max_addr = pri_fa->fa_off + pri_fa->fa_size; +#endif + check_addresses = true; } - if (reset_value < min_addr || reset_value> (max_addr)) { + if (check_addresses == true && (reset_value < min_addr || reset_value > max_addr)) { BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot"); BOOT_LOG_ERR("Erasing image from secondary slot"); @@ -1397,36 +1416,54 @@ boot_update_security_counter(struct boot_loader_state *state, int slot, int hdr_ #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. @@ -1438,8 +1475,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; @@ -1448,17 +1485,20 @@ static void sec_slot_cleanup_if_unusable(void) if (!rc) { rc = flash_area_erase(secondary_fa, 0, secondary_fa->fa_size); if (!rc) { - BOOT_LOG_ERR("Cleaned-up secondary slot of %d. image.", idx); + BOOT_LOG_ERR("Cleaned-up secondary slot of image %d", idx); } } if (rc) { - BOOT_LOG_ERR("Can not cleanup secondary slot of %d. image.", idx); + BOOT_LOG_ERR("Failed to clean-up secondary slot of image %d: %d", idx, rc); } } } } #else +static inline void sec_slot_untouch(struct boot_loader_state *state) +{ +} static inline void sec_slot_touch(struct boot_loader_state *state) { } @@ -1490,7 +1530,7 @@ boot_validated_swap_type(struct boot_loader_state *state, owner_nsib[BOOT_CURR_IMG(state)] = false; #endif -#if defined(PM_S1_ADDRESS) || defined(CONFIG_SOC_NRF5340_CPUAPP) +#if defined(PM_S1_ADDRESS) || defined(PM_CPUNET_B0N_ADDRESS) const struct flash_area *secondary_fa = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT); struct image_header *hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT); @@ -1528,31 +1568,31 @@ boot_validated_swap_type(struct boot_loader_state *state, } /* Check start and end of primary slot for current image */ - if (reset_addr < primary_fa->fa_off) { -#if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(CONFIG_NRF53_MULTI_IMAGE_UPDATE) - const struct flash_area *nsib_fa; - - /* 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; } @@ -1565,7 +1605,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)) { @@ -2237,7 +2277,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; @@ -2931,12 +2986,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: @@ -3004,13 +3053,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..079e193d5 --- /dev/null +++ b/boot/bootutil/src/swap_nsib.c @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "bootutil/bootutil.h" +#include "bootutil_priv.h" +#include "swap_priv.h" +#include "bootutil/bootutil_log.h" + +#include "mcuboot_config/mcuboot_config.h" + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +void nsib_swap_run(struct boot_loader_state *state, struct boot_status *bs) +{ + uint32_t sector_sz; + uint8_t image_index; + const struct flash_area *fap_pri; + const struct flash_area *fap_sec; + int rc; + + BOOT_LOG_INF("Starting swap using nsib algorithm."); + + sector_sz = boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0); + +#if (CONFIG_NCS_IS_VARIANT_IMAGE) + rc = flash_area_open(PM_S0_ID, &fap_pri); +#else + rc = flash_area_open(PM_S1_ID, &fap_pri); +#endif + assert (rc == 0); + image_index = BOOT_CURR_IMG(state); + + rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap_sec); + assert (rc == 0); + + rc = boot_erase_region(fap_pri, 0, fap_pri->fa_size, 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 1db4ed270..0bd0fb919 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -181,6 +181,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 d5f373adeb1c296c8d312ca8484f5f73414d7f48 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 15 Oct 2024 11:31:20 +0100 Subject: [PATCH 058/125] [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 (cherry picked from commit 9c834622b023e321350fca2aedb15a8a9570c63a) --- boot/bootutil/src/loader.c | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index a75d1a911..dd4853874 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -101,6 +101,17 @@ static struct sector_buffer_t sector_buffers; #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 @@ -1182,11 +1193,45 @@ 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 be6d73eca89a94e990f57eac4acd8a6c60858a84 Mon Sep 17 00:00:00 2001 From: Maximilian Deubel Date: Wed, 23 Oct 2024 16:48:13 +0200 Subject: [PATCH 059/125] [nrf noup] boards: Thingy:91 X release config Update the configuration files for the Thingy:91 X targets to the ones used in production. Signed-off-by: Maximilian Deubel Signed-off-by: Michal Kozikowski (cherry picked from commit 8444d75ad1f76463f571f08d8088bcb5b88ae50c) --- boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf | 3 +++ boot/zephyr/boards/thingy91x_nrf9151.conf | 7 +++++-- boot/zephyr/boards/thingy91x_nrf9151.overlay | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 boot/zephyr/boards/thingy91x_nrf9151.overlay diff --git a/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf b/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf index 37c7e95b1..d3e253b65 100644 --- a/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf +++ b/boot/zephyr/boards/thingy91x_nrf5340_cpuapp.conf @@ -58,3 +58,6 @@ CONFIG_BOOT_SERIAL_IMG_GRP_IMAGE_STATE=y # Skip checks on the secondary image to make it possible to update MCUBoot on S1/S0 CONFIG_MCUBOOT_VERIFY_IMG_ADDRESS=n + +CONFIG_BOOT_SERIAL_NO_APPLICATION=y +CONFIG_FW_INFO_FIRMWARE_VERSION=2 diff --git a/boot/zephyr/boards/thingy91x_nrf9151.conf b/boot/zephyr/boards/thingy91x_nrf9151.conf index 2efe1e170..8088686e0 100644 --- a/boot/zephyr/boards/thingy91x_nrf9151.conf +++ b/boot/zephyr/boards/thingy91x_nrf9151.conf @@ -5,13 +5,16 @@ CONFIG_SPI=y CONFIG_SPI_NOR=y CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 CONFIG_SPI_NOR_SFDP_DEVICETREE=y -CONFIG_MULTITHREADING=y # Disable Zephyr console and use UART for MCUboot serial recovery instead CONFIG_CONSOLE=n CONFIG_CONSOLE_HANDLER=n CONFIG_UART_CONSOLE=n CONFIG_MCUBOOT_SERIAL=y - CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y CONFIG_BOOT_SERIAL_IMG_GRP_IMAGE_STATE=y + +CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y +CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK=y + +CONFIG_FW_INFO_FIRMWARE_VERSION=2 diff --git a/boot/zephyr/boards/thingy91x_nrf9151.overlay b/boot/zephyr/boards/thingy91x_nrf9151.overlay new file mode 100644 index 000000000..7f2818c0d --- /dev/null +++ b/boot/zephyr/boards/thingy91x_nrf9151.overlay @@ -0,0 +1,4 @@ +&uart0 { + status = "okay"; + current-speed = < 1000000 >; +}; From e40684941b5d29b21d9ae4d4afb56841b685f177 Mon Sep 17 00:00:00 2001 From: Carles Cufi Date: Fri, 25 Oct 2024 09:37:44 +0200 Subject: [PATCH 060/125] [nrf noup] workflows: Add a backport workflow Enable backporting of PRs. Signed-off-by: Carles Cufi (cherry picked from commit b1376c631a543e03b85e7da6bd473cfb43e973b0) --- .github/workflows/backport.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/backport.yml diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 000000000..e986738ff --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,31 @@ +name: Backport +on: + pull_request_target: + types: + - closed + - labeled + branches: + - main + +jobs: + backport: + name: Backport + runs-on: ubuntu-22.04 + # Only react to merged PRs for security reasons. + # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. + if: > + github.event.pull_request.merged && + ( + github.event.action == 'closed' || + ( + github.event.action == 'labeled' && + contains(github.event.label.name, 'backport') + ) + ) + steps: + - name: Backport + uses: zephyrproject-rtos/action-backport@v2.0.3-3 + with: + github_token: ${{ secrets.NCS_GITHUB_TOKEN }} + issue_labels: Backport + labels_template: '["Backport"]' From 835b63f3a179634b5c265aa1f39f4834b54bd9cc Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Thu, 7 Nov 2024 11:09:18 +0100 Subject: [PATCH 061/125] [nrf noup] boot/zephyr: add nrf54l15dk ext flash configs Moved configs from nrf54l15pdk. Turn protection on fprotect by default. Signed-off-by: Andrzej Puzdrowski Signed-off-by: Mateusz Michalek Signed-off-by: Michal Kozikowski Signed-off-by: Jamie McCrae (cherry picked from commit add70d4044cc2914197ac147af13384f15d80e64) --- .../boards/nrf54l15dk_nrf54l15_cpuapp.conf | 16 ------- .../nrf54l15dk_nrf54l15_cpuapp_ext_flash.conf | 9 ++++ ...f54l15dk_nrf54l15_cpuapp_ext_flash.overlay | 48 +++++++++++++++++++ boot/zephyr/prj.conf | 1 - .../nrf54l05_cpuapp.conf} | 2 - .../nrf54l10_cpuapp.conf} | 2 - boot/zephyr/socs/nrf54l15_cpuapp.conf | 14 ++++++ 7 files changed, 71 insertions(+), 21 deletions(-) delete mode 100644 boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf create mode 100644 boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp_ext_flash.conf create mode 100644 boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp_ext_flash.overlay rename boot/zephyr/{boards/nrf54l15dk_nrf54l05_cpuapp.conf => socs/nrf54l05_cpuapp.conf} (94%) rename boot/zephyr/{boards/nrf54l15dk_nrf54l10_cpuapp.conf => socs/nrf54l10_cpuapp.conf} (94%) diff --git a/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf b/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf deleted file mode 100644 index 1dbd7c1ab..000000000 --- a/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp.conf +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2024 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: Apache-2.0 -# -CONFIG_BOOT_MAX_IMG_SECTORS=256 - -# Ensure that the SPI NOR driver is disabled by default -CONFIG_SPI_NOR=n - -# TODO: below are not yet supported and need fixing -CONFIG_FPROTECT=n - -CONFIG_BOOT_WATCHDOG_FEED=n - -# Ensure the fastest RRAM write operations -CONFIG_NRF_RRAM_WRITE_BUFFER_SIZE=32 diff --git a/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp_ext_flash.conf b/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp_ext_flash.conf new file mode 100644 index 000000000..ec944f828 --- /dev/null +++ b/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp_ext_flash.conf @@ -0,0 +1,9 @@ +CONFIG_SPI=y +CONFIG_SPI_NOR=y +CONFIG_FLASH=y +CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x14000 +CONFIG_MAIN_STACK_SIZE=20480 +CONFIG_BOOT_MAX_IMG_SECTORS=512 +CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 +# Ensure that the qspi driver is disabled by default +CONFIG_NORDIC_QSPI_NOR=n diff --git a/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp_ext_flash.overlay b/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp_ext_flash.overlay new file mode 100644 index 000000000..ba6274221 --- /dev/null +++ b/boot/zephyr/boards/nrf54l15dk_nrf54l15_cpuapp_ext_flash.overlay @@ -0,0 +1,48 @@ +/ { + chosen { + nordic,pm-ext-flash = &mx25r64; + zephyr,code-partition = &boot_partition; + }; +}; + +/delete-node/ &boot_partition; +/delete-node/ &slot0_partition; +/delete-node/ &slot1_partition; + +/delete-node/ &storage_partition; + +&cpuapp_rram { + reg = < 0x0 DT_SIZE_K(1524) >; + + partitions { + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x000000000 0x00014000>; + }; + + slot0_partition: partition@14000 { + label = "image-0"; + reg = <0x000014000 0x0015A000>; + }; + + storage_partition: partition@16E000 { + label = "storage"; + reg = < 0x16E000 0x9000 >; + }; + }; +}; + +&mx25r64 { + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + slot1_partition: partition@0 { + label = "image-1"; + reg = <0x000000000 0x0015A000>; + }; + }; +}; diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 9ff1ba274..eecc1cbca 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -18,7 +18,6 @@ CONFIG_BOOT_BOOTSTRAP=n # CONFIG_TINYCRYPT_SHA256 is not set CONFIG_FLASH=y -CONFIG_FPROTECT=y ### Various Zephyr boards enable features that we don't want. # CONFIG_BT is not set diff --git a/boot/zephyr/boards/nrf54l15dk_nrf54l05_cpuapp.conf b/boot/zephyr/socs/nrf54l05_cpuapp.conf similarity index 94% rename from boot/zephyr/boards/nrf54l15dk_nrf54l05_cpuapp.conf rename to boot/zephyr/socs/nrf54l05_cpuapp.conf index f911aa248..c8fcd32c3 100644 --- a/boot/zephyr/boards/nrf54l15dk_nrf54l05_cpuapp.conf +++ b/boot/zephyr/socs/nrf54l05_cpuapp.conf @@ -7,8 +7,6 @@ CONFIG_BOOT_MAX_IMG_SECTORS=256 # Ensure that the SPI NOR driver is disabled by default CONFIG_SPI_NOR=n -CONFIG_FPROTECT=y - CONFIG_BOOT_WATCHDOG_FEED=n # Ensure the fastest RRAM write operations diff --git a/boot/zephyr/boards/nrf54l15dk_nrf54l10_cpuapp.conf b/boot/zephyr/socs/nrf54l10_cpuapp.conf similarity index 94% rename from boot/zephyr/boards/nrf54l15dk_nrf54l10_cpuapp.conf rename to boot/zephyr/socs/nrf54l10_cpuapp.conf index f911aa248..c8fcd32c3 100644 --- a/boot/zephyr/boards/nrf54l15dk_nrf54l10_cpuapp.conf +++ b/boot/zephyr/socs/nrf54l10_cpuapp.conf @@ -7,8 +7,6 @@ CONFIG_BOOT_MAX_IMG_SECTORS=256 # Ensure that the SPI NOR driver is disabled by default CONFIG_SPI_NOR=n -CONFIG_FPROTECT=y - CONFIG_BOOT_WATCHDOG_FEED=n # Ensure the fastest RRAM write operations diff --git a/boot/zephyr/socs/nrf54l15_cpuapp.conf b/boot/zephyr/socs/nrf54l15_cpuapp.conf index 8db9d2d23..645325513 100644 --- a/boot/zephyr/socs/nrf54l15_cpuapp.conf +++ b/boot/zephyr/socs/nrf54l15_cpuapp.conf @@ -1,3 +1,17 @@ +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_BOOT_MAX_IMG_SECTORS=256 + +# Ensure that the SPI NOR driver is disabled by default +CONFIG_SPI_NOR=n + +CONFIG_BOOT_WATCHDOG_FEED=n + +# Ensure the fastest RRAM write operations +CONFIG_NRF_RRAM_WRITE_BUFFER_SIZE=32 + # Link Time Optimizations CONFIG_ISR_TABLES_LOCAL_DECLARATION=y CONFIG_LTO=y From a4457ac3dd0a734fb7ff2122fef2eadc3dc5b2ad Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Thu, 19 Sep 2024 14:32:37 +0200 Subject: [PATCH 062/125] [nrf noup] boot/zephyr/Kconfig: conditionally disable BOOT_MAX_IMG_SECTORS_AUTO Automatic calculation are based on DTS data which are no the right source on partition layout in case Partition manager does the partitioning. Signed-off-by: Andrzej Puzdrowski Signed-off-by: Dominik Ermel (cherry picked from commit 19ac794b9c56162b8e59f07b8827ba1549c779de) --- boot/zephyr/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 89cda41bd..e482d9fab 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -709,7 +709,7 @@ config BOOT_ENCRYPTION_KEY_FILE config BOOT_MAX_IMG_SECTORS_AUTO bool "Calculate maximum sectors automatically" - default y + default y if !PARTITION_MANAGER_ENABLED help If this option is enabled then the maximum number of supported sectors per image will be calculated automatically from the flash erase sizes and size of each partition for From 2f3b28c09ebc156310732cc991d2c5995e62aed2 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 9 Dec 2024 12:27:38 +0000 Subject: [PATCH 063/125] [nrf noup] boot: zephyr: serial_recovery: Add nRF5340 Kconfig override Adds additional conditions that lets the direct upload option to be selected on nRF5340 to allow for uploading network core updates directly to the network core with the flash simulator Signed-off-by: Jamie McCrae (cherry picked from commit 2591ebdedca1d6deb2e94bb6d8617356d0d419be) --- boot/zephyr/Kconfig.serial_recovery | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig.serial_recovery b/boot/zephyr/Kconfig.serial_recovery index 45d252408..5b4ba3e11 100644 --- a/boot/zephyr/Kconfig.serial_recovery +++ b/boot/zephyr/Kconfig.serial_recovery @@ -46,9 +46,14 @@ config BOOT_SERIAL_CDC_ACM endchoice +DT_COMPAT_SIM_FLASH:= zephyr,sim-flash +DT_SIM_FLASH_PATH := $(dt_nodelabel_path,flash_sim0) + config MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD bool "Allow to select image number for DFU" - depends on !SINGLE_APPLICATION_SLOT + # Allow this option to be selected in cases where support for direct uploading to nRF5340 + # network core should be supported + depends on !SINGLE_APPLICATION_SLOT || (SINGLE_APPLICATION_SLOT && SOC_NRF5340_CPUAPP && BOOT_IMAGE_ACCESS_HOOK_NRF5340 && FLASH_SIMULATOR && $(dt_compat_enabled,$(DT_COMPAT_SIM_FLASH))) help With the option enabled, the mcuboot serial recovery will respect the "image" field in mcumgr image update frame From 9e2bba9806b33af0d52e1f62774de55a48d2538d Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 5 Dec 2024 10:20:19 +0000 Subject: [PATCH 064/125] [nrf noup] boot: Remove child/parent references Removes stray child/parent references Signed-off-by: Jamie McCrae (cherry picked from commit 1e18f3cab16e601542e8ce7f620670d92db6e173) --- 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 60dcc0d468fde468f36637a5603204a8ea972b9b Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 15 Jan 2025 15:09:55 +0000 Subject: [PATCH 065/125] [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 8a3f50821649cc71ac4cd68103eefb0ca7faa463) --- 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 fd3ccd378677d6cd27df57dcb774698fa5adbdd9 Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk Date: Fri, 24 Jan 2025 08:59:31 +0100 Subject: [PATCH 066/125] [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 2c73cb431579f6039cd18121d62e057a2ccc817f) --- 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 1f1b7be6c9500a53f9e55fe30a6b22898d5d478f Mon Sep 17 00:00:00 2001 From: Sigurd Hellesvik Date: Thu, 6 Feb 2025 08:47:39 +0100 Subject: [PATCH 067/125] [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 7911236b6da3cf291d98c40e87851d6666541027) --- 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 f471000c9946cbd678b25ce9b63427550d525450 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 4 Mar 2025 17:31:33 +0000 Subject: [PATCH 068/125] [nrf noup] zephyr: sdk-nrf specific overrides on PSA Kconfigs Select proper configuration and disable mbedTLS selection, as we are using NRF Security enabled Oberon. Signed-off-by: Dominik Ermel Signed-off-by: Artur Hadasz (cherry picked from commit 558d1c1dd10eecad9120582d63c79299698d180b) --- boot/bootutil/zephyr/CMakeLists.txt | 2 +- boot/zephyr/Kconfig | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/boot/bootutil/zephyr/CMakeLists.txt b/boot/bootutil/zephyr/CMakeLists.txt index f6d37441c..44f78f395 100644 --- a/boot/bootutil/zephyr/CMakeLists.txt +++ b/boot/bootutil/zephyr/CMakeLists.txt @@ -40,7 +40,7 @@ if(CONFIG_BOOT_USE_PSA_CRYPTO) ) endif() -if(CONFIG_BOOT_USE_MBEDTLS OR CONFIG_BOOT_USE_PSA_CRYPTO) +if(CONFIG_BOOT_USE_MBEDTLS OR CONFIG_BOOT_USE_PSA_CRYPTO AND NOT CONFIG_NRF_SECURITY) zephyr_link_libraries(mbedTLS) endif() endif() diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index e482d9fab..3d729d663 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -88,8 +88,7 @@ config BOOT_PSA_IMG_HASH_ALG_SHA512_DEPENDENCIES config BOOT_ED25519_PSA_DEPENDENCIES bool select PSA_WANT_ALG_PURE_EDDSA - # Seems that upstream mbedTLS does not have TE - #select PSA_WANT_ECC_TWISTED_EDWARDS_255 + select PSA_WANT_ECC_TWISTED_EDWARDS_255 select PSA_WANT_ECC_MONTGOMERY_255 select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT help @@ -119,7 +118,7 @@ endif # BOOT_ENCRYPT_IMAGE config BOOT_ECDSA_PSA_DEPENDENCIES bool select PSA_WANT_ALG_ECDSA - select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT + select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT if !PSA_CORE_LITE select PSA_WANT_ECC_SECP_R1_256 help Dependencies for ECDSA signature @@ -248,7 +247,8 @@ choice BOOT_SIGNATURE_TYPE config BOOT_SIGNATURE_TYPE_NONE bool "No signature; use only hash check" - select BOOT_USE_TINYCRYPT + select BOOT_USE_TINYCRYPT if !SOC_SERIES_NRF54LX + select BOOT_USE_PSA_CRYPTO if SOC_SERIES_NRF54LX select BOOT_IMG_HASH_ALG_SHA256_ALLOW config BOOT_SIGNATURE_TYPE_RSA @@ -280,6 +280,7 @@ config BOOT_SIGNATURE_TYPE_ECDSA_P256 if BOOT_SIGNATURE_TYPE_ECDSA_P256 choice BOOT_ECDSA_IMPLEMENTATION prompt "Ecdsa implementation" + default BOOT_ECDSA_PSA if NRF_SECURITY default BOOT_ECDSA_TINYCRYPT config BOOT_ECDSA_TINYCRYPT @@ -296,11 +297,12 @@ config BOOT_ECDSA_CC310 config BOOT_ECDSA_PSA bool "Use psa cryptoo" + depends on NRF_SECURITY select BOOT_USE_PSA_CRYPTO select PSA_CRYPTO_CLIENT select PSA_CRYPTO_C - select BOOT_IMG_HASH_ALG_SHA256_ALLOW - select BOOT_IMG_HASH_ALG_SHA512_ALLOW + select BOOT_IMG_HASH_ALG_SHA256_ALLOW if !PSA_CORE_LITE + select BOOT_IMG_HASH_ALG_SHA512_ALLOW if !PSA_CORE_LITE select BOOT_ECDSA_PSA_DEPENDENCIES endchoice # Ecdsa implementation @@ -332,6 +334,7 @@ config BOOT_SIGNATURE_TYPE_PURE choice BOOT_ED25519_IMPLEMENTATION prompt "Ecdsa implementation" + default BOOT_ED25519_PSA if NRF_SECURITY default BOOT_ED25519_TINYCRYPT config BOOT_ED25519_TINYCRYPT @@ -352,7 +355,7 @@ config BOOT_ED25519_MBEDTLS config BOOT_ED25519_PSA bool "Use PSA crypto" - select MBEDTLS + depends on NRF_SECURITY select BOOT_USE_PSA_CRYPTO select PSA_CRYPTO_CLIENT select PSA_CRYPTO_C @@ -429,6 +432,7 @@ config MBEDTLS_CFG_FILE # is used, but the fact is that Mbed TLS' ASN1 parse module is used # also when TinyCrypt is used as crypto backend. default "mcuboot-mbedtls-cfg.h" if BOOT_USE_TINYCRYPT + default "config-tls-generic.h" if NRF_SECURITY && (MBEDTLS_BUILTIN || BOOT_USE_PSA_CRYPTO) default "mcuboot-mbedtls-cfg.h" if BOOT_USE_MBEDTLS && !MBEDTLS_BUILTIN config BOOT_HW_KEY From 791dd599386c95e464c6958927fb98a88dd61e3e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 11 Jul 2023 08:42:49 +0100 Subject: [PATCH 069/125] [nrf noup] zephyr: Fix path variables Fixes path variables to use the proper Zephyr module variables Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 63224e31afcd983f3d435f259372a6a3d853a46c) --- boot/zephyr/CMakeLists.txt | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 0bd0fb919..e2c981aae 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -35,21 +35,20 @@ if(NOT CONFIG_MBEDTLS_BUILTIN AND NOT CONFIG_BOOT_KEY_IMPORT_BYPASS_ASN) set(MBEDTLS_ASN1_DIR "${MCUBOOT_DIR}/ext/mbedtls-asn1") assert_exists(MBEDTLS_ASN1_DIR) endif() -set(NRF_DIR "${MCUBOOT_DIR}/ext/nrf") +set(MCUBOOT_NRF_EXT_DIR "${MCUBOOT_DIR}/ext/nrf") if(CONFIG_BOOT_USE_NRF_CC310_BL) -set(NRFXLIB_DIR ${ZEPHYR_BASE}/../nrfxlib) -if(NOT EXISTS ${NRFXLIB_DIR}) - message(FATAL_ERROR " + if(NOT EXISTS ${ZEPHYR_NRFXLIB_MODULE_DIR}) + message(FATAL_ERROR " ------------------------------------------------------------------------ - No such file or directory: ${NRFXLIB_DIR} + No such file or directory: ${ZEPHYR_NRFXLIB_MODULE_DIR} The current configuration enables nRF CC310 crypto accelerator hardware with the `CONFIG_BOOT_USE_NRF_CC310_BL` option. Please follow `ext/nrf/README.md` guide to fix your setup or use tinycrypt instead of the HW accelerator. To use the tinycrypt set `CONFIG_BOOT_ECDSA_TINYCRYPT` to y. ------------------------------------------------------------------------") -endif() + endif() endif() zephyr_library_include_directories( @@ -218,8 +217,8 @@ if(CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256 OR CONFIG_BOOT_ENCRYPT_EC256) ${TINYCRYPT_DIR}/source/utils.c ) elseif(CONFIG_BOOT_USE_NRF_CC310_BL) - zephyr_library_sources(${NRF_DIR}/cc310_glue.c) - zephyr_library_include_directories(${NRF_DIR}) + zephyr_library_sources(${MCUBOOT_NRF_EXT_DIR}/cc310_glue.c) + zephyr_library_include_directories(${MCUBOOT_NRF_EXT_DIR}) zephyr_link_libraries(nrfxlib_crypto) elseif(CONFIG_BOOT_USE_NRF_EXTERNAL_CRYPTO) zephyr_include_directories(${BL_CRYPTO_DIR}/../include) From 7f674d9817e30c458a33af49211a34f21bb023da Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 14 Mar 2025 17:51:23 +0000 Subject: [PATCH 070/125] [nrf noup] zephyr: Use mbedTLS specific C functions with RSA Use snprinf, alloc, calloc and free from mbedTLS rather than from Zephyr. Signed-off-by: Dominik Ermel (cherry picked from commit 7ff9d37234f071e8ee0442b03df8f45058e2c39f) --- boot/zephyr/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 3d729d663..5aee4f1eb 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -261,6 +261,8 @@ config BOOT_SIGNATURE_TYPE_RSA select MBEDTLS_PKCS1_V15 if MBEDTLS_BUILTIN select MBEDTLS_PKCS1_V21 if MBEDTLS_BUILTIN select MBEDTLS_KEY_EXCHANGE_RSA_ENABLED if MBEDTLS_BUILTIN + select MBEDTLS_PLATFORM_NO_STD_FUNCTIONS if MBEDTLS_BUILTIN + select MBEDTLS_PLATFORM_SNPRINTF_ALT if MBEDTLS_BUILTIN select BOOT_ENCRYPTION_SUPPORT select BOOT_IMG_HASH_ALG_SHA256_ALLOW select BOOT_AES_MBEDTLS_DEPENDENCIES if MBEDTLS_BUILTIN && BOOT_ENCRYPT_IMAGE From c872f6ab7bd026fe779543f24ede6d2b343202f3 Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Mon, 10 Mar 2025 17:23:37 +0100 Subject: [PATCH 071/125] [nrf noup] boot/zephyr: nrf54h20dk board support Added basic support for nrf54h20dk_nrf54h20_cpuapp_iron board. This commit turns off CONFIG_FPROTECT for this board build. Signed-off-by: Michal Kozikowski (cherry picked from commit b404bb106afc4705ffe9b92a63196f8881500195) --- boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf b/boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf index 12c96ff0f..31666d9fe 100644 --- a/boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf +++ b/boot/zephyr/boards/nrf54h20dk_nrf54h20_cpuapp_iron.conf @@ -6,4 +6,7 @@ # Ensure that the SPI NOR driver is disabled by default CONFIG_SPI_NOR=n +# TODO: below are not yet supported and need fixing +CONFIG_FPROTECT=n + CONFIG_BOOT_WATCHDOG_FEED=n From 31766fcae89baee588d1ac49802ce5b1fd7b544d Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Fri, 28 Mar 2025 17:46:28 +0100 Subject: [PATCH 072/125] [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 ea5b6b6e8bda2c3570e509c18e18642c7d69c95a) --- 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 051705ec9..72c601db3 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,7 +113,10 @@ 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 fac7ac4990fe9f28348bfb3e0e52ac4bf51c757a Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Tue, 5 Mar 2024 18:44:13 +0100 Subject: [PATCH 073/125] [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 1f19003bc37950ba4c42673beb98b514da974829) --- 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 72c601db3..1252334ca 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[i]); + } + } + #if defined(NRF_DPPIC) /* Clear all SUBSCRIBE configurations. */ memset((uint8_t *)current + NRF_UARTE_SUBSCRIBE_CONF_OFFS, 0, From c6e2585f8e382a3bc6f1700d892d3636a3155af5 Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Tue, 1 Apr 2025 19:30:57 +0200 Subject: [PATCH 074/125] [nrf noup] boot/zephyr/Kconfig: fix MBEDTLS_CFG_FILE value Zephyr provides "mcuboot-mbedtls-cfg.h" as glue interface for configure mbedts. "config-tls-generic.h" default value was erroneously introduced during a meta codebase synchronization. Signed-off-by: Andrzej Puzdrowski (cherry picked from commit a5b259409ac74ed94b5bf304a4e9d756b465997f) --- boot/zephyr/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 5aee4f1eb..1c71f33eb 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -434,7 +434,6 @@ config MBEDTLS_CFG_FILE # is used, but the fact is that Mbed TLS' ASN1 parse module is used # also when TinyCrypt is used as crypto backend. default "mcuboot-mbedtls-cfg.h" if BOOT_USE_TINYCRYPT - default "config-tls-generic.h" if NRF_SECURITY && (MBEDTLS_BUILTIN || BOOT_USE_PSA_CRYPTO) default "mcuboot-mbedtls-cfg.h" if BOOT_USE_MBEDTLS && !MBEDTLS_BUILTIN config BOOT_HW_KEY From 5f6e119a726d9f17b3f65139540db838f2286bde Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Fri, 11 Apr 2025 12:55:00 +0200 Subject: [PATCH 075/125] [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 5717af4899216809cc1a9b84454c38179920246a) --- 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 1252334ca..f90a46af1 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[i]); } } +#endif #if defined(NRF_DPPIC) /* Clear all SUBSCRIBE configurations. */ From 1aa8af0eae8d67f21cdccd81588f37cebde536c8 Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Wed, 23 Apr 2025 09:05:24 +0200 Subject: [PATCH 076/125] [nrf noup] boot: zephyr: boards: nrf54lm20pdk adding default configs. Signed-off-by: Mateusz Michalek (cherry picked from commit cc3d19b82c584e9759ba0cbc022a0d80747117ca) --- .../boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 boot/zephyr/boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf diff --git a/boot/zephyr/boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf b/boot/zephyr/boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf new file mode 100644 index 000000000..4944f7b13 --- /dev/null +++ b/boot/zephyr/boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf @@ -0,0 +1,16 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_BOOT_MAX_IMG_SECTORS=256 + +# Ensure that the SPI NOR driver is disabled by default +CONFIG_SPI_NOR=n + +# TODO: below are not yet supported and need fixing +CONFIG_FPROTECT=n + +CONFIG_BOOT_WATCHDOG_FEED=n + +CONFIG_PSA_CRYPTO_DRIVER_CRACEN=n +CONFIG_PSA_CRYPTO_DRIVER_OBERON=y From b6c992e20c51fd77c1761450aaae118fee3f097d Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Mon, 28 Apr 2025 14:17:35 +0200 Subject: [PATCH 077/125] [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 df61bd1f2181a7ccc7f908afbd8cd26f6858edfc) --- boot/zephyr/nrf_cleanup.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index f90a46af1..39dfcbc41 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,13 @@ 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) @@ -62,10 +72,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 +97,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 +154,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 898b9bcb12baf499860ed7eb5d4754f1bbaa4284 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 22 Aug 2024 14:17:46 +0100 Subject: [PATCH 078/125] [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 (cherry picked from commit c3ba62823648cd9ce3d933bcdeb08fc791033838) --- 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, 1929 insertions(+), 24 deletions(-) create mode 100644 boot/zephyr/decompression.c create 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 a88ad0dad..96be26692 100644 --- a/boot/bootutil/src/bootutil_misc.c +++ b/boot/bootutil/src/bootutil_misc.c @@ -47,6 +47,11 @@ #include "swap_priv.h" #endif +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include +#endif + BOOT_LOG_MODULE_DECLARE(mcuboot); /* Currently only used by imgmgr */ @@ -482,35 +487,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); + + 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); - 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 += 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 ade67cc4b..0875fd47b 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -45,6 +45,11 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include +#endif + #ifdef MCUBOOT_ENC_IMAGES #include "bootutil/enc_key.h" #endif @@ -507,7 +512,7 @@ bootutil_img_validate(struct boot_loader_state *state, #endif ) { -#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) +#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) || defined(MCUBOOT_DECOMPRESS_IMAGES) int image_index = (state == NULL ? 0 : BOOT_CURR_IMG(state)); #endif uint32_t off; @@ -552,6 +557,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) #if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_SERIAL_RECOVERY) @@ -800,6 +866,161 @@ bootutil_img_validate(struct boot_loader_state *state, skip_security_counter_check: #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 dd4853874..c074a00db 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -50,6 +50,11 @@ #include "bootutil/boot_hooks.h" #include "bootutil/mcuboot_status.h" +#if defined(MCUBOOT_DECOMPRESS_IMAGES) +#include +#include +#endif + #ifdef __ZEPHYR__ #include #endif @@ -1012,10 +1017,10 @@ boot_is_header_valid(const struct image_header *hdr, const struct flash_area *fa 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 @@ -1263,6 +1268,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_PRIMARY_SLOT) ? "primary" : "secondary"); @@ -1919,6 +1925,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))); @@ -1944,6 +1953,16 @@ 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 e2c981aae..957c6c50a 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -317,6 +317,12 @@ if(CONFIG_BOOT_ENCRYPT_EC256) ) 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 1c71f33eb..e36fdd8e9 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1101,6 +1101,9 @@ config BOOT_BANNER_STRING 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. @@ -1108,6 +1111,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 @@ -1116,9 +1121,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..87e3d3763 --- /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_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 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 0ae144127f7d9cfca4907e5cec167c8d6643bf28 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 7 Nov 2024 10:53:06 +0000 Subject: [PATCH 079/125] [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 8cd14c1e992dc8af95c29a29baa837ef1f60df12) --- boot/zephyr/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index e36fdd8e9..12fd9c5e4 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1110,9 +1110,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 002515b349bd8cd4e190af2807c50e88ef8605fd Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Tue, 13 May 2025 13:33:22 +0200 Subject: [PATCH 080/125] [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 aa59badf3d04a18f35ad2b0e0ff2ad6ff15b5b7e) --- 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 87e3d3763..ce4fe0b2b 100644 --- a/boot/zephyr/decompression.c +++ b/boot/zephyr/decompression.c @@ -256,15 +256,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)); @@ -276,12 +267,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 */ @@ -1101,7 +1108,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)) { @@ -1124,7 +1131,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); @@ -1135,16 +1142,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); @@ -1158,12 +1156,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 9200785d3284a15f6a469a86efb79d95b68cce1c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 12 Jun 2025 08:38:15 +0100 Subject: [PATCH 081/125] [nrf noup] boot: zephyr: Add bm firmware loader code Adds firmware loader code for use in baremetal mode Signed-off-by: Jamie McCrae (cherry picked from commit f123819a1d3322fa230f7cacd6d8f1672d8651e7) --- boot/zephyr/CMakeLists.txt | 19 ++- boot/zephyr/firmware_loader_bm.c | 283 +++++++++++++++++++++++++++++++ boot/zephyr/io_bm.c | 198 +++++++++++++++++++++ 3 files changed, 496 insertions(+), 4 deletions(-) create mode 100644 boot/zephyr/firmware_loader_bm.c create mode 100644 boot/zephyr/io_bm.c diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 957c6c50a..54deaf93b 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -64,12 +64,17 @@ endif() # Zephyr port-specific sources. zephyr_library_sources( main.c - io.c flash_map_extended.c os.c keys.c ) +if(CONFIG_NCS_BM) + zephyr_library_sources(io_bm.c) +else() + zephyr_library_sources(io.c) +endif() + if(DEFINED CONFIG_ENABLE_MGMT_PERUSER) zephyr_library_sources( boot_serial_extensions.c @@ -150,9 +155,15 @@ elseif(CONFIG_SINGLE_APPLICATION_SLOT) ) zephyr_library_include_directories(${BOOT_DIR}/bootutil/src) elseif(CONFIG_BOOT_FIRMWARE_LOADER) - zephyr_library_sources( - ${BOOT_DIR}/zephyr/firmware_loader.c - ) + if(CONFIG_NCS_BM) + zephyr_library_sources( + ${BOOT_DIR}/zephyr/firmware_loader_bm.c + ) + else() + zephyr_library_sources( + ${BOOT_DIR}/zephyr/firmware_loader.c + ) + endif() zephyr_library_include_directories(${BOOT_DIR}/bootutil/src) else() zephyr_library_sources( diff --git a/boot/zephyr/firmware_loader_bm.c b/boot/zephyr/firmware_loader_bm.c new file mode 100644 index 000000000..14d5c96bd --- /dev/null +++ b/boot/zephyr/firmware_loader_bm.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "bootutil/image.h" +#include "bootutil_priv.h" +#include "bootutil/bootutil_log.h" +#include "bootutil/bootutil_public.h" +#include "bootutil/fault_injection_hardening.h" +#include + +#include "io/io.h" +#include "mcuboot_config/mcuboot_config.h" + +#define IMAGE_TLV_INSTALLER_IMAGE 0xa0 + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +static struct flash_area fa_app_installer = { + .fa_id = 1, + .fa_off = FIXED_PARTITION_OFFSET(slot0_partition), + .fa_size = FIXED_PARTITION_SIZE(slot0_partition), + .fa_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)), +}; + +static struct image_header hdr_app_installer = { 0 }; + +static struct flash_area fa_softdevice = { + .fa_id = 2, + .fa_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)), +}; + +static struct image_header hdr_softdevice = { 0 }; + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER +static struct flash_area fa_firmware_loader = { + .fa_id = 3, + .fa_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)), +}; + +static struct image_header hdr_firmware_loader = { 0 }; +#endif + +/** + * Validate hash of a primary boot image. + * + * @param[in] fa_p flash area pointer + * @param[in] hdr boot image header pointer + * + * @return FIH_SUCCESS on success, error code otherwise + */ +static fih_ret validate_image(const struct flash_area *fap, struct image_header *hdr) +{ + static uint8_t tmpbuf[BOOT_TMPBUF_SZ]; + FIH_DECLARE(fih_rc, FIH_FAILURE); + + FIH_CALL(bootutil_img_validate, fih_rc, NULL, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, NULL, 0, NULL); + FIH_RET(fih_rc); +} + +/** + * Gather information on image and prepare for booting. Will boot from main + * image if none of the enabled entrance modes for the firmware loader are set, + * otherwise will boot the firmware loader. Note: firmware loader must be a + * valid signed image with the same signing key as the application image. + * + * @param[out] rsp Parameters for booting image, on success + * + * @return FIH_SUCCESS on success; non-zero on failure. + */ +fih_ret +boot_go(struct boot_rsp *rsp) +{ + bool boot_firmware_loader = false; + FIH_DECLARE(fih_rc, FIH_FAILURE); + bool softdevice_area_valid = false; + bool firmware_loader_area_valid = false; + int rc; + bool app_installer_image_valid = false; + bool softdevice_image_valid = false; + bool firmware_loader_image_valid = false; + bool app_installer_is_installer_image = false; + + bm_installs_init(); + + if (bm_installs_is_valid()) { + off_t start_address = 0; + size_t image_size = 0; + + rc = bm_installs_get_image_data(BM_INSTALLS_IMAGE_INDEX_SOFTDEVICE, &start_address, + &image_size); + + if (!rc) { + fa_softdevice.fa_off = start_address; + fa_softdevice.fa_size = image_size; + + if (start_address < fa_app_installer.fa_off) { + /* Invalid start address for SoftDevice */ + goto invalid_softdevice; + } + + fa_app_installer.fa_size = start_address - fa_app_installer.fa_off; + + rc = boot_image_load_header(&fa_softdevice, &hdr_softdevice); + + if (!rc) { + softdevice_area_valid = true; + } + } + +invalid_softdevice: +#ifdef CONFIG_BOOT_FIRMWARE_LOADER + start_address = 0; + image_size = 0; + rc = bm_installs_get_image_data(BM_INSTALLS_IMAGE_INDEX_FIRMWARE_LOADER, &start_address, + &image_size); + + if (!rc) { + fa_firmware_loader.fa_off = start_address; + fa_firmware_loader.fa_size = image_size; + + if (start_address < fa_app_installer.fa_off) { + /* Invalid start address for firmware loader */ + goto invalid_firmware_loader; + } + + fa_app_installer.fa_size = start_address - fa_app_installer.fa_off; + + rc = boot_image_load_header(&fa_firmware_loader, &hdr_softdevice); + + if (!rc) { + firmware_loader_area_valid = true; + } + } +#endif + } + +invalid_firmware_loader: + rc = boot_image_load_header(&fa_app_installer, &hdr_app_installer); + + if (rc) { + BOOT_LOG_ERR("Failed loading application/installer image header: %d", rc); + } else { + FIH_CALL(validate_image, fih_rc, &fa_app_installer, &hdr_app_installer); + + if (FIH_EQ(fih_rc, FIH_SUCCESS)) { + struct image_tlv_iter it; + uint32_t off2; + uint16_t len2; + + app_installer_image_valid = true; + + if (hdr_app_installer.ih_protect_tlv_size > 0) { + rc = bootutil_tlv_iter_begin(&it, &hdr_app_installer, &fa_app_installer, + IMAGE_TLV_INSTALLER_IMAGE, true); + + if (rc == 0) { + rc = bootutil_tlv_iter_next(&it, &off2, &len2, NULL); + + if (rc == 0 && len2 == sizeof(app_installer_is_installer_image)) { + rc = LOAD_IMAGE_DATA(&hdr_app_installer, &fa_app_installer, off2, + &app_installer_is_installer_image, len2); + + if (rc != 0) { + app_installer_is_installer_image = false; + } + } + } + } + } + } + + if (softdevice_area_valid) { + fih_rc = FIH_FAILURE; + rc = boot_image_load_header(&fa_softdevice, &hdr_softdevice); + + if (rc) { + BOOT_LOG_ERR("Failed loading SoftDevice image header: %d", rc); + } else { + FIH_CALL(validate_image, fih_rc, &fa_softdevice, &hdr_softdevice); + + if (FIH_EQ(fih_rc, FIH_SUCCESS)) { + softdevice_image_valid = true; + } + } + } + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER + if (firmware_loader_area_valid) { + fih_rc = FIH_FAILURE; + rc = boot_image_load_header(&fa_firmware_loader, &hdr_firmware_loader); + + if (rc) { + BOOT_LOG_ERR("Failed loading firmware loader image header: %d", rc); + } else { + FIH_CALL(validate_image, fih_rc, &fa_firmware_loader, &hdr_firmware_loader); + + if (FIH_EQ(fih_rc, FIH_SUCCESS)) { + firmware_loader_image_valid = true; + } + } + } +#endif + + BOOT_LOG_DBG("Application/installer partition offset: 0x%lx, size: 0x%x, type: %d", + fa_app_installer.fa_off, fa_app_installer.fa_size, + app_installer_is_installer_image); + BOOT_LOG_DBG("SoftDevice partition offset: 0x%lx, size: 0x%x", fa_softdevice.fa_off, + fa_softdevice.fa_size); +#ifdef CONFIG_BOOT_FIRMWARE_LOADER + BOOT_LOG_DBG("Firmware loader off: 0x%lx, size: 0x%x", fa_firmware_loader.fa_off, + fa_firmware_loader.fa_size); + BOOT_LOG_DBG("SoftDevice area valid: %d, Firmware loader area valid: %d, " + "Application/installer image valid: %d, SoftDevice image valid: %d, " + "Firmware loader image valid: %d", softdevice_area_valid, + firmware_loader_area_valid, app_installer_image_valid, softdevice_image_valid, + firmware_loader_image_valid); +#else + BOOT_LOG_DBG("SoftDevice area valid: %d, Application/installer image valid: %d, " + "SoftDevice image valid: %d", softdevice_area_valid, app_installer_image_valid, + softdevice_image_valid); +#endif + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO + if (io_detect_pin() && !io_boot_skip_serial_recovery()) { + BOOT_LOG_DBG("GPIO detected for firmware loader mode"); + boot_firmware_loader = true; + } +#endif + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET + if (io_detect_pin_reset()) { + BOOT_LOG_DBG("Pin reset detected for firmware loader mode"); + boot_firmware_loader = true; + } +#endif + +#ifdef CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE + if (io_detect_boot_mode()) { + BOOT_LOG_DBG("Boot mode detected for firmware loader mode"); + boot_firmware_loader = true; + } +#endif + + if (app_installer_image_valid == true && app_installer_is_installer_image == true) { + /* Installer image is present, this gets priority */ + BOOT_LOG_DBG("Booting installer"); + rsp->br_image_off = flash_area_get_off(&fa_app_installer); + rsp->br_hdr = &hdr_app_installer; + } else if (boot_firmware_loader == true && softdevice_image_valid == true && + firmware_loader_image_valid == true) { + /* Boot firmware loader */ + BOOT_LOG_INF("Booting firmware loader"); + rsp->br_image_off = flash_area_get_off(&fa_firmware_loader); + rsp->br_hdr = &hdr_firmware_loader; + } else if (app_installer_image_valid == true && softdevice_image_valid == true) { + /* Boot main application */ + BOOT_LOG_INF("Booting main application"); + rsp->br_image_off = flash_area_get_off(&fa_app_installer); + rsp->br_hdr = &hdr_app_installer; + } else if (app_installer_image_valid == false && softdevice_image_valid == true && + firmware_loader_image_valid == true) { + /* Boot firmware loader due to missing main image */ + BOOT_LOG_INF("Booting firmware loader due to missing application image"); + rsp->br_image_off = flash_area_get_off(&fa_firmware_loader); + rsp->br_hdr = &hdr_firmware_loader; + } else { + /* Cannot boot in this configuration */ + BOOT_LOG_ERR("Error: no bootable configuration found"); + return -1; + } + + rsp->br_flash_dev_id = flash_area_get_device_id(&fa_app_installer); + + return 0; +} diff --git a/boot/zephyr/io_bm.c b/boot/zephyr/io_bm.c new file mode 100644 index 000000000..3f65a5d0e --- /dev/null +++ b/boot/zephyr/io_bm.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2012-2014 Wind River Systems, Inc. + * Copyright (c) 2020 Arm Limited + * Copyright (c) 2021-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. + * 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 +#include +#include + +#include "target.h" +#include "bootutil/bootutil_log.h" + +#include +#include + +#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) || defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) +#include +#endif + +#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) || defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) +#include +#endif + +/* Validate serial recovery configuration */ +#ifdef CONFIG_MCUBOOT_SERIAL +#if !defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) && \ + !defined(CONFIG_BOOT_SERIAL_WAIT_FOR_DFU) && \ + !defined(CONFIG_BOOT_SERIAL_BOOT_MODE) && \ + !defined(CONFIG_BOOT_SERIAL_NO_APPLICATION) && \ + !defined(CONFIG_BOOT_SERIAL_PIN_RESET) +#error "Serial recovery selected without an entrance mode set" +#endif +#endif + +/* Validate firmware loader configuration */ +#ifdef CONFIG_BOOT_FIRMWARE_LOADER +#if !defined(CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO) && \ + !defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) && \ + !defined(CONFIG_BOOT_FIRMWARE_LOADER_NO_APPLICATION) && \ + !defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) +#error "Firmware loader selected without an entrance mode set" +#endif +#endif + +BOOT_LOG_MODULE_DECLARE(mcuboot); + +#ifdef CONFIG_MCUBOOT_INDICATION_LED + +void io_led_init(void) +{ + nrf_gpio_cfg_output(BOARD_PIN_LED_0); + nrf_gpio_pin_write(BOARD_PIN_LED_0, BOARD_LED_ACTIVE_STATE); +} + +void io_led_set(int value) +{ + nrf_gpio_pin_write(BOARD_PIN_LED_0, (value == 0 ? !BOARD_LED_ACTIVE_STATE : BOARD_LED_ACTIVE_STATE)); +} +#endif /* CONFIG_MCUBOOT_INDICATION_LED */ + +#if defined(CONFIG_BOOT_SERIAL_ENTRANCE_GPIO) || defined(CONFIG_BOOT_USB_DFU_GPIO) || \ + defined(CONFIG_BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO) + +#if defined(CONFIG_MCUBOOT_SERIAL) +#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_SERIAL_DETECT_DELAY +#elif defined(CONFIG_BOOT_FIRMWARE_LOADER) +#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_FIRMWARE_LOADER_DETECT_DELAY +#else +#define BUTTON_0_DETECT_DELAY CONFIG_BOOT_USB_DFU_DETECT_DELAY +#endif + +bool io_detect_pin(void) +{ + int rc; + bool pin_active; + + rc = bm_buttons_init( + &(struct bm_buttons_config){ + .pin_number = BOARD_PIN_BTN_0, + .active_state = BM_BUTTONS_ACTIVE_LOW, + .pull_config = BM_BUTTONS_PIN_PULLUP, + }, + 1, + BM_BUTTONS_DETECTION_DELAY_MIN_US); + if (rc) { + BOOT_LOG_ERR("Failed to initialize buttons: %d", rc); + return false; + } + + rc = bm_buttons_enable(); + if (rc) { + BOOT_LOG_ERR("Failed to enable button detection: %d", rc); + return false; + } + + pin_active = bm_buttons_is_pressed(BOARD_PIN_BTN_0); + + if (pin_active) { + if (BUTTON_0_DETECT_DELAY > 0) { +#ifdef CONFIG_MULTITHREADING + k_sleep(K_MSEC(50)); +#else + k_busy_wait(50000); +#endif + + /* Get the uptime for debounce purposes. */ + int64_t timestamp = k_uptime_get(); + + for(;;) { + pin_active = bm_buttons_is_pressed(BOARD_PIN_BTN_0); + + /* Get delta from when this started */ + uint32_t delta = k_uptime_get() - timestamp; + + /* If not pressed OR if pressed > debounce period, stop. */ + if (delta >= BUTTON_0_DETECT_DELAY || !pin_active) { + break; + } + + /* Delay 1 ms */ +#ifdef CONFIG_MULTITHREADING + k_sleep(K_MSEC(1)); +#else + k_busy_wait(1000); +#endif + } + } + } + + rc = bm_buttons_disable(); + + if (rc) { + BOOT_LOG_ERR("Failed to disable buttons: %d", rc); + } + + rc = bm_buttons_deinit(); + if (rc) { + BOOT_LOG_ERR("Failed to de-initialize buttons: %d", rc); + } + + return (bool)pin_active; +} +#endif + +#if defined(CONFIG_BOOT_SERIAL_PIN_RESET) || defined(CONFIG_BOOT_FIRMWARE_LOADER_PIN_RESET) +bool io_detect_pin_reset(void) +{ + uint32_t reset_cause; + int rc; + + rc = hwinfo_get_reset_cause(&reset_cause); + + if (rc == 0 && (reset_cause & RESET_PIN)) { + (void)hwinfo_clear_reset_cause(); + return true; + } + + return false; +} +#endif + +#if defined(CONFIG_BOOT_SERIAL_BOOT_MODE) || defined(CONFIG_BOOT_FIRMWARE_LOADER_BOOT_MODE) +bool io_detect_boot_mode(void) +{ + int32_t boot_mode; + + boot_mode = bootmode_check(BOOT_MODE_TYPE_BOOTLOADER); + + if (boot_mode == 1) { + /* Boot mode to stay in bootloader, clear status and enter serial + * recovery mode + */ + bootmode_clear(); + + return true; + } + + return false; +} +#endif From 068718ae281e70cc5c771d51320f1f8707d8ea59 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Thu, 3 Jul 2025 12:52:05 +0200 Subject: [PATCH 082/125] [nrf noup] boot: Provide default configuration for nRF54H20 Enable ed25519 signature as well as direct hashing while building for nRF54H20DK. Ref: NCSDK-34304 Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 29bcb744c54f93bc363b47e498afd31bbbdf2f6e) --- boot/zephyr/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 12fd9c5e4..de31262a4 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -185,6 +185,7 @@ config BOOT_IMG_HASH_ALG_SHA512_ALLOW config BOOT_IMG_HASH_DIRECTLY_ON_STORAGE bool "Hash calculation functions access storage through address space" + default y if NRF_SECURITY && SOC_NRF54H20 depends on !BOOT_ENCRYPT_IMAGE help When possible to map storage device, at least for read operations, @@ -242,7 +243,7 @@ config BOOT_SIGNATURE_TYPE_PURE_ALLOW choice BOOT_SIGNATURE_TYPE prompt "Signature type" - default BOOT_SIGNATURE_TYPE_ED25519 if SOC_NRF54L15_CPUAPP + default BOOT_SIGNATURE_TYPE_ED25519 if SOC_NRF54L15_CPUAPP || SOC_NRF54H20_CPUAPP default BOOT_SIGNATURE_TYPE_RSA config BOOT_SIGNATURE_TYPE_NONE From a9e70e43fa548c86bec946dc06210b8a2ba2b860 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 083/125] [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ł (cherry picked from commit 25346815646625708b3269c46fe45089885da551) --- boot/bootutil/src/loader.c | 39 ++++++++++++++++++++++++++++++++++---- boot/zephyr/Kconfig | 17 +++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index c074a00db..5adbfcca0 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -57,6 +57,9 @@ #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) @@ -909,14 +912,42 @@ 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 */ + #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); + 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); + 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 de31262a4..6bb236969 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1251,4 +1251,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 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 26192ca1c9986dd9f50b9e5537bfc38fd2953128 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 20 Sep 2024 16:34:00 +0000 Subject: [PATCH 084/125] [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 e28f5e98cf92b174412bf18dd633d035c84da5ac) --- boot/bootutil/src/ed25519_psa.c | 51 ++++++++++++++++++++++++++++++ boot/bootutil/src/image_ed25519.c | 9 +++++- boot/bootutil/src/image_validate.c | 12 +++++-- boot/zephyr/CMakeLists.txt | 2 +- boot/zephyr/Kconfig | 26 +++++++++++++++ 5 files changed, 96 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 0875fd47b..96c1853dd 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -292,6 +292,7 @@ bootutil_img_hash(struct boot_loader_state *state, # 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) @@ -360,6 +361,7 @@ bootutil_find_key(uint8_t image_index, uint8_t *key, uint16_t key_len) } #endif /* !MCUBOOT_HW_KEY */ #endif /* !MCUBOOT_BUILTIN_KEY */ +#endif /* !defined(CONFIG_BOOT_SIGNATURE_USING_KMU) */ #endif /* EXPECTED_SIG_TLV */ /** @@ -729,6 +731,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: { @@ -760,15 +763,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; @@ -925,7 +931,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; @@ -971,7 +977,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) { @@ -994,10 +1000,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 54deaf93b..ecb4ac704 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -355,7 +355,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 6bb236969..cddb1f9c3 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -384,6 +384,22 @@ endif endchoice +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 @@ -401,6 +417,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 @@ -430,6 +448,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 373038be7dde47f025974e6591e91d0dad8ab355 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 2 Dec 2024 10:51:41 +0000 Subject: [PATCH 085/125] [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 e211d928110ca431a29613e2eb0def155e079ea5) --- 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 cddb1f9c3..606d82ed4 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -398,6 +398,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 9dacf6dbff98acc4eb93312393eee8a197064ea2 Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Mon, 17 Mar 2025 21:25:41 +0100 Subject: [PATCH 086/125] [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 a378749369382ef9eeadaa51b10d0ed77831e0b2) --- .../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 5adbfcca0..366982246 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; @@ -3110,6 +3114,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. @@ -3218,6 +3227,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 ecb4ac704..2f47766e3 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -104,6 +104,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 606d82ed4..2b998e9b9 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -410,6 +410,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 2f7059edfa0140851289651fd9b69069a31051e2 Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Wed, 28 May 2025 15:09:33 +0200 Subject: [PATCH 087/125] [nrf noup] boot: zephyr: Kconfig dependencies for PSA LITE exclude certain crypto parts when PSA_CORE_LITE is selected. Signed-off-by: Mateusz Michalek Signed-off-by: Dominik Ermel (cherry picked from commit 23a25925c5ff278c0f8c7069fcea50f0ce719718) --- boot/zephyr/Kconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 2b998e9b9..9a1f6633b 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -74,14 +74,14 @@ if BOOT_USE_PSA_CRYPTO config BOOT_PSA_IMG_HASH_ALG_SHA256_DEPENDENCIES bool default y if BOOT_SOMETHING_USES_SHA256 - select PSA_WANT_ALG_SHA_256 + select PSA_WANT_ALG_SHA_256 if !PSA_CORE_LITE help Dependencies for hashing with SHA256 config BOOT_PSA_IMG_HASH_ALG_SHA512_DEPENDENCIES bool default y if BOOT_SOMETHING_USES_SHA512 - select PSA_WANT_ALG_SHA_512 + select PSA_WANT_ALG_SHA_512 if !PSA_CORE_LITE help Dependencies for hashing with SHA512 @@ -90,7 +90,7 @@ config BOOT_ED25519_PSA_DEPENDENCIES select PSA_WANT_ALG_PURE_EDDSA select PSA_WANT_ECC_TWISTED_EDWARDS_255 select PSA_WANT_ECC_MONTGOMERY_255 - select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT + select PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT if !PSA_CORE_LITE help Dependencies for ed25519 signature @@ -364,9 +364,9 @@ config BOOT_ED25519_PSA select PSA_CRYPTO_C select MBEDTLS_PSA_CRYPTO_C select MBEDTLS_ASN1_PARSE_C if MBEDTLS_BUILTIN - select MBEDTLS_ENABLE_HEAP - select BOOT_IMG_HASH_ALG_SHA256_ALLOW - select BOOT_IMG_HASH_ALG_SHA512_ALLOW + select MBEDTLS_ENABLE_HEAP if !PSA_CORE_LITE + select BOOT_IMG_HASH_ALG_SHA256_ALLOW if !PSA_CORE_LITE + select BOOT_IMG_HASH_ALG_SHA512_ALLOW if !PSA_CORE_LITE select BOOT_ED25519_PSA_DEPENDENCIES select BOOT_X25519_PSA_DEPENDENCIES if BOOT_ENCRYPT_IMAGE From d69621e3032f03ddf462eb3a9d2df5af03955898 Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Thu, 24 Jul 2025 13:31:00 +0200 Subject: [PATCH 088/125] [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 (cherry picked from commit 68379845127b83191fd3d06591e084f6a532a9a5) --- 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, 64 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/include/bootutil/crypto/ecdsa.h b/boot/bootutil/include/bootutil/crypto/ecdsa.h index a5d0f8b1b..31d7bec9a 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -473,6 +473,7 @@ 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 */ @@ -491,6 +492,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_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 96c1853dd..522e5da2d 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -514,7 +514,8 @@ bootutil_img_validate(struct boot_loader_state *state, #endif ) { -#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) || defined(MCUBOOT_DECOMPRESS_IMAGES) +#if (defined(EXPECTED_KEY_TLV) && defined(MCUBOOT_HW_KEY)) || defined(MCUBOOT_HW_ROLLBACK_PROT) || defined(MCUBOOT_DECOMPRESS_IMAGES) \ + || defined(MCUBOOT_BUILTIN_KEY) 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 9a1f6633b..2076ddc1f 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -422,7 +422,14 @@ config BOOT_KMU_KEYS_REVOCATION help Enabling KMU key revocation backend. -if !BOOT_SIGNATURE_USING_KMU +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 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 ae9571100..5223a3f44 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_NRF_BOOT_SIGNATURE_USING_ITS +#define MCUBOOT_BUILTIN_KEY +#endif + #ifdef CONFIG_BOOT_VALIDATE_SLOT0 #define MCUBOOT_VALIDATE_PRIMARY_SLOT #endif From 31c8554d59b13f95558e0b91653629f810d69250 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 29 Jul 2025 16:17:11 +0000 Subject: [PATCH 089/125] [nrf fromtree] bootutil: Fix X25519 HMAC-SHA512 The MAC tag of encryption key has been incorrectly using only 32 bytes of HKDF for HMAC-SHA512 keyword. Signed-off-by: Dominik Ermel (cherry picked from commit 32db78869a173758f30a6a4592342edb34ca097e) --- boot/bootutil/src/encrypted_psa.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/boot/bootutil/src/encrypted_psa.c b/boot/bootutil/src/encrypted_psa.c index 0cfdc9768..7e53ed4a7 100644 --- a/boot/bootutil/src/encrypted_psa.c +++ b/boot/bootutil/src/encrypted_psa.c @@ -43,7 +43,11 @@ static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_ISO_IDENTIFIED_ORG \ #define HKDF_AES_KEY_SIZE (BOOT_ENC_KEY_SIZE) /* MAC feed */ #define HKDF_MAC_FEED_INDEX (HKDF_AES_KEY_INDEX + HKDF_AES_KEY_SIZE) -#define HKDF_MAC_FEED_SIZE (32) /* This is SHA independent */ +#if !defined(MCUBOOT_HMAC_SHA512) +#define HKDF_MAC_FEED_SIZE (32) +#else +#define HKDF_MAC_FEED_SIZE (64) +#endif /* Total size */ #define HKDF_SIZE (HKDF_AES_KEY_SIZE + HKDF_MAC_FEED_SIZE) From 2128ae512234af3b8eb0c6ecb6ac3270a69b098b Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 29 Jul 2025 16:18:31 +0000 Subject: [PATCH 090/125] [nrf fromtree] imgtool: Fix x25519 TLV HMAC tag HMAC-SHA512 has been incorrectly fed only 32 bytes of password. Signed-off-by: Dominik Ermel (cherry picked from commit 94d85f91f98386a85a282c151a40527f342b8937) --- scripts/imgtool/image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index 4e2830370..b24e5de8d 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -444,7 +444,7 @@ def ecies_hkdf(self, enckey, plainkey, hmac_sha_alg): newpk = X25519PrivateKey.generate() shared = newpk.exchange(enckey._get_public()) derived_key = HKDF( - algorithm=hmac_sha_alg, length=48, salt=None, + algorithm=hmac_sha_alg, length=16 + hmac_sha_alg.digest_size, salt=None, info=b'MCUBoot_ECIES_v1', backend=default_backend()).derive(shared) encryptor = Cipher(algorithms.AES(derived_key[:16]), modes.CTR(bytes([0] * 16)), From 8b2d04cba336b40f97b1c5edbef80f4e58fa1a90 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 30 Jul 2025 14:09:32 +0000 Subject: [PATCH 091/125] [nrf noup] zephyr: Enforce HMAC-SHA512 for NRF54L with X25519 ECIES-X25519 key exchange on NRF54L will be using HMAC-SHA512 for MAC tagging encryption key. Signed-off-by: Dominik Ermel --- boot/zephyr/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 2076ddc1f..0a543a384 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -728,6 +728,7 @@ if BOOT_ENCRYPT_X25519 && BOOT_USE_PSA_CRYPTO choice BOOT_HMAC_SHA prompt "SHA used for HMAC and HKDF in encryption key exchange" + default BOOT_HMAC_SHA512 if BOOT_ENCRYPT_X25519 && (SOC_NRF54L15_CPUAPP || SOC_NRF54LM20A_ENGA_CPUAPP) default BOOT_HMAC_SHA256 help HMAC/HKDF sha algorithm may be selected to synchronize sha From 30e7326a49a20df7326d3996bec73cf3802745e2 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 31 Jul 2025 12:01:43 +0000 Subject: [PATCH 092/125] [nrf noup] boot: Use NCS_ prefix for sdk-nrf specific Kconfigs nrf-squash! [nrf noup] boot: Add retry for image verification Use NCS_ prefix, for Kconfigs added in noups, to avoid collisions. The NRF_ prefix will remain reserved for Kconfigs related to products or sdk-nrf subsystems. Signed-off-by: Dominik Ermel --- 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 366982246..23a65d1ec 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -57,9 +57,9 @@ #ifdef __ZEPHYR__ #include -#if defined(CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) +#if defined(CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS) #include -#endif /* CONFIG_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ +#endif /* CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS */ #endif #if defined(CONFIG_SOC_NRF5340_CPUAPP) && defined(PM_CPUNET_B0N_ADDRESS) && defined(CONFIG_PCD_APP) @@ -916,10 +916,10 @@ 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 */ + 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 */ #if defined(MCUBOOT_SWAP_USING_OFFSET) && defined(MCUBOOT_SERIAL_RECOVERY) FIH_CALL(bootutil_img_validate, fih_rc, state, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ, @@ -930,25 +930,25 @@ boot_image_check(struct boot_loader_state *state, struct image_header *hdr, #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 */ +#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_NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 +#if CONFIG_NCS_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 */ + CONFIG_NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT, fih_rc); +#endif /* 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 + 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_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 */ + 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 */ } } } diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 0a543a384..fd3c09af8 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1309,7 +1309,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 NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT +config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT int "Number of image validation attempts" default 1 help @@ -1318,9 +1318,9 @@ config NRF_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 NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS +config NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_WAIT_MS int "Time between image validation attempts" - depends on NRF_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 + depends on NCS_MCUBOOT_IMG_VALIDATE_ATTEMPT_COUNT > 1 default 5000 help Time between image validation attempts, in milliseconds. From 4bfb139af4fadbc651ea61e27d21331834ce2307 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Fri, 1 Aug 2025 10:36:12 +0000 Subject: [PATCH 093/125] [nrf noup] boot: Use NCS_ prefix for sdk-nrf specific Kconfigs nrf-squash! [nrf noup] Added BOOT_SIGNATURE_USING_ITS for ecdsa configuration Replace NRF_BOOT_SIGNATURE_USING_ITS with NCS_BOOT_SIGNATURE_USING_ITS prefix. Signed-off-by: Dominik Ermel --- 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 31d7bec9a..0e9205c29 100644 --- a/boot/bootutil/include/bootutil/crypto/ecdsa.h +++ b/boot/bootutil/include/bootutil/crypto/ecdsa.h @@ -473,7 +473,7 @@ static int bootutil_ecdsa_parse_public_key(bootutil_ecdsa_context *ctx, } #endif /* !MCUBOOT_BUILTIN_KEY */ -#if !defined(CONFIG_NRF_BOOT_SIGNATURE_USING_ITS) +#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 */ @@ -492,7 +492,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_NRF_BOOT_SIGNATURE_USING_ITS */ +#else /* !CONFIG_NCS_BOOT_SIGNATURE_USING_ITS */ static const psa_key_id_t builtin_key_ids[] = { 0x40022100, @@ -539,7 +539,7 @@ static inline int bootutil_ecdsa_verify(bootutil_ecdsa_context *ctx, return status == PSA_SUCCESS ? 0 : 2; } -#endif /* !CONFIG_NRF_BOOT_SIGNATURE_USING_ITS */ +#endif /* !CONFIG_NCS_BOOT_SIGNATURE_USING_ITS */ #elif defined(MCUBOOT_USE_MBED_TLS) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index fd3c09af8..cdb4d29cc 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -422,14 +422,14 @@ config BOOT_KMU_KEYS_REVOCATION help Enabling KMU key revocation backend. -config NRF_BOOT_SIGNATURE_USING_ITS +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 && !NRF_BOOT_SIGNATURE_USING_ITS +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 5223a3f44..8ba030738 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_NRF_BOOT_SIGNATURE_USING_ITS +#ifdef CONFIG_NCS_BOOT_SIGNATURE_USING_ITS #define MCUBOOT_BUILTIN_KEY #endif From 58175b6f71bdae10e1d10896c1c858520ab583ec Mon Sep 17 00:00:00 2001 From: Audun Korneliussen Date: Mon, 4 Aug 2025 15:50:33 +0200 Subject: [PATCH 094/125] [nrf noup] boot/zephyr/nrf_cleanup: fix index error nrf-squash! [nrf noup] boot/zephyr/nrf_cleanup: cleanup uarte pins Fix indexing variable mismatch. Signed-off-by: Audun Korneliussen --- 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 39dfcbc41..e261d1914 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[i]); + nrfy_gpio_cfg_default(pin[j]); } } #endif From 37486f508fd7bc760732a67eab650d76590ebe86 Mon Sep 17 00:00:00 2001 From: Kari Hamalainen Date: Fri, 8 Aug 2025 09:32:03 +0300 Subject: [PATCH 095/125] [nrf noup] workflows: Add manifest PRs creation Adding action to create manifest PRs automatically. Signed-off-by: Kari Hamalainen --- .github/workflows/manifest-PR.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/manifest-PR.yml diff --git a/.github/workflows/manifest-PR.yml b/.github/workflows/manifest-PR.yml new file mode 100644 index 000000000..a871aa381 --- /dev/null +++ b/.github/workflows/manifest-PR.yml @@ -0,0 +1,17 @@ +name: handle manifest PR +on: + pull_request_target: + types: [opened, synchronize, closed] + branches: + - main + + +jobs: + call-manifest-pr-action: + runs-on: ubuntu-latest + steps: + - name: handle manifest PR + uses: nrfconnect/action-manifest-pr@main + with: + token: ${{ secrets.NCS_GITHUB_TOKEN }} + manifest-pr-title-details: ${{ github.event.pull_request.title }} From bc5eb3f126f655b4dd51ce06952e126a8c54186d Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 7 Aug 2025 11:54:42 +0100 Subject: [PATCH 096/125] [nrf fromlist] boot: zephyr: Fix including asn1 when ed25519 is used Fixes wrongly including the asn1 MBEDTLS file when the Kconfig is set to not include it Upstream PR #: 2416 Signed-off-by: Jamie McCrae --- boot/zephyr/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index 2f47766e3..abb0f9a2d 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -309,8 +309,13 @@ elseif(CONFIG_BOOT_SIGNATURE_TYPE_ED25519 OR CONFIG_BOOT_ENCRYPT_X25519) ${FIAT_DIR}/src/curve25519.c ) else() + if(MBEDTLS_ASN1_DIR) + zephyr_library_sources( + ${MBEDTLS_ASN1_DIR}/src/asn1parse.c + ) + endif() + zephyr_library_sources( - ${MBEDTLS_ASN1_DIR}/src/asn1parse.c ${BOOT_DIR}/bootutil/src/ed25519_psa.c ) endif() From a184e32064cb04efdd49951088f8b2e802990e7e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 7 Aug 2025 11:58:29 +0100 Subject: [PATCH 097/125] [nrf noup] boot: zephyr: Fix bm IO button check nrf-squash! [nrf noup] boot: zephyr: Add bm firmware loader code Fixes IO in BM mode to use the hal directly rather than a library that increases the build size by 2.5KiB for a simple button check Signed-off-by: Jamie McCrae --- boot/zephyr/io_bm.c | 45 +++++++++------------------------------------ 1 file changed, 9 insertions(+), 36 deletions(-) diff --git a/boot/zephyr/io_bm.c b/boot/zephyr/io_bm.c index 3f65a5d0e..798cf7a3f 100644 --- a/boot/zephyr/io_bm.c +++ b/boot/zephyr/io_bm.c @@ -89,31 +89,13 @@ void io_led_set(int value) bool io_detect_pin(void) { - int rc; bool pin_active; - rc = bm_buttons_init( - &(struct bm_buttons_config){ - .pin_number = BOARD_PIN_BTN_0, - .active_state = BM_BUTTONS_ACTIVE_LOW, - .pull_config = BM_BUTTONS_PIN_PULLUP, - }, - 1, - BM_BUTTONS_DETECTION_DELAY_MIN_US); - if (rc) { - BOOT_LOG_ERR("Failed to initialize buttons: %d", rc); - return false; - } + nrf_gpio_cfg_input(BOARD_PIN_BTN_0, BM_BUTTONS_PIN_PULLUP); - rc = bm_buttons_enable(); - if (rc) { - BOOT_LOG_ERR("Failed to enable button detection: %d", rc); - return false; - } + pin_active = (bool)nrf_gpio_pin_read(BOARD_PIN_BTN_0); - pin_active = bm_buttons_is_pressed(BOARD_PIN_BTN_0); - - if (pin_active) { + if (!pin_active) { if (BUTTON_0_DETECT_DELAY > 0) { #ifdef CONFIG_MULTITHREADING k_sleep(K_MSEC(50)); @@ -125,13 +107,15 @@ bool io_detect_pin(void) int64_t timestamp = k_uptime_get(); for(;;) { - pin_active = bm_buttons_is_pressed(BOARD_PIN_BTN_0); + uint32_t delta; + + pin_active = (bool)nrf_gpio_pin_read(BOARD_PIN_BTN_0); /* Get delta from when this started */ - uint32_t delta = k_uptime_get() - timestamp; + delta = k_uptime_get() - timestamp; /* If not pressed OR if pressed > debounce period, stop. */ - if (delta >= BUTTON_0_DETECT_DELAY || !pin_active) { + if (delta >= BUTTON_0_DETECT_DELAY || pin_active) { break; } @@ -145,18 +129,7 @@ bool io_detect_pin(void) } } - rc = bm_buttons_disable(); - - if (rc) { - BOOT_LOG_ERR("Failed to disable buttons: %d", rc); - } - - rc = bm_buttons_deinit(); - if (rc) { - BOOT_LOG_ERR("Failed to de-initialize buttons: %d", rc); - } - - return (bool)pin_active; + return (bool)!pin_active; } #endif From edcad137cf026394c217487e1f35498f0a4178e6 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 7 Aug 2025 13:03:03 +0100 Subject: [PATCH 098/125] Revert "[nrf noup] boot: zephyr: Add NCS boot banner" This reverts commit c41b4a88811a7feeefea7146d44da3ecf9bafc24. Signed-off-by: Jamie McCrae --- boot/zephyr/prj.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index eecc1cbca..51dc99b27 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -35,6 +35,3 @@ CONFIG_CBPRINTF_NANO=y ### Use the minimal C library to reduce flash usage CONFIG_MINIMAL_LIBC=y CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 - -# NCS boot banner -CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="MCUboot" From b31a7c67942e3380bd24d172a27e59f062a78add Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Thu, 7 Aug 2025 13:03:53 +0100 Subject: [PATCH 099/125] Revert "[nrf noup] zephyr: Restore default RTC user channel count" This reverts commit abaff579f26f58d9c8969ee5863d5e44d56bcc7e. Signed-off-by: Jamie McCrae --- boot/zephyr/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 51dc99b27..119e07579 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -34,4 +34,3 @@ CONFIG_MCUBOOT_LOG_LEVEL_INF=y CONFIG_CBPRINTF_NANO=y ### Use the minimal C library to reduce flash usage CONFIG_MINIMAL_LIBC=y -CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 From edc1c7053f9acb65344fcda860aeb16a8c14d3ff Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 9 May 2025 17:20:18 -0700 Subject: [PATCH 100/125] [nrf fromtree] boot: Switch to picolibc Save some memory Signed-off-by: Keith Packard (cherry picked from commit 11982df962e2314f4e0c73b7ebc17172026c9266) --- boot/zephyr/prj.conf | 6 ++++-- boot/zephyr/socs/esp32_procpu.conf | 3 ++- boot/zephyr/socs/esp32c2.conf | 3 ++- boot/zephyr/socs/esp32c3.conf | 3 ++- boot/zephyr/socs/esp32c6.conf | 3 ++- boot/zephyr/socs/esp32s2.conf | 3 ++- boot/zephyr/socs/esp32s3_procpu.conf | 3 ++- 7 files changed, 16 insertions(+), 8 deletions(-) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 119e07579..02b27f1c4 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -32,5 +32,7 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_MCUBOOT_LOG_LEVEL_INF=y ### Decrease footprint by ~4 KB in comparison to CBPRINTF_COMPLETE=y CONFIG_CBPRINTF_NANO=y -### Use the minimal C library to reduce flash usage -CONFIG_MINIMAL_LIBC=y +### Use picolibc to reduce flash usage +CONFIG_PICOLIBC=y +### Disable malloc arena because we don't need it +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32_procpu.conf b/boot/zephyr/socs/esp32_procpu.conf index b2b405922..7d3368bad 100644 --- a/boot/zephyr/socs/esp32_procpu.conf +++ b/boot/zephyr/socs/esp32_procpu.conf @@ -16,4 +16,5 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32c2.conf b/boot/zephyr/socs/esp32c2.conf index 5b49f163b..8fdaa8852 100644 --- a/boot/zephyr/socs/esp32c2.conf +++ b/boot/zephyr/socs/esp32c2.conf @@ -17,4 +17,5 @@ CONFIG_DEBUG=n CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32c3.conf b/boot/zephyr/socs/esp32c3.conf index 56298cd4f..96b81e797 100644 --- a/boot/zephyr/socs/esp32c3.conf +++ b/boot/zephyr/socs/esp32c3.conf @@ -17,4 +17,5 @@ CONFIG_DEBUG=n CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32c6.conf b/boot/zephyr/socs/esp32c6.conf index 5b49f163b..8fdaa8852 100644 --- a/boot/zephyr/socs/esp32c6.conf +++ b/boot/zephyr/socs/esp32c6.conf @@ -17,4 +17,5 @@ CONFIG_DEBUG=n CONFIG_XIP=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32s2.conf b/boot/zephyr/socs/esp32s2.conf index b2b405922..7d3368bad 100644 --- a/boot/zephyr/socs/esp32s2.conf +++ b/boot/zephyr/socs/esp32s2.conf @@ -16,4 +16,5 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 diff --git a/boot/zephyr/socs/esp32s3_procpu.conf b/boot/zephyr/socs/esp32s3_procpu.conf index b2b405922..7d3368bad 100644 --- a/boot/zephyr/socs/esp32s3_procpu.conf +++ b/boot/zephyr/socs/esp32s3_procpu.conf @@ -16,4 +16,5 @@ CONFIG_LOG_DEFAULT_LEVEL=0 CONFIG_DEBUG=n CONFIG_HEAP_MEM_POOL_SIZE=4096 -CONFIG_MINIMAL_LIBC=y +CONFIG_PICOLIBC=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 From 50e1caa7c6d9710a610537e97188e624d548dfca Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Mon, 21 Mar 2022 13:44:27 +0100 Subject: [PATCH 101/125] [nrf noup] zephyr: Restore default RTC user channel count The default value of CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT for nRF52 SOCs has been changed from 0 to 3, but it makes MCUBoot get stuck on erasing flash pages when swapping two images. Restore the previous value until the RTC issue is resolved (see NCSDK-14427) Signed-off-by: Damian Krolik Signed-off-by: Torsten Rasmussen Signed-off-by: Jamie McCrae Signed-off-by: Dominik Ermel (cherry picked from commit 3957a30521a42f1794dca54f3e8f383f8d69ce8a) --- boot/zephyr/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 02b27f1c4..26b9b4d65 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -36,3 +36,4 @@ CONFIG_CBPRINTF_NANO=y CONFIG_PICOLIBC=y ### Disable malloc arena because we don't need it CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 +CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 From 8d31ad7f5e284789e9dc3acb3cb223dfe4e4db09 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 11 Jun 2024 12:32:51 +0100 Subject: [PATCH 102/125] [nrf noup] boot: zephyr: Add NCS boot banner Adds a boot banner which shows as MCUboot Signed-off-by: Jamie McCrae (cherry picked from commit 4b3d6ab014bca42f57b25bfc1843a473f11cb898) --- boot/zephyr/prj.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 26b9b4d65..87829ba63 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -37,3 +37,6 @@ CONFIG_PICOLIBC=y ### Disable malloc arena because we don't need it CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 + +# NCS boot banner +CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="MCUboot" From c72ed153fb924203975c38dfea2853ae612e0a9a Mon Sep 17 00:00:00 2001 From: Andrzej Puzdrowski Date: Fri, 8 Aug 2025 13:30:10 +0200 Subject: [PATCH 103/125] [nrf fromlist] boot/boot_serial: build-time skip of the erasing of img status page For MCUboot's MCUBOOT_SINGLE_APPLICATION_SLOT, MCUBOOT_FIRMWARE_LOADER, MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD modes there is not image run-time status data at the end on the image. Erase of that was done as the last image page erase - and was no harm before by luck. Following commit just reveled the issue: #35536633846b53ccdf01bea0594526de4b416fc0 Upstream PR #: 2417 Signed-off-by: Andrzej Puzdrowski --- boot/boot_serial/src/boot_serial.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/boot/boot_serial/src/boot_serial.c b/boot/boot_serial/src/boot_serial.c index 82e1abddb..fd1871b5e 100644 --- a/boot/boot_serial/src/boot_serial.c +++ b/boot/boot_serial/src/boot_serial.c @@ -77,6 +77,12 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); +#if !(defined(MCUBOOT_SINGLE_APPLICATION_SLOT) || \ + defined(MCUBOOT_FIRMWARE_LOADER) || \ + defined(MCUBOOT_SINGLE_APPLICATION_SLOT_RAM_LOAD)) +#define BOOT_IMAGE_HAS_STATUS_FIELDS +#endif + #ifndef ARRAY_SIZE #define ARRAY_SIZE ZCBOR_ARRAY_SIZE #endif @@ -914,8 +920,10 @@ bs_upload(char *buf, int len) * erase has stopped to let us know whether erase * is needed to be able to write current chunk. */ +#ifdef BOOT_IMAGE_HAS_STATUS_FIELDS static struct flash_sector status_sector; #endif +#endif /* MCUBOOT_ERASE_PROGRESSIVELY */ #ifdef MCUBOOT_SWAP_USING_OFFSET static uint32_t start_off = 0; #endif @@ -988,7 +996,7 @@ bs_upload(char *buf, int len) #endif curr_off = 0; -#ifdef MCUBOOT_ERASE_PROGRESSIVELY +#if defined(MCUBOOT_ERASE_PROGRESSIVELY) && defined(BOOT_IMAGE_HAS_STATUS_FIELDS) /* Get trailer sector information; this is done early because inability to get * that sector information means that upload will not work anyway. * TODO: This is single occurrence issue, it should get detected during tests @@ -1167,7 +1175,7 @@ bs_upload(char *buf, int len) if (rc == 0) { curr_off += img_chunk_len + rem_bytes; if (curr_off == img_size) { -#ifdef MCUBOOT_ERASE_PROGRESSIVELY +#if defined(MCUBOOT_ERASE_PROGRESSIVELY) && defined(BOOT_IMAGE_HAS_STATUS_FIELDS) /* Assure that sector for image trailer was erased. */ /* Check whether it was erased during previous upload. */ off_t start = flash_sector_get_off(&status_sector); From 95d384ac85bb8c81c1102f4b94b90515264058ae Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Fri, 8 Aug 2025 16:42:15 +0200 Subject: [PATCH 104/125] [nrf fromtree] bootutil: Fix scratch scrambling This commit fixes the scrambling of the scratch area after persisting a trailer to the primary slot. Previous use of boot_erase_region() didn't guarantee that the scratch area is scrambled, as it only erases memory for devices that selects CONFIG_MCUBOOT_STORAGE_WITH_ERASE. Signed-off-by: Michal Kozikowski (cherry picked from commit 800868a951dd6042ba11de6d056dad5e76bbf738) --- boot/bootutil/src/swap_scratch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c index 360dbe88c..6581b55a6 100644 --- a/boot/bootutil/src/swap_scratch.c +++ b/boot/bootutil/src/swap_scratch.c @@ -926,7 +926,7 @@ boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state, * happens then the scratch which is partially erased would be wrote back to the * primary slot, causing a corrupt unbootable image */ - rc = boot_erase_region(fap_scratch, 0, flash_area_get_size(fap_scratch), true); + rc = boot_scramble_region(fap_scratch, 0, flash_area_get_size(fap_scratch), true); assert(rc == 0); } } From 6c096b8ed7bfddf044b20dfb512c4c1fd06c2ef6 Mon Sep 17 00:00:00 2001 From: Georgios Vasilakis Date: Fri, 8 Aug 2025 12:52:24 +0200 Subject: [PATCH 105/125] [nrf noup] boot: zephyr: Adjust PSA requirements for PSA_CORE_LITE nrf-squash! [nrf noup] boot: zephyr: Kconfig dependencies for PSA LITE The PSA core lite now requires the PSA_WANTs for the hashing functions to be set in order to be used so select them as normal. Signed-off-by: Georgios Vasilakis --- boot/zephyr/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index cdb4d29cc..4ddd138d7 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -74,14 +74,14 @@ if BOOT_USE_PSA_CRYPTO config BOOT_PSA_IMG_HASH_ALG_SHA256_DEPENDENCIES bool default y if BOOT_SOMETHING_USES_SHA256 - select PSA_WANT_ALG_SHA_256 if !PSA_CORE_LITE + select PSA_WANT_ALG_SHA_256 help Dependencies for hashing with SHA256 config BOOT_PSA_IMG_HASH_ALG_SHA512_DEPENDENCIES bool default y if BOOT_SOMETHING_USES_SHA512 - select PSA_WANT_ALG_SHA_512 if !PSA_CORE_LITE + select PSA_WANT_ALG_SHA_512 help Dependencies for hashing with SHA512 From 4e467978a6a1c2f0703e20fe956e4c34e94da700 Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Wed, 6 Aug 2025 16:49:05 +0200 Subject: [PATCH 106/125] [nrf fromtree] bootutil: Fixed security counter overflow detected to late This commit fixes the issue, occuring when the maximum amount of security counter updates has been reached. This fact was only detected after a permament update already happened - the updated firmware was unable to boot, as it failed when trying to update the security counter after the permament swap. This commit adds the check if the security counter can be updated (i. e. free security counter slots are still available) before the swap is performed, fixing the issue. Signed-off-by: Artur Hadasz (cherry picked from commit fe8f9fc07a3b01e239fa2e999615227fa314520a) --- boot/bootutil/include/bootutil/security_cnt.h | 13 +++++++++++++ boot/bootutil/src/image_validate.c | 13 +++++++++++++ boot/zephyr/Kconfig | 11 +++++++++++ boot/zephyr/include/mcuboot_config/mcuboot_config.h | 4 ++++ 4 files changed, 41 insertions(+) diff --git a/boot/bootutil/include/bootutil/security_cnt.h b/boot/bootutil/include/bootutil/security_cnt.h index 7e1389618..ff3a7371c 100644 --- a/boot/bootutil/include/bootutil/security_cnt.h +++ b/boot/bootutil/include/bootutil/security_cnt.h @@ -72,6 +72,19 @@ fih_ret boot_nv_security_counter_get(uint32_t image_id, fih_int *security_cnt); int32_t boot_nv_security_counter_update(uint32_t image_id, uint32_t img_security_cnt); +/** + * This function verifies whether the security counter update to a given value is possible. + * The update might not be possible if the maximum amount of security counter updates + * was reached. + * + * @param image_id Index of the image (from 0). + * @param img_security_cnt New security counter value. + * + * @return FIH_SUCCESS if update is possible; FIH_FAILURE otherwise + */ +fih_ret boot_nv_security_counter_is_update_possible(uint32_t image_id, + uint32_t img_security_cnt); + #ifdef __cplusplus } #endif diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index 522e5da2d..ba31ddbf3 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -839,6 +839,19 @@ bootutil_img_validate(struct boot_loader_state *state, goto out; } +#ifdef MCUBOOT_HW_ROLLBACK_PROT_COUNTER_LIMITED + if (img_security_cnt > (uint32_t)fih_int_decode(security_cnt)) { + FIH_CALL(boot_nv_security_counter_is_update_possible, fih_rc, image_index, + img_security_cnt); + if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) { + FIH_SET(fih_rc, FIH_FAILURE); + BOOT_LOG_ERR("Security counter update is not possible, possibly the maximum " + "number of security updates has been reached."); + goto out; + } + } +#endif + /* The image's security counter has been successfully verified. */ security_counter_valid = fih_rc; skip_security_counter_read: diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 4ddd138d7..6534962ab 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1076,6 +1076,17 @@ config MCUBOOT_HW_DOWNGRADE_PREVENTION Because of the acceptance of equal values it allows for software downgrade to some extent. +config MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_LIMITED + bool "HW based downgrade prevention counter has limited number of updates" + depends on MCUBOOT_HW_DOWNGRADE_PREVENTION + help + When this option is set, the hardware downgrade prevention counter + has limited number of updates. This option will enable checking + if it is possible to update the counter before performing + the upgrade. If an update package contains a security counter + value as a TLV but it is not possible to update the counter, + the update will be rejected. + endchoice config BOOT_WATCHDOG_FEED diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 8ba030738..0c02f62bc 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -209,6 +209,10 @@ #define MCUBOOT_HW_ROLLBACK_PROT #endif +#ifdef CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_LIMITED +#define MCUBOOT_HW_ROLLBACK_PROT_COUNTER_LIMITED +#endif + #ifdef CONFIG_MEASURED_BOOT #define MCUBOOT_MEASURED_BOOT #endif From 0fadab126d9ba51365b3db1cdb6d55ed892c62b4 Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Mon, 11 Aug 2025 14:23:04 +0200 Subject: [PATCH 107/125] [nrf noup] zephyr: hw security counter limited set by default This commit sets the MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_LIMITED by default for platforms which support the security counter. Signed-off-by: Artur Hadasz --- boot/zephyr/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 6534962ab..b6098fd09 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1079,6 +1079,7 @@ config MCUBOOT_HW_DOWNGRADE_PREVENTION config MCUBOOT_HW_DOWNGRADE_PREVENTION_COUNTER_LIMITED bool "HW based downgrade prevention counter has limited number of updates" depends on MCUBOOT_HW_DOWNGRADE_PREVENTION + default y if SOC_NRF5340_CPUAPP || SOC_SERIES_NRF91X || SOC_SERIES_NRF54LX help When this option is set, the hardware downgrade prevention counter has limited number of updates. This option will enable checking From c03a815aa7ed2968ff296e82036980d180919974 Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Wed, 6 Aug 2025 15:12:20 +0200 Subject: [PATCH 108/125] [nrf fromlist] bootutil: Fix PureEdDSA when flash base is not 0x0 This commit introduces fix for PureEdDSA signature verification when the flash base address is not 0x0. The issue was that the flash base address was not taken into account when passing the image address to the signature verification function. Upstream PR #: 2414 Signed-off-by: Michal Kozikowski --- boot/bootutil/src/image_validate.c | 10 +++++++++- docs/release-notes.d/fix-pure-eddsa-base-address.md | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 docs/release-notes.d/fix-pure-eddsa-base-address.md diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c index ba31ddbf3..ff6970b64 100644 --- a/boot/bootutil/src/image_validate.c +++ b/boot/bootutil/src/image_validate.c @@ -544,6 +544,9 @@ bootutil_img_validate(struct boot_loader_state *state, #endif int rc = 0; FIH_DECLARE(fih_rc, FIH_FAILURE); +#if defined(MCUBOOT_SIGN_PURE) + uintptr_t base = 0; +#endif #ifdef MCUBOOT_HW_ROLLBACK_PROT fih_int security_cnt = fih_int_encode(INT_MAX); uint32_t img_security_cnt = 0; @@ -788,11 +791,16 @@ bootutil_img_validate(struct boot_loader_state *state, FIH_CALL(bootutil_verify_sig, valid_signature, hash, sizeof(hash), buf, len, key_id); #else + rc = flash_device_base(flash_area_get_device_id(fap), &base); + if (rc != 0) { + goto out; + } + /* Directly check signature on the image, by using the mapping of * a device to memory. The pointer is beginning of image in flash, * so offset of area, the range is header + image + protected tlvs. */ - FIH_CALL(bootutil_verify_img, valid_signature, (void *)flash_area_get_off(fap), + FIH_CALL(bootutil_verify_img, valid_signature, (void *)(base + flash_area_get_off(fap)), hdr->ih_hdr_size + hdr->ih_img_size + hdr->ih_protect_tlv_size, buf, len, key_id); #endif diff --git a/docs/release-notes.d/fix-pure-eddsa-base-address.md b/docs/release-notes.d/fix-pure-eddsa-base-address.md new file mode 100644 index 000000000..4fe226792 --- /dev/null +++ b/docs/release-notes.d/fix-pure-eddsa-base-address.md @@ -0,0 +1,2 @@ + - Fixed issue in image_validate when `BOOT_SIGNATURE_TYPE_PURE` is enabled + for platforms with NVM memory that does not start at 0x00. From e032eb160eda49185351a35059193b0eece9efa3 Mon Sep 17 00:00:00 2001 From: Michal Kozikowski Date: Thu, 7 Aug 2025 15:31:02 +0200 Subject: [PATCH 109/125] [nrf fromlist] zephyr: Fix FLASH_DEVICE_ID for nRF54H20 platform FLASH_DEVICE_ID was incorrectly set to spi related flash id instead of SoC related. Upstream PR #: 2414 Signed-off-by: Michal Kozikowski --- boot/zephyr/flash_map_extended.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/zephyr/flash_map_extended.c b/boot/zephyr/flash_map_extended.c index 3b95b1fd7..ac9ceba0b 100644 --- a/boot/zephyr/flash_map_extended.c +++ b/boot/zephyr/flash_map_extended.c @@ -38,7 +38,7 @@ BOOT_LOG_MODULE_DECLARE(mcuboot); #elif (defined(CONFIG_SOC_SERIES_NRF54HX) && DT_HAS_CHOSEN(zephyr_flash)) -#define FLASH_DEVICE_ID SPI_FLASH_0_ID +#define FLASH_DEVICE_ID SOC_FLASH_0_ID #define FLASH_DEVICE_BASE CONFIG_FLASH_BASE_ADDRESS #define FLASH_DEVICE_NODE DT_CHOSEN(zephyr_flash) From 1b102ec6654ac85b44a13b991db368f037f2f0af Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Tue, 29 Jul 2025 15:15:10 +0200 Subject: [PATCH 110/125] [nrf fromtree] imgtool: Allow for AES256 encryption Modified code to correctly generate the TLV for AES256 Signed-off-by: Artur Hadasz (cherry picked from commit a5c48f3c842b339b55f4a67def122331844c56e0) --- scripts/imgtool/image.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) mode change 100644 => 100755 scripts/imgtool/image.py diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py old mode 100644 new mode 100755 index b24e5de8d..112d2ef4e --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -443,14 +443,23 @@ def ecies_hkdf(self, enckey, plainkey, hmac_sha_alg): else: newpk = X25519PrivateKey.generate() shared = newpk.exchange(enckey._get_public()) + + # Detect AES key length from plainkey size + key_len = len(plainkey) # 16 for AES-128, 32 for AES-256 + + # Generate derived key with appropriate length (key_len + 32 bytes for HMAC) derived_key = HKDF( - algorithm=hmac_sha_alg, length=16 + hmac_sha_alg.digest_size, salt=None, + algorithm=hmac_sha_alg, length=key_len + hmac_sha_alg.digest_size, salt=None, info=b'MCUBoot_ECIES_v1', backend=default_backend()).derive(shared) - encryptor = Cipher(algorithms.AES(derived_key[:16]), + + # Use appropriate key length for AES encryption + encryptor = Cipher(algorithms.AES(derived_key[:key_len]), modes.CTR(bytes([0] * 16)), backend=default_backend()).encryptor() cipherkey = encryptor.update(plainkey) + encryptor.finalize() - mac = hmac.HMAC(derived_key[16:], hmac_sha_alg, + + # Use remaining bytes for HMAC (after the AES key) + mac = hmac.HMAC(derived_key[key_len:], hmac_sha_alg, backend=default_backend()) mac.update(cipherkey) ciphermac = mac.finalize() From 3b20ec38019dc0841062ba0622b4d7b6792193e5 Mon Sep 17 00:00:00 2001 From: Artur Hadasz Date: Tue, 29 Jul 2025 15:16:23 +0200 Subject: [PATCH 111/125] [nrf fromtree] zephyr: Add support for AES256 This commit adds the parts in the tooling allowing AES256 to work with MCUBoot in zephyr. Currently only in combination PSA + ED25519 Signed-off-by: Artur Hadasz (cherry picked from commit 268968f8e4a834ea3825d98439e4c321de0c6a78) --- boot/zephyr/Kconfig | 16 ++++++++++++++++ .../include/mcuboot_config/mcuboot_config.h | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index b6098fd09..97a6b6679 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -724,6 +724,22 @@ config BOOT_ENCRYPT_X25519 help Hidden option selecting x25519 encryption. +if BOOT_ENCRYPT_IMAGE + +choice BOOT_ENCRYPT_ALG + prompt "Algorithm used for image encryption" + default BOOT_ENCRYPT_ALG_AES_128 + +config BOOT_ENCRYPT_ALG_AES_128 + bool "Use AES-128 for image encryption" + +config BOOT_ENCRYPT_ALG_AES_256 + bool "Use AES-256 for image encryption" + +endchoice # BOOT_ENCRYPT_ALG + +endif # BOOT_ENCRYPT_IMAGE + if BOOT_ENCRYPT_X25519 && BOOT_USE_PSA_CRYPTO choice BOOT_HMAC_SHA diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 0c02f62bc..3b8b0be3f 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -163,6 +163,14 @@ #define MCUBOOT_ENCRYPT_X25519 #endif +#ifdef CONFIG_BOOT_ENCRYPT_ALG_AES_128 +#define MCUBOOT_AES_128 +#endif + +#ifdef CONFIG_BOOT_ENCRYPT_ALG_AES_256 +#define MCUBOOT_AES_256 +#endif + /* Support for HMAC/HKDF using SHA512; this is used in key exchange where * HKDF is used for key expansion and HMAC is used for key verification. */ From 3adc1f232221dc8a6d77c378aa0d97fa24c9c0cb Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Tue, 19 Aug 2025 12:37:42 +0200 Subject: [PATCH 112/125] [nrf noup] boot: zephyr: remove nonsecure ram cleanup nrf-squash! [nrf noup] zephyr: Clean up non-secure RAM if enabled This leads to stack corruption. Signed-off-by: Mateusz Michalek --- boot/zephyr/CMakeLists.txt | 2 +- boot/zephyr/main.c | 5 +---- boot/zephyr/nrf_cleanup.c | 9 --------- 3 files changed, 2 insertions(+), 14 deletions(-) diff --git a/boot/zephyr/CMakeLists.txt b/boot/zephyr/CMakeLists.txt index abb0f9a2d..e8d79af7d 100644 --- a/boot/zephyr/CMakeLists.txt +++ b/boot/zephyr/CMakeLists.txt @@ -755,7 +755,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/main.c b/boot/zephyr/main.c index c51616dda..53a393401 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -144,7 +144,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 @@ -224,9 +224,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_nvic(); /* cleanup NVIC registers */ diff --git a/boot/zephyr/nrf_cleanup.c b/boot/zephyr/nrf_cleanup.c index e261d1914..5ddc74a64 100644 --- a/boot/zephyr/nrf_cleanup.c +++ b/boot/zephyr/nrf_cleanup.c @@ -158,12 +158,3 @@ 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 1b1a37fb7abf8b6e5f7d1e05daacd0081ce2844e Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 19 Aug 2025 12:29:54 +0100 Subject: [PATCH 113/125] [nrf noup] boot: zephyr: Delay bm IO button check nrf-squash! [nrf noup] boot: zephyr: Add bm firmware loader code Delays checking IO button state by 5us after pull-up has been applied to allow time for it to be applied Signed-off-by: Jamie McCrae --- boot/zephyr/io_bm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boot/zephyr/io_bm.c b/boot/zephyr/io_bm.c index 798cf7a3f..788bfab9e 100644 --- a/boot/zephyr/io_bm.c +++ b/boot/zephyr/io_bm.c @@ -93,6 +93,9 @@ bool io_detect_pin(void) nrf_gpio_cfg_input(BOARD_PIN_BTN_0, BM_BUTTONS_PIN_PULLUP); + /* Delay 5 us for pull-up to be applied */ + k_busy_wait(5); + pin_active = (bool)nrf_gpio_pin_read(BOARD_PIN_BTN_0); if (!pin_active) { From f9e4ce08681b0360567ff4b049a991bf91b74054 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 26 Aug 2025 10:02:14 +0100 Subject: [PATCH 114/125] Revert "[nrf noup] boot: zephyr: Add NCS boot banner" This reverts commit 8d31ad7f5e284789e9dc3acb3cb223dfe4e4db09. Signed-off-by: Jamie McCrae --- boot/zephyr/prj.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 87829ba63..26b9b4d65 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -37,6 +37,3 @@ CONFIG_PICOLIBC=y ### Disable malloc arena because we don't need it CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 - -# NCS boot banner -CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="MCUboot" From 446967f45450f972ecab3b76fc48ebbf497c968c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 26 Aug 2025 10:02:18 +0100 Subject: [PATCH 115/125] Revert "[nrf noup] zephyr: Restore default RTC user channel count" This reverts commit 50e1caa7c6d9710a610537e97188e624d548dfca. Signed-off-by: Jamie McCrae --- boot/zephyr/prj.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 26b9b4d65..02b27f1c4 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -36,4 +36,3 @@ CONFIG_CBPRINTF_NANO=y CONFIG_PICOLIBC=y ### Disable malloc arena because we don't need it CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 -CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0 From c85960801ddb83ca6cc2125bd5342139d3befa2c Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 11 Jun 2024 12:32:51 +0100 Subject: [PATCH 116/125] [nrf noup] boot: zephyr: Add NCS boot banner Adds a boot banner which shows as MCUboot Signed-off-by: Jamie McCrae (cherry picked from commit 4b3d6ab014bca42f57b25bfc1843a473f11cb898) --- boot/zephyr/prj.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/boot/zephyr/prj.conf b/boot/zephyr/prj.conf index 02b27f1c4..766762237 100644 --- a/boot/zephyr/prj.conf +++ b/boot/zephyr/prj.conf @@ -36,3 +36,6 @@ CONFIG_CBPRINTF_NANO=y CONFIG_PICOLIBC=y ### Disable malloc arena because we don't need it CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=0 + +# NCS boot banner +CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="MCUboot" From ecc13ac1b0336c5ff39fc00075d34b55ab619752 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 26 Aug 2025 10:22:04 +0100 Subject: [PATCH 117/125] [nrf noup] boot: zephyr: firmware_loader: Allow GPIO usage in BM Allows GPIO entrance mode when bare metal is used, this is needed because the zephyr GPIO drivers are not used, therefore the Kconfig will not be enabled Signed-off-by: Jamie McCrae --- boot/zephyr/Kconfig.firmware_loader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/zephyr/Kconfig.firmware_loader b/boot/zephyr/Kconfig.firmware_loader index 1ba223949..036da98eb 100644 --- a/boot/zephyr/Kconfig.firmware_loader +++ b/boot/zephyr/Kconfig.firmware_loader @@ -8,7 +8,7 @@ menu "Firmware loader entrance methods" menuconfig BOOT_FIRMWARE_LOADER_ENTRANCE_GPIO bool "GPIO" - depends on GPIO + depends on GPIO || NCS_BM help Use a GPIO to enter firmware loader mode. From 285fd59f4386a0317e476da5484f67b906073296 Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Tue, 5 Aug 2025 15:55:31 +0200 Subject: [PATCH 118/125] [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 --- boot/zephyr/Kconfig | 7 +++ boot/zephyr/main.c | 129 +++++++++++++++++++++++++++++++++----------- 2 files changed, 105 insertions(+), 31 deletions(-) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 97a6b6679..3c3c508b1 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -472,6 +472,13 @@ 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 53a393401..fa3eeff90 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -148,6 +148,25 @@ 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); @@ -163,6 +182,84 @@ struct arm_vector_table { uint32_t reset; }; +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, @@ -273,37 +370,7 @@ static void do_boot(struct boot_rsp *rsp) __set_CONTROL(0x00); /* application will configures core on its own */ __ISB(); #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 - ((void (*)(void))vt->reset)(); -#endif + jump_in(vt->reset); } #elif defined(CONFIG_XTENSA) || defined(CONFIG_RISCV) From d8a2e457f25f4d8b3924e3da69b54965e1690678 Mon Sep 17 00:00:00 2001 From: Mateusz Michalek Date: Tue, 26 Aug 2025 12:42:56 +0200 Subject: [PATCH 119/125] [nrf noup] zephyr: boards: nrf54lm20dk_nrf54lm20a_cpuapp.conf adding DK default configuration and fixing PDK configuration. Signed-off-by: Mateusz Michalek --- .../boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf | 13 +++++++++++++ .../boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf | 3 --- 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 boot/zephyr/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf diff --git a/boot/zephyr/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf b/boot/zephyr/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf new file mode 100644 index 000000000..816560405 --- /dev/null +++ b/boot/zephyr/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf @@ -0,0 +1,13 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_BOOT_MAX_IMG_SECTORS=256 + +# Ensure that the SPI NOR driver is disabled by default +CONFIG_SPI_NOR=n + +# TODO: below are not yet supported and need fixing +CONFIG_FPROTECT=n + +CONFIG_BOOT_WATCHDOG_FEED=n diff --git a/boot/zephyr/boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf b/boot/zephyr/boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf index 4944f7b13..816560405 100644 --- a/boot/zephyr/boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf +++ b/boot/zephyr/boards/nrf54lm20pdk_nrf54lm20a_cpuapp.conf @@ -11,6 +11,3 @@ CONFIG_SPI_NOR=n CONFIG_FPROTECT=n CONFIG_BOOT_WATCHDOG_FEED=n - -CONFIG_PSA_CRYPTO_DRIVER_CRACEN=n -CONFIG_PSA_CRYPTO_DRIVER_OBERON=y From c13c65257af74ef087920082d50b040d5d435669 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Wed, 30 Jul 2025 12:09:57 +0200 Subject: [PATCH 120/125] [nrf fromtree] loader: Add boot hook for slot selection Add a bootloader hook to alter the logic of the active slot selection in Direct XIP modes. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit 7c4ec9ab153d105e6e966cecef6806be7b9e6a25) --- boot/bootutil/include/bootutil/boot_hooks.h | 24 +++++++++++++++++++++ boot/bootutil/src/loader.c | 14 ++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/boot/bootutil/include/bootutil/boot_hooks.h b/boot/bootutil/include/bootutil/boot_hooks.h index ef7a89b28..f5b10e8c7 100644 --- a/boot/bootutil/include/bootutil/boot_hooks.h +++ b/boot/bootutil/include/bootutil/boot_hooks.h @@ -82,6 +82,18 @@ #endif /* MCUBOOT_BOOT_GO_HOOKS */ +#ifdef MCUBOOT_FIND_NEXT_SLOT_HOOKS + +#define BOOT_HOOK_FIND_SLOT_CALL(f, ret_default, ...) \ + DO_HOOK_CALL(f, ret_default, __VA_ARGS__) + +#else + +#define BOOT_HOOK_FIND_SLOT_CALL(f, ret_default, ...) \ + HOOK_CALL_NOP(f, ret_default, __VA_ARGS__) + +#endif /* MCUBOOT_FIND_NEXT_SLOT_HOOKS */ + #ifdef MCUBOOT_FLASH_AREA_HOOKS #define BOOT_HOOK_FLASH_AREA_CALL(f, ret_default, ...) \ @@ -260,4 +272,16 @@ int flash_area_get_device_id_hook(const struct flash_area *fa, #define BOOT_RESET_REQUEST_HOOK_CHECK_FAILED 3 #define BOOT_RESET_REQUEST_HOOK_INTERNAL_ERROR 4 +/** + * Finds the preferred slot containing the image. + * + * @param[in] state Boot loader status information. + * @param[in] image Image, for which the slot should be found. + * @param[out] active_slot Number of the preferred slot. + * + * @return 0 if a slot was requested; + * BOOT_HOOK_REGULAR follow the normal execution path. + */ +int boot_find_next_slot_hook(struct boot_loader_state *state, uint8_t image, uint32_t *active_slot); + #endif /*H_BOOTUTIL_HOOKS*/ diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c index 23a65d1ec..1a2290769 100644 --- a/boot/bootutil/src/loader.c +++ b/boot/bootutil/src/loader.c @@ -3605,7 +3605,12 @@ boot_load_and_validate_images(struct boot_loader_state *state) break; } - active_slot = find_slot_with_highest_version(state); + 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 == NO_ACTIVE_SLOT) { BOOT_LOG_INF("No slot to load for image %d", BOOT_CURR_IMG(state)); @@ -3652,7 +3657,12 @@ boot_load_and_validate_images(struct boot_loader_state *state) break; } - active_slot = find_slot_with_highest_version(state); + 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 == NO_ACTIVE_SLOT) { BOOT_LOG_INF("No slot to load for image %d", BOOT_CURR_IMG(state)); From 301ab3359addfcab53539623d866dd83a8d202bf Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Wed, 30 Jul 2025 12:10:31 +0200 Subject: [PATCH 121/125] [nrf fromtree] zephyr: Add support for slot selection boot hook Add a Kconfig option to enable a bootloader hook to alter the logic of the active slot selection in Direct XIP modes. Signed-off-by: Tomasz Chyrowicz (cherry picked from commit d5f84b49cd3e2d51c51f9a1ddd5d60002d297cbc) --- boot/zephyr/Kconfig | 7 +++++++ boot/zephyr/hooks_sample.c | 5 +++++ boot/zephyr/include/mcuboot_config/mcuboot_config.h | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig index 3c3c508b1..d1f5be182 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1165,6 +1165,13 @@ config MCUBOOT_ACTION_HOOKS 'mcuboot_status_type_t' is listed in boot/bootutil/include/bootutil/mcuboot_status.h +config FIND_NEXT_SLOT_HOOKS + bool "Enable hooks for finding the next active slot" + help + Allow to provide procedures for override or extend the search policy + for the best slot to boot in the Direct XIP mode. + By default a slot with the highest version is selected. + config BOOT_DISABLE_CACHES bool "Disable I/D caches before chain-loading application" depends on CPU_HAS_ICACHE || CPU_HAS_DCACHE diff --git a/boot/zephyr/hooks_sample.c b/boot/zephyr/hooks_sample.c index a5a729314..fc7bd2fa4 100644 --- a/boot/zephyr/hooks_sample.c +++ b/boot/zephyr/hooks_sample.c @@ -93,3 +93,8 @@ int boot_img_install_stat_hook(int image_index, int slot, int *img_install_stat) { return BOOT_HOOK_REGULAR; } + +int boot_find_next_slot_hook(struct boot_loader_state *state, uint8_t image, uint32_t *active_slot) +{ + return BOOT_HOOK_REGULAR; +} diff --git a/boot/zephyr/include/mcuboot_config/mcuboot_config.h b/boot/zephyr/include/mcuboot_config/mcuboot_config.h index 3b8b0be3f..d8a8462e0 100644 --- a/boot/zephyr/include/mcuboot_config/mcuboot_config.h +++ b/boot/zephyr/include/mcuboot_config/mcuboot_config.h @@ -283,6 +283,10 @@ #define MCUBOOT_FLASH_AREA_HOOKS #endif +#ifdef CONFIG_FIND_NEXT_SLOT_HOOKS +#define MCUBOOT_FIND_NEXT_SLOT_HOOKS +#endif + #ifdef CONFIG_MCUBOOT_VERIFY_IMG_ADDRESS #define MCUBOOT_VERIFY_IMG_ADDRESS #endif From e1f2ab3806ce7ebc7ef34b3fc04272e747590745 Mon Sep 17 00:00:00 2001 From: Tomasz Chyrowicz Date: Mon, 28 Jul 2025 12:46:20 +0200 Subject: [PATCH 122/125] [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 --- 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, 613 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..b1e8f891e --- /dev/null +++ b/boot/bootutil/include/bootutil/boot_request.h @@ -0,0 +1,105 @@ +/* + * 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 8860fca41..7371a9fe9 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,47 @@ 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, bool confirm, int image_id, uint32_t slot_id) +{ + int rc = BOOT_EBADIMAGE; -static int flash_area_to_image(const struct flash_area *fa) + /* 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 */ + +#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; } @@ -520,15 +556,31 @@ static int flash_area_to_image(const struct flash_area *fa) } #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; @@ -539,6 +591,15 @@ 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.*/ @@ -569,7 +630,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 +661,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 +683,15 @@ 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 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..023f5af5e --- /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) + +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 d1f5be182..a94c7e1e5 100644 --- a/boot/zephyr/Kconfig +++ b/boot/zephyr/Kconfig @@ -1333,6 +1333,10 @@ 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 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 5b4ba3e11..b6c71e5e0 100644 --- a/boot/zephyr/Kconfig.serial_recovery +++ b/boot/zephyr/Kconfig.serial_recovery @@ -191,6 +191,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 1df848634..834dc6341 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 fa3eeff90..38640aa97 100644 --- a/boot/zephyr/main.c +++ b/boot/zephyr/main.c @@ -46,6 +46,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 */ /* Check if Espressif target is supported */ #ifdef CONFIG_SOC_FAMILY_ESPRESSIF_ESP32 @@ -543,6 +549,37 @@ 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; @@ -574,6 +611,11 @@ int main(void) mcuboot_status_change(MCUBOOT_STATUS_STARTUP); + 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() && @@ -589,6 +631,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()) { @@ -649,6 +698,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 5af259f253d5e11a3ab6b99de122b2e8db6fa5c7 Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Tue, 12 Aug 2025 09:27:35 +0000 Subject: [PATCH 123/125] [nrf fromtree] bootutil: Fix bootutil_aes_ctr_drop memset usage memset was given incorrectly pointer size, instead of object size. Signed-off-by: Dominik Ermel (cherry picked from commit aa229135b30e6ce9a24c9ae2cf3a85591d1aa7d6) --- boot/bootutil/include/bootutil/crypto/aes_ctr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr.h b/boot/bootutil/include/bootutil/crypto/aes_ctr.h index e5416dca0..88ae87c39 100644 --- a/boot/bootutil/include/bootutil/crypto/aes_ctr.h +++ b/boot/bootutil/include/bootutil/crypto/aes_ctr.h @@ -58,7 +58,7 @@ void bootutil_aes_ctr_init(bootutil_aes_ctr_context *ctx); static inline void bootutil_aes_ctr_drop(bootutil_aes_ctr_context *ctx) { - memset(ctx, 0, sizeof(ctx)); + memset(ctx, 0, sizeof(*ctx)); } static inline int bootutil_aes_ctr_set_key(bootutil_aes_ctr_context *ctx, const uint8_t *k) From d79a412144f2cbeadb3037883edc4677819102ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Szczygie=C5=82?= Date: Fri, 5 Sep 2025 07:30:25 +0200 Subject: [PATCH 124/125] Revert "[nrf noup] zephyr: add 'minimal' configuration files" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 54f21298ed294b707b5c78f6da81b5e2d262e95b. nrf-squash! [nrf noup] zephyr: add 'minimal' configuration files The minimal configuration is now deprecated: - it is not minimal configuration anymore - built image cannot fit into flash memory - smp_svr_mini_boot sample is a new reference for minimal config Signed-off-by: Adam Szczygieł --- .../nrf5340dk_nrf5340_cpuapp_minimal.conf | 13 ------ boot/zephyr/prj_minimal.conf | 41 ------------------- 2 files changed, 54 deletions(-) delete mode 100644 boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf delete mode 100644 boot/zephyr/prj_minimal.conf diff --git a/boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf b/boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf deleted file mode 100644 index dd5468106..000000000 --- a/boot/zephyr/boards/nrf5340dk_nrf5340_cpuapp_minimal.conf +++ /dev/null @@ -1,13 +0,0 @@ -# -# Copyright (c) 2021 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause -# - -# CC3xx is currently not used for nrf53 -CONFIG_HW_CC3XX=n -CONFIG_NRF_CC3XX_PLATFORM=n - -# Required for kernel operation -CONFIG_CLOCK_CONTROL=y -CONFIG_SYS_CLOCK_EXISTS=y diff --git a/boot/zephyr/prj_minimal.conf b/boot/zephyr/prj_minimal.conf deleted file mode 100644 index 91cf1bc96..000000000 --- a/boot/zephyr/prj_minimal.conf +++ /dev/null @@ -1,41 +0,0 @@ -# -# Copyright (c) 2021 Nordic Semiconductor ASA -# -# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause -# - -CONFIG_MAIN_STACK_SIZE=10240 -CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h" - -CONFIG_FLASH=y -CONFIG_FPROTECT=y -CONFIG_PM=n - -CONFIG_BOOT_SWAP_SAVE_ENCTLV=n -CONFIG_BOOT_ENCRYPT_IMAGE=n - -CONFIG_BOOT_BOOTSTRAP=n -CONFIG_BOOT_UPGRADE_ONLY=n - -### Minimal Configurations ### -CONFIG_BOOT_USE_MIN_PARTITION_SIZE=y -CONFIG_ASSERT=n -CONFIG_BOOT_BANNER=n -CONFIG_NCS_BOOT_BANNER=n -CONFIG_CLOCK_CONTROL=n -CONFIG_CONSOLE=n -CONFIG_CONSOLE_HANDLER=n -CONFIG_GPIO=n -CONFIG_KERNEL_MEM_POOL=n -CONFIG_LOG=n -CONFIG_COMMON_LIBC_CALLOC=n -CONFIG_COMMON_LIBC_MALLOC=n -CONFIG_COMMON_LIBC_REALLOCARRAY=n -CONFIG_NCS_SAMPLES_DEFAULTS=n -CONFIG_NO_RUNTIME_CHECKS=y -CONFIG_NRF_RTC_TIMER=n -CONFIG_PRINTK=n -CONFIG_SERIAL=n -CONFIG_SIZE_OPTIMIZATIONS=y -CONFIG_SYS_CLOCK_EXISTS=n -CONFIG_UART_CONSOLE=n From a7f9f772e82085da75a64c8b4a81512a463e1d8b Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Mon, 2 Jun 2025 16:14:06 +0100 Subject: [PATCH 125/125] [nrf noup] sysflash: Correct ALL_AVAILABLE_SLOTS when MCUBOOT is not image 2 Consider an nRF5340 application with the following sysbuild config: ``` SB_CONFIG_BOOTLOADER_MCUBOOT=y SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y SB_CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y SB_CONFIG_SECURE_BOOT_APPCORE=y SB_CONFIG_SECURE_BOOT_NETCORE=y SB_CONFIG_NETCORE_APP_UPDATE=y SB_CONFIG_MCUBOOT_NRF53_MULTI_IMAGE_UPDATE=y SB_CONFIG_MCUBOOT_MODE_OVERWRITE_ONLY=y ``` In this case, we have a total of 3 updatable images (app, net, mcuboot). `MCUBOOT_IMAGE_NUMBER = 2` (i.e. `CONFIG_UPDATEABLE_IMAGE_NUMBER = 2`), as the app secondary partition is reused for MCUBoot secondary. `CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER = 2` as the net core image has index 1. In this case, we should fall through to the definition of `ALL_AVAILABLE_SLOTS` that caters for 2 updatable images. --- boot/zephyr/include/sysflash/pm_sysflash.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/boot/zephyr/include/sysflash/pm_sysflash.h b/boot/zephyr/include/sysflash/pm_sysflash.h index 0cb16292f..366251901 100644 --- a/boot/zephyr/include/sysflash/pm_sysflash.h +++ b/boot/zephyr/include/sysflash/pm_sysflash.h @@ -31,12 +31,12 @@ #define MCUBOOT_S0_S1_SLOTS #endif -#if (MCUBOOT_IMAGE_NUMBER == 1) || (MCUBOOT_IMAGE_NUMBER == 2 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1) +#if (MCUBOOT_IMAGE_NUMBER == 1) || (MCUBOOT_IMAGE_NUMBER == 2 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER == 1) #define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS -#elif (MCUBOOT_IMAGE_NUMBER == 2) || (MCUBOOT_IMAGE_NUMBER == 3 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER != -1) +#elif (MCUBOOT_IMAGE_NUMBER == 2) || (MCUBOOT_IMAGE_NUMBER == 3 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER == 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) +#elif (MCUBOOT_IMAGE_NUMBER == 3) || (MCUBOOT_IMAGE_NUMBER == 4 && CONFIG_MCUBOOT_MCUBOOT_IMAGE_NUMBER == 3) #define ALL_AVAILABLE_SLOTS FLASH_AREA_IMAGE_0_SLOTS \ FLASH_AREA_IMAGE_1_SLOTS \ FLASH_AREA_IMAGE_2_SLOTS