Infineon: Add Direct-XIP feature for CYW20829 devices
diff --git a/boot/bootutil/include/bootutil/bootutil.h b/boot/bootutil/include/bootutil/bootutil.h
index 4e9fc38..51ec64e 100644
--- a/boot/bootutil/include/bootutil/bootutil.h
+++ b/boot/bootutil/include/bootutil/bootutil.h
@@ -31,6 +31,7 @@
#include <inttypes.h>
#include "bootutil/fault_injection_hardening.h"
#include "bootutil/bootutil_public.h"
+#include "bootutil/image.h"
#ifdef MCUBOOT_ENC_IMAGES_XIP
#include "bootutil/enc_key.h"
@@ -74,6 +75,10 @@
* when attempting to read/write a trailer.
*/
struct image_trailer {
+#if defined(MCUBOOT_DIRECT_XIP)
+ uint8_t image_inactive;
+ uint8_t pad0[BOOT_MAX_ALIGN - 1];
+#endif
uint8_t swap_type;
uint8_t pad1[BOOT_MAX_ALIGN - 1];
uint8_t copy_done;
@@ -86,15 +91,184 @@
uint8_t magic[BOOT_MAGIC_SZ];
};
+typedef enum
+{
+ MCUBOOT_SLOT_STATE_NO_IMAGE = 0,
+ MCUBOOT_SLOT_STATE_ACTIVE,
+ MCUBOOT_SLOT_STATE_PENDING,
+ MCUBOOT_SLOT_STATE_VERIFYING,
+ MCUBOOT_SLOT_STATE_INACTIVE
+} boot_slot_state_t;
+
/* you must have pre-allocated all the entries within this structure */
fih_int boot_go(struct boot_rsp *rsp);
fih_int boot_go_for_image_id(struct boot_rsp *rsp, uint32_t image_id);
+/**
+ * @brief Performs slot validation without performing boot
+ *
+ * @param image_id - Image number, starting from 0
+ *
+ * @param slot_id - Slot index: 0 - primary slot, 1 - secondary slot
+ *
+ * @retval FIH_SUCCESS on success
+ */
+fih_int
+boot_validate_slot_for_image_id(uint32_t image_id, uint32_t slot_id);
+
+/**
+ * @brief Reads image version fields from the image header area
+ *
+ * @param image_id - Image number, starting from 0
+ *
+ * @param slot_id - Slot index: 0 - primary slot, 1 - secondary slot
+ *
+ * @param ver - Version structure output
+ *
+ * @retval 0 on success
+ */
+int
+boot_get_image_version(uint32_t image_id, uint32_t slot_id, struct image_version* ver);
+
+#if defined(MCUBOOT_DIRECT_XIP)
+/**
+ * @brief Marks the slot as inactive.
+ *
+ * @param image_id - Image number, starting from 0.
+ *
+ * @param slot_id - Slot index: 0 - primary slot, 1 - secondary slot.
+ *
+ * @retval 0 on success
+ */
+int
+boot_set_inactive_slot(uint32_t image_id, uint32_t slot_id);
+
+/**
+ * @brief Checks if the slot is inactive.
+ *
+ * @param image_id - Image number, starting from 0.
+ *
+ * @param slot_id - Slot index: 0 - primary slot, 1 - secondary slot.
+ *
+ * @retval 1 The slot is set as inactive
+ * 0 The slot is not set as inactive
+ * -1 On error
+ */
+int
+boot_is_slot_inactive(uint32_t image_id, uint32_t slot_id);
+
+/**
+ * @brief Restores slot from inactive state to make it able to boot.
+ *
+ * @param image_id - Image number, starting from 0
+ *
+ * @param slot_id - Slot index: 0 - primary slot, 1 - secondary slot
+ *
+ * @retval 0 on success
+ *
+ */
+int
+boot_set_pending_slot(uint32_t image_id, uint32_t slot_id);
+
+
+/**
+ * @brief Sets the revert state to the slot. Image will be erased on next reboot
+ *
+ * @param image_id - Image number, starting from 0
+ *
+ * @param slot_id - Slot index: 0 - primary slot, 1 - secondary slot
+ *
+ * @retval 0 on success
+ *
+ */
+int
+boot_set_revert_slot(uint32_t image_id, uint32_t slot_id);
+
+/**
+ * @brief Finds the TLV (Type-Length-Value) metadata information for a specific image and slot.
+ *
+ * Retrieves offset and length information for the requested TLV entry.
+ *
+ * @param image_id Image identifier (starting from 0).
+ *
+ * @param slot_id Slot index (0 for primary slot, 1 for secondary slot).
+ *
+ * @param type TLV type identifier.
+ *
+ * @param len Output pointer for storing TLV length.
+ *
+ * @param off Output pointer for storing TLV offset.
+ *
+ * @retval 0 Success.
+ * @retval Non-zero Error occurred or TLV not found.
+ */
+int
+boot_find_image_tlv_info(uint32_t image_id, uint32_t slot_id, uint16_t type, uint16_t* len, uint32_t* off);
+
+/**
+ * @brief Reads the TLV metadata value from a specified image slot.
+ *
+ * Fetches the actual data associated with the specified TLV type.
+ *
+ * @param image_id Image identifier (starting from 0).
+ *
+ * @param slot_id Slot index (0 for primary slot, 1 for secondary slot).
+ *
+ * @param type TLV type identifier.
+ *
+ * @param buf Buffer pointer to store the retrieved TLV value.
+ *
+ * @param buf_len Length of provided buffer.
+ *
+ * @param read_len Output pointer for storing the actual number of bytes read.
+ *
+ * @retval 0 Success.
+ * @retval Non-zero Error occurred or insufficient buffer length.
+ */
+int
+boot_read_image_tlv_value(uint32_t image_id, uint32_t slot_id, uint16_t type, uint8_t* buf, uint32_t buf_len, uint32_t* read_len);
+
+/**
+ * @brief Retrieves the current state of the specified slot.
+ *
+ * Provides details about the current slot status without image verification.
+ *
+ * @param image_id Image identifier (starting from 0).
+ *
+ * @param slot_id Slot index (0 for primary slot, 1 for secondary slot).
+ *
+ * @param state Output pointer to store the slot state information.
+ *
+ * @retval 0 Success.
+ * @retval Non-zero Error occurred.
+ */
+int
+boot_get_slot_state(uint32_t image_id, uint32_t slot_id, boot_slot_state_t* state);
+
+/**
+ * @brief Retrieves the current state of the specified image slot.
+ *
+ * Provides details about the current status (active, inactive, pending, etc.) of the specified slot.
+ *
+ * @param image_id Image identifier (starting from 0).
+ *
+ * @param slot_id Slot index (0 for primary slot, 1 for secondary slot).
+ *
+ * @param state Output pointer to store the slot state information.
+ *
+ * @retval 0 Success.
+ * @retval Non-zero Error occurred.
+ */
+int
+boot_get_image_state(uint32_t image_id, uint32_t slot_id, boot_slot_state_t* state);
+
+#endif
+
struct boot_loader_state;
void boot_state_clear(struct boot_loader_state *state);
fih_int context_boot_go_flash(struct boot_loader_state *state, struct boot_rsp *rsp);
-#if defined(MCUBOOT_RAM_LOAD)
+#if defined(MCUBOOT_RAM_LOAD) || defined(MCUBOOT_DIRECT_XIP)
fih_int context_boot_go_ram(struct boot_loader_state *state, struct boot_rsp *rsp);
fih_int boot_go_for_image_id_ram(struct boot_rsp *rsp, uint32_t image_id);
#endif
diff --git a/boot/bootutil/include/bootutil/bootutil_public.h b/boot/bootutil/include/bootutil/bootutil_public.h
index 2c303d8..e8e1fb5 100644
--- a/boot/bootutil/include/bootutil/bootutil_public.h
+++ b/boot/bootutil/include/bootutil/bootutil_public.h
@@ -147,6 +147,9 @@
uint8_t copy_done; /* One of the BOOT_FLAG_[...] values. */
uint8_t image_ok; /* One of the BOOT_FLAG_[...] values. */
uint8_t image_num; /* Boot status belongs to this image */
+#if defined(MCUBOOT_DIRECT_XIP)
+ uint8_t image_inactive; /* One of the BOOT_FLAG_[...] values. */
+#endif
};
/**
@@ -230,6 +233,18 @@
*/
uint32_t boot_swap_info_off(const struct flash_area *fap);
+#if defined(MCUBOOT_DIRECT_XIP)
+/**
+ * @brief Get offset of the image invalidation field in the image trailer.
+ *
+ * @param fap Flash are for which offset is determined.
+ *
+ * @retval offset of the image invalidation field.
+ */
+uint32_t
+boot_image_inactive_off(const struct flash_area *fap);
+#endif
+
/**
* @brief Get value of image-ok flag of the image.
*
diff --git a/boot/bootutil/include/bootutil/crypto/aes_ctr.h b/boot/bootutil/include/bootutil/crypto/aes_ctr.h
index 90727f1..5c0796a 100644
--- a/boot/bootutil/include/bootutil/crypto/aes_ctr.h
+++ b/boot/bootutil/include/bootutil/crypto/aes_ctr.h
@@ -137,7 +137,7 @@
}
if (status == PSA_SUCCESS) {
- status = psa_cipher_finish(&ctx->operation, c + out_sz, sizeof(mlen) - out_sz, &f_sz);
+ status = psa_cipher_finish(&ctx->operation, c + out_sz, mlen - out_sz, &f_sz);
}
if ((status != PSA_SUCCESS) || ((out_sz + f_sz) != mlen)) {
@@ -168,7 +168,7 @@
}
if (status == PSA_SUCCESS) {
- status = psa_cipher_finish(&ctx->operation, m + out_sz, sizeof(clen) - out_sz, &f_sz);
+ status = psa_cipher_finish(&ctx->operation, m + out_sz, clen - out_sz, &f_sz);
}
if ((status != PSA_SUCCESS) || ((out_sz + f_sz) != clen)) {
diff --git a/boot/bootutil/include/bootutil/security_cnt.h b/boot/bootutil/include/bootutil/security_cnt.h
index 515041e..d66c296 100644
--- a/boot/bootutil/include/bootutil/security_cnt.h
+++ b/boot/bootutil/include/bootutil/security_cnt.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2019-2020, Arm Limited. All rights reserved.
- * Copyright (c) 2021 Infineon Technologies AG
+ * Copyright (c) 2025 Infineon Technologies AG
*
* SPDX-License-Identifier: Apache-2.0
*/
diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h
index 04c61f9..97841c3 100644
--- a/boot/bootutil/src/bootutil_priv.h
+++ b/boot/bootutil/src/bootutil_priv.h
@@ -266,6 +266,7 @@
#elif defined(MCUBOOT_DIRECT_XIP_REVERT)
/* Swap status for the active slot */
struct boot_swap_state swap_state;
+ bool slot_validated[BOOT_NUM_SLOTS];
#endif
} slot_usage[BOOT_IMAGE_NUMBER];
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
@@ -290,6 +291,9 @@
int boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
uint8_t image_num);
int boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size);
+int boot_write_image_inv(const struct flash_area *fap);
+int boot_read_copy_done(const struct flash_area *fap, uint8_t *copy_done);
+int boot_read_image_inactive(const struct flash_area *fap, uint8_t *image_inactive);
int boot_write_trailer(const struct flash_area *fap, uint32_t off,
const uint8_t *inbuf, uint8_t inlen);
int boot_write_trailer_flag(const struct flash_area *fap, uint32_t off,
diff --git a/boot/bootutil/src/bootutil_public.c b/boot/bootutil/src/bootutil_public.c
index 38b2bd1..c1af9a5 100644
--- a/boot/bootutil/src/bootutil_public.c
+++ b/boot/bootutil/src/bootutil_public.c
@@ -143,7 +143,7 @@
}
#endif /* !MCUBOOT_SWAP_USING_STATUS */
-static int
+int
boot_flag_decode(uint8_t flag)
{
if (flag != BOOT_FLAG_SET) {
@@ -160,7 +160,7 @@
return ALIGN_DOWN(boot_magic_off(fap) - BOOT_MAX_ALIGN, BOOT_MAX_ALIGN);
}
-static inline uint32_t
+uint32_t
boot_copy_done_off(const struct flash_area *fap)
{
return boot_image_ok_off(fap) - BOOT_MAX_ALIGN;
@@ -171,6 +171,13 @@
{
return boot_copy_done_off(fap) - BOOT_MAX_ALIGN;
}
+
+uint32_t
+boot_image_inactive_off(const struct flash_area *fap)
+{
+ return boot_swap_info_off(fap) - BOOT_MAX_ALIGN;
+}
+
#endif /* !MCUBOOT_SWAP_USING_STATUS */
/**
@@ -232,16 +239,35 @@
static int
boot_read_flag(const struct flash_area *fap, uint8_t *flag, uint32_t off)
{
+ uint8_t buf[BOOT_MAX_ALIGN];
int rc;
- rc = flash_area_read(fap, off, flag, sizeof *flag);
+ rc = flash_area_read(fap, off, buf, BOOT_MAX_ALIGN);
+
if (rc != 0) {
return BOOT_EFLASH;
}
- if (*flag == flash_area_erased_val(fap)) {
+
+ if (bootutil_buffer_is_erased(fap, buf, BOOT_MAX_ALIGN))
+ {
*flag = BOOT_FLAG_UNSET;
- } else {
- *flag = boot_flag_decode(*flag);
+ }
+ else
+ {
+ bool erased = bootutil_buffer_is_erased(fap, buf+1U, BOOT_MAX_ALIGN-1U);
+
+ if ((*buf == BOOT_FLAG_SET) && erased)
+ {
+ *flag = BOOT_FLAG_SET;
+ }
+ else if ((*buf != BOOT_FLAG_SET) && erased)
+ {
+ *flag = BOOT_FLAG_BAD;
+ }
+ else
+ {
+ *flag = BOOT_FLAG_UNSET;
+ }
}
return 0;
@@ -249,12 +275,27 @@
#ifndef MCUBOOT_SWAP_USING_STATUS
-static inline int
+int
boot_read_copy_done(const struct flash_area *fap, uint8_t *copy_done)
{
return boot_read_flag(fap, copy_done, boot_copy_done_off(fap));
}
+int
+boot_read_image_inactive(const struct flash_area *fap, uint8_t *image_inactive)
+{
+ return boot_read_flag(fap, image_inactive, boot_image_inactive_off(fap));
+}
+
+int
+boot_write_image_inv(const struct flash_area *fap)
+{
+ uint32_t off;
+
+ off = boot_image_inactive_off(fap);
+
+ return boot_write_trailer_flag(fap, off, BOOT_FLAG_SET);
+}
int
boot_read_swap_state(const struct flash_area *fap,
@@ -297,6 +338,13 @@
return BOOT_EFLASH;
}
+#if defined(MCUBOOT_DIRECT_XIP)
+ rc = boot_read_image_inactive(fap, &state->image_inactive);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+#endif
+
return boot_read_image_ok(fap, &state->image_ok);
}
@@ -406,14 +454,8 @@
uint8_t erased_val;
uint32_t align;
int rc;
-
- align = flash_area_align(fap);
-
- if (align == 0u) {
- return BOOT_EFLASH;
- }
- align = ALIGN_UP(inlen, align);
+ align = ALIGN_UP(inlen, BOOT_MAX_ALIGN);
if (align > BOOT_MAX_ALIGN) {
return -1;
}
diff --git a/boot/bootutil/src/crc32c.c b/boot/bootutil/src/crc32c.c
index d298a1f..dd0ccb2 100644
--- a/boot/bootutil/src/crc32c.c
+++ b/boot/bootutil/src/crc32c.c
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
- * Copyright (c) 2020 Cypress Semiconductors
+ * Copyright (c) 2025 Cypress Semiconductors
*
* Original license:
*
diff --git a/boot/bootutil/src/crc32c.h b/boot/bootutil/src/crc32c.h
index 3a45663..ca48dd7 100644
--- a/boot/bootutil/src/crc32c.h
+++ b/boot/bootutil/src/crc32c.h
@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
- * Copyright (c) 2020 Cypress Semiconductors
+ * Copyright (c) 2025 Cypress Semiconductors
*
* Original license:
*
diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c
index 6d37ecb..322d71b 100644
--- a/boot/bootutil/src/encrypted.c
+++ b/boot/bootutil/src/encrypted.c
@@ -202,12 +202,12 @@
}
#if !defined(MCUBOOT_USE_PSA_CRYPTO)
- if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 ||
- memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
+ if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
+ memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -6;
}
- if (param.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 ||
- memcmp(param.MBEDTLS_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
+ if (param.len != sizeof(ec_secp256r1_oid) - 1 ||
+ memcmp(param.p, ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
return -7;
}
#endif
@@ -283,8 +283,8 @@
}
#if !defined(MCUBOOT_USE_PSA_CRYPTO)
- if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 ||
- memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
+ if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
+ memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -5;
}
#endif
diff --git a/boot/bootutil/src/image_ec256.c b/boot/bootutil/src/image_ec256.c
index 4d67063..07172e6 100644
--- a/boot/bootutil/src/image_ec256.c
+++ b/boot/bootutil/src/image_ec256.c
@@ -70,33 +70,35 @@
if (mbedtls_asn1_get_alg(p, end, &alg, ¶m)) {
return -2;
}
- if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 ||
- memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
+
+ else if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
+ memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -3;
}
- if (param.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 ||
- memcmp(param.MBEDTLS_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
+
+ else if (param.len != sizeof(ec_secp256r1_oid) - 1 ||
+ memcmp(param.p, ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
return -4;
}
- if (mbedtls_ecp_group_load(&ctx->MBEDTLS_CONTEXT_MEMBER(grp), MBEDTLS_ECP_DP_SECP256R1)) {
+ else if (mbedtls_ecp_group_load(&ctx->MBEDTLS_CONTEXT_MEMBER(grp), MBEDTLS_ECP_DP_SECP256R1)) {
return -5;
}
- if (mbedtls_asn1_get_bitstring_null(p, end, &len)) {
+ else if (mbedtls_asn1_get_bitstring_null(p, end, &len)) {
return -6;
}
- if (*p + len != end) {
+ else if (*p + len != end) {
return -7;
}
- if (mbedtls_ecp_point_read_binary(&ctx->MBEDTLS_CONTEXT_MEMBER(grp),
+ else if (mbedtls_ecp_point_read_binary(&ctx->MBEDTLS_CONTEXT_MEMBER(grp),
&ctx->MBEDTLS_CONTEXT_MEMBER(Q),
*p, end - *p)) {
return -8;
}
- if (mbedtls_ecp_check_pubkey(&ctx->MBEDTLS_CONTEXT_MEMBER(grp),
+ else if (mbedtls_ecp_check_pubkey(&ctx->MBEDTLS_CONTEXT_MEMBER(grp),
&ctx->MBEDTLS_CONTEXT_MEMBER(Q))) {
return -9;
}
@@ -120,17 +122,28 @@
if (mbedtls_asn1_get_alg(cp, end, &alg, ¶m)) {
return -2;
}
-
- if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_pubkey_oid) - 1 ||
- memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
+#ifdef PSE84
+ /* id-ecPublicKey (RFC5480) */
+ if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
+ memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
return -3;
}
/* namedCurve (RFC5480) */
- if (param.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ec_secp256r1_oid) - 1 ||
- memcmp(param.MBEDTLS_CONTEXT_MEMBER(p), ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
+ if (param.len != sizeof(ec_secp256r1_oid) - 1 ||
+ memcmp(param.p, ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
return -4;
}
-
+#else
+ if (alg.len != sizeof(ec_pubkey_oid) - 1 ||
+ memcmp(alg.p, ec_pubkey_oid, sizeof(ec_pubkey_oid) - 1)) {
+ return -3;
+ }
+ /* namedCurve (RFC5480) */
+ if (param.len != sizeof(ec_secp256r1_oid) - 1 ||
+ memcmp(param.p, ec_secp256r1_oid, sizeof(ec_secp256r1_oid) - 1)) {
+ return -4;
+ }
+#endif
/* ECPoint (RFC5480) */
if (mbedtls_asn1_get_bitstring_null(cp, end, &len)) {
return -6;
diff --git a/boot/bootutil/src/image_ed25519.c b/boot/bootutil/src/image_ed25519.c
index 47fd5ba..2eb2774 100644
--- a/boot/bootutil/src/image_ed25519.c
+++ b/boot/bootutil/src/image_ed25519.c
@@ -45,8 +45,8 @@
return -2;
}
- if (alg.MBEDTLS_CONTEXT_MEMBER(len) != sizeof(ed25519_pubkey_oid) - 1 ||
- memcmp(alg.MBEDTLS_CONTEXT_MEMBER(p), ed25519_pubkey_oid, sizeof(ed25519_pubkey_oid) - 1)) {
+ if (alg.len != sizeof(ed25519_pubkey_oid) - 1 ||
+ memcmp(alg.p, ed25519_pubkey_oid, sizeof(ed25519_pubkey_oid) - 1)) {
return -3;
}
diff --git a/boot/bootutil/src/image_validate.c b/boot/bootutil/src/image_validate.c
index 79dc2fd..e95ce61 100644
--- a/boot/bootutil/src/image_validate.c
+++ b/boot/bootutil/src/image_validate.c
@@ -4,7 +4,7 @@
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
- * Copyright (c) 2021 Infineon Technologies AG
+ * Copyright (c) 2025 Infineon Technologies AG
*
* Original license:
*
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index ba5350e..e441b56 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -4,6 +4,7 @@
* Copyright (c) 2016-2020 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2021 Arm Limited
+ * Copyright (c) 2021-2025 Cypress Semiconductor Corporation (an Infineon company)
*
* Original license:
*
@@ -241,12 +242,11 @@
}
}
-#if !defined(MCUBOOT_DIRECT_XIP)
/*
* Compute the total size of the given image. Includes the size of
* the TLVs.
*/
-#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST) || defined(MCUBOOT_RAM_LOAD)
+#if defined(MCUBOOT_DIRECT_XIP) || !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST) || defined(MCUBOOT_RAM_LOAD)
static int
boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
{
@@ -526,7 +526,7 @@
#endif /* MCUBOOT_SWAP_USING_STATUS */
-#endif /* !MCUBOOT_DIRECT_XIP */
+
/*
* Validate image hash/signature and optionally the security counter in a slot.
@@ -558,7 +558,11 @@
/* In the case of ram loading the image has already been decrypted as it is
* decrypted when copied in ram */
#if defined(MCUBOOT_ENC_IMAGES)
+#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
+ if (MUST_DECRYPT(fap, image_index, hdr)) {
+#else
if (MUST_DECRYPT(fap, image_index, hdr) && !IS_RAM_BOOTABLE(hdr)) {
+#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
int rc = flash_area_id_to_multi_image_slot(image_index, fap->fa_id);
if (rc < 0) {
FIH_RET(fih_rc);
@@ -796,7 +800,7 @@
f_off = boot_img_slot_off(state, active_slot);
if (hdr->ih_flags & IMAGE_F_ROM_FIXED && hdr->ih_load_addr != f_off) {
- BOOT_LOG_WRN("Image in %s slot at 0x%" PRIx32
+ BOOT_LOG_DBG("Image in %s slot at 0x%" PRIx32
" has been built for offset 0x%" PRIx32 ", skipping",
active_slot == 0 ? "primary" : "secondary", f_off,
hdr->ih_load_addr);
@@ -839,7 +843,7 @@
hdr = boot_img_hdr(state, slot);
#ifdef MCUBOOT_ENC_IMAGES_XIP_MULTI
-/* In the XIP encryption multi image case if XIP encryption is turned on then
+/* In the XIP encryption multi image case if XIP encryption is turned on then
* the boot_check_header_erased() can't detect erased header correctly for the second and next images
* because erased value is not read as 0xFF.
* So, the bootloader has one option only to detect correctness of image header: it is
@@ -956,6 +960,102 @@
FIH_RET(fih_rc);
}
+/*
+ * Check that there is a valid image in a slot
+ *
+ * @returns
+ * FIH_SUCCESS if image was successfully validated
+ * 1 (or its fih_int encoded form) if no bootloable image was found
+ * FIH_FAILURE on any errors
+ */
+static fih_int
+boot_soft_validate_slot(struct boot_loader_state *state, int slot,
+ struct boot_status *bs)
+{
+ const struct flash_area *fap = NULL;
+ struct image_header *hdr;
+ int area_id;
+ fih_int fih_rc = FIH_FAILURE;
+ int rc;
+
+ area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
+ rc = flash_area_open(area_id, &fap);
+ if (rc != 0) {
+ FIH_RET(fih_rc);
+ }
+
+ BOOT_LOG_DBG("> boot_validate_slot: fa_id = %u", (unsigned)fap->fa_id);
+
+ hdr = boot_img_hdr(state, slot);
+
+ if (hdr->ih_magic != IMAGE_MAGIC) {
+ FIH_RET(fih_rc);
+ }
+
+#if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION)
+ if (slot != BOOT_PRIMARY_SLOT) {
+ /* 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 (rc < 0 && boot_check_header_erased(state, BOOT_PRIMARY_SLOT)) {
+ BOOT_LOG_ERR("insufficient version in secondary slot");
+ fih_rc = FIH_SWAP_TYPE_NONE;
+ goto out;
+ }
+ }
+#endif
+ BOOT_HOOK_CALL_FIH(boot_image_check_hook, FIH_INT_INIT(BOOT_HOOK_REGULAR),
+ fih_rc, BOOT_CURR_IMG(state), slot);
+ if (fih_eq(fih_rc, FIH_INT_INIT(BOOT_HOOK_REGULAR)))
+ {
+ FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
+ }
+ if (!boot_is_header_valid(hdr, fap) || !fih_eq(fih_rc, FIH_SUCCESS)) {
+ if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
+ BOOT_LOG_DBG(" * Image in the secondary slot is invalid.");
+ }
+#if !defined(__BOOTSIM__)
+ BOOT_LOG_DBG("Image in the %s slot is not valid!",
+ (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
+#endif
+ fih_rc = FIH_SWAP_TYPE_NONE;
+ goto out;
+ }
+
+#if MCUBOOT_IMAGE_NUMBER > 1 && !defined(MCUBOOT_ENC_IMAGES) && defined(MCUBOOT_VERIFY_IMG_ADDRESS)
+ /* Verify that the image in the secondary slot has a reset address
+ * located in the primary slot. This is done to avoid users incorrectly
+ * overwriting an application written to the incorrect slot.
+ * This feature is only supported by ARM platforms.
+ */
+ if (area_id == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
+ const struct flash_area *pri_fa = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
+ struct image_header *secondary_hdr = boot_img_hdr(state, slot);
+ uint32_t reset_value = 0;
+ uint32_t reset_addr = secondary_hdr->ih_hdr_size + sizeof(reset_value);
+
+ rc = flash_area_read(fap, reset_addr, &reset_value, sizeof(reset_value));
+ if (rc != 0) {
+ fih_rc = FIH_INT_INIT(1);
+ goto out;
+ }
+
+ if (reset_value < pri_fa->fa_off || reset_value> (pri_fa->fa_off + pri_fa->fa_size)) {
+ BOOT_LOG_ERR("Reset address of image in secondary slot is not in the primary slot");
+
+ fih_rc = FIH_INT_INIT(1);
+ goto out;
+ }
+ }
+#endif
+
+out:
+ flash_area_close(fap);
+ BOOT_LOG_DBG("< boot_validate_slot: fa_id = %u", (unsigned)fap->fa_id);
+ FIH_RET(fih_rc);
+}
+
#ifdef MCUBOOT_HW_ROLLBACK_PROT
/**
* Updates the stored security counter value with the image's security counter
@@ -1579,7 +1679,7 @@
switch (BOOT_SWAP_TYPE(state)) {
case BOOT_SWAP_TYPE_TEST:
case BOOT_SWAP_TYPE_PERM:
- /* BOOT_SWAP_TYPE_NONE has been changed to BOOT_SWAP_TYPE_FAIL to avoid
+ /* BOOT_SWAP_TYPE_NONE has been changed to BOOT_SWAP_TYPE_FAIL to avoid
* reversion again after device reset */
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
break;
@@ -1713,9 +1813,9 @@
*/
for (int idx = 0; idx < BOOT_IMAGE_NUMBER; idx++) {
BOOT_CURR_IMG(state) = idx;
- /*When dependency is not satisfied, the boot_verify_slot_dependencies_flash
+ /*When dependency is not satisfied, the boot_verify_slot_dependencies_flash
changes swap type to BOOT_SWAP_TYPE_REVERT to have ability of reversion of a
- dependent image. That's why BOOT_SWAP_TYPE_REVERT must not be changed to
+ dependent image. That's why BOOT_SWAP_TYPE_REVERT must not be changed to
BOOT_SWAP_TYPE_NONE */
if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_REVERT) {
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
@@ -2249,7 +2349,19 @@
continue;
}
#endif
+#else
+ /* Dependency is set and encryption is enabled. In this case we cannot
+ * reread the first image header because it is encrypted
+ */
+#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
+#if BOOT_IMAGE_NUMBER > 1
+ if ((BOOT_CURR_IMG(state) == 0) && (state->img_mask[BOOT_CURR_IMG(state)] == true)) {
+ continue;
+ }
#endif
+#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
+#endif /* !defined(MCUBOOT_DEPENDENCY_CHECK) */
+
#if defined(MCUBOOT_ENC_IMAGES) && (BOOT_IMAGE_NUMBER > 1)
/* The keys used for encryption may no longer be valid (could belong to
* another images). Therefore, mark them as invalid to force their reload
@@ -2410,7 +2522,11 @@
#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
#if defined(MCUBOOT_RAM_LOAD) /* to fix Rule 14.3 violation */
+#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
+ if (true) {
+#else
if(IS_RAM_BOOTABLE(boot_img_hdr(state, BOOT_PRIMARY_SLOT)) == false) {
+#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
#endif /* defined(MCUBOOT_RAM_LOAD) */
FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, &bs);
if (!fih_eq(fih_rc, FIH_SUCCESS)) {
@@ -2598,8 +2714,18 @@
assert(rc == 0);
}
+#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
+ if (BOOT_CURR_IMG(state) == 0) {
+ SMIF_SET_CRYPTO_MODE(Disable);
+ }
+#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
/* Attempt to read an image header from each slot. */
rc = boot_read_image_headers(state, false, NULL);
+#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
+ if (BOOT_CURR_IMG(state) == 0) {
+ SMIF_SET_CRYPTO_MODE(Enable);
+ }
+#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
if (rc != 0) {
BOOT_LOG_WRN("Failed reading image headers.");
return rc;
@@ -2698,6 +2824,28 @@
#endif
#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
+static int
+boot_get_swap_state(struct boot_loader_state *state, uint32_t active_slot, struct boot_swap_state* active_swap_state)
+{
+ (void)state;
+ int rc = -1;
+
+ const struct flash_area *fap;
+ int fa_id;
+
+ fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
+ rc = flash_area_open(fa_id, &fap);
+
+ if (rc == 0)
+ {
+ (void)memset(active_swap_state, 0, sizeof(struct boot_swap_state));
+
+ rc = boot_read_swap_state(fap, active_swap_state);
+ }
+
+ return rc;
+}
+
/**
* Checks whether the active slot of the current image was previously selected
* to run. Erases the image if it was selected but its execution failed,
@@ -2720,52 +2868,67 @@
fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
rc = flash_area_open(fa_id, &fap);
- assert(rc == 0);
active_swap_state = &(state->slot_usage[BOOT_CURR_IMG(state)].swap_state);
(void)memset(active_swap_state, 0, sizeof(struct boot_swap_state));
rc = boot_read_swap_state(fap, active_swap_state);
- assert(rc == 0);
- if (active_swap_state->magic != BOOT_MAGIC_GOOD ||
- (active_swap_state->copy_done == BOOT_FLAG_SET &&
- active_swap_state->image_ok != BOOT_FLAG_SET)) {
+ if ((active_swap_state->copy_done == BOOT_FLAG_SET &&
+ active_swap_state->image_ok != BOOT_FLAG_SET)) {
/*
- * A reboot happened without the image being confirmed at
- * runtime or its trailer is corrupted/invalid. Erase the image
- * to prevent it from being selected again on the next reboot.
- */
+ * A reboot happened without the image being confirmed at
+ * runtime or its trailer is corrupted/invalid. Erase the image
+ * to prevent it from being selected again on the next reboot.
+ */
BOOT_LOG_DBG("Erasing faulty image in the %s slot.",
- (active_slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
+ (active_slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
rc = flash_area_erase(fap, 0, flash_area_get_size(fap));
assert(rc == 0);
- flash_area_close(fap);
rc = -1;
} else {
- if (active_swap_state->copy_done != BOOT_FLAG_SET) {
- if (active_swap_state->copy_done == BOOT_FLAG_BAD) {
- BOOT_LOG_DBG("The copy_done flag had an unexpected value. Its "
- "value was neither 'set' nor 'unset', but 'bad'.");
- }
- /*
- * Set the copy_done flag, indicating that the image has been
- * selected to boot. It can be set in advance, before even
- * validating the image, because in case the validation fails, the
- * entire image slot will be erased (including the trailer).
- */
- rc = boot_write_copy_done(fap);
- if (rc != 0) {
- BOOT_LOG_WRN("Failed to set copy_done flag of the image in "
- "the %s slot.", (active_slot == BOOT_PRIMARY_SLOT) ?
- "primary" : "secondary");
- rc = 0;
+ struct image_header *hdr = boot_img_hdr(state, active_slot);
+
+ if (boot_is_header_valid(hdr, fap))
+ {
+ if (active_swap_state->copy_done != BOOT_FLAG_SET) {
+ if (active_swap_state->copy_done == BOOT_FLAG_BAD) {
+ BOOT_LOG_DBG("The copy_done flag had an unexpected value. Its "
+ "value was neither 'set' nor 'unset', but 'bad'.");
+ }
+
+ bool img_ok = (active_swap_state->image_ok == BOOT_FLAG_SET);
+
+ uint32_t off = flash_area_get_size(fap) - BOOT_MAX_ALIGN;
+
+ flash_area_erase(fap, off, BOOT_MAX_ALIGN);
+
+ /*
+ * Set the copy_done flag, indicating that the image has been
+ * selected to boot. It can be set in advance, before even
+ * validating the image, because in case the validation fails, the
+ * entire image slot will be erased (including the trailer).
+ */
+ rc = boot_write_copy_done(fap);
+
+ rc |= boot_write_magic(fap);
+
+ if (img_ok) {
+ rc |= boot_write_image_ok(fap);
+ }
+
+ if (rc != 0) {
+ BOOT_LOG_WRN("Failed to set copy_done flag of the image in "
+ "the %s slot.", (active_slot == BOOT_PRIMARY_SLOT) ?
+ "primary" : "secondary");
+ rc = 0;
+ }
}
}
- flash_area_close(fap);
}
-
+
+ flash_area_close(fap);
return rc;
}
#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */
@@ -2855,19 +3018,21 @@
* 4. The image is authenticated in RAM.
*/
const struct flash_area *fap_src = NULL;
+ uint32_t tlv_off;
+ int area_id;
+ int rc;
+ uint8_t image_index;
+ uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst);
+#if !defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
struct boot_status bs;
uint32_t blk_off;
- uint32_t tlv_off;
uint32_t blk_sz;
uint32_t bytes_copied = hdr->ih_hdr_size;
uint32_t chunk_sz;
uint32_t max_sz = 1024;
uint16_t idx;
- uint8_t image_index;
uint8_t * cur_dst;
- int area_id;
- int rc;
- uint8_t * ram_dst = (void *)(IMAGE_RAM_BASE + img_dst);
+#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
image_index = BOOT_CURR_IMG(state);
area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
@@ -2883,7 +3048,7 @@
if (rc != 0) {
goto done;
}
-
+#if !defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap_src, &bs);
if (rc < 0) {
goto done;
@@ -2923,6 +3088,25 @@
bytes_copied += chunk_sz;
}
+#else
+ (void)image_index;
+ /* Special case for the first image because header and TLV are not encrypted */
+ SMIF_CRYPTO_SECTION(Disable) {
+ /* Copy header to RAM */
+ rc = flash_area_read(fap_src, 0, ram_dst, hdr->ih_hdr_size);
+ }
+ if (0 != rc) {
+ goto done;
+ }
+
+ SMIF_CRYPTO_SECTION(Disable) {
+ /* Copy TLV ro RAM */
+ rc = flash_area_read(fap_src, tlv_off, ram_dst + tlv_off, src_sz - tlv_off);
+ }
+ if (0 != rc) {
+ goto done;
+ }
+#endif /* !defined(MCUBOOT_ENC_IMAGES_XIP_MULTI) */
rc = 0;
done:
@@ -3067,7 +3251,17 @@
img_dst = hdr->ih_load_addr;
+#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
+ if (BOOT_CURR_IMG(state) == 0) {
+ SMIF_SET_CRYPTO_MODE(Disable);
+ }
+#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
rc = boot_read_image_size(state, active_slot, &img_sz);
+#if defined(MCUBOOT_ENC_IMAGES_XIP_MULTI)
+ if (BOOT_CURR_IMG(state) == 0) {
+ SMIF_SET_CRYPTO_MODE(Enable);
+ }
+#endif /* MCUBOOT_ENC_IMAGES_XIP_MULTI */
if (rc != 0) {
return rc;
}
@@ -3174,6 +3368,51 @@
return rc;
}
+
+/**
+ * Switch to image in SRAM
+ *
+ * @param state Boot loader status information.
+ * @param slot The flash slot of the image to be erased.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static inline int
+boot_switch_to_sram_image(struct boot_loader_state *state, uint32_t slot)
+{
+ int area_id = -1;
+ int rc = -1;
+ struct flash_area *fap = NULL;
+ struct image_header *hdr = NULL;
+
+ (void)state;
+
+ hdr = boot_img_hdr(state, slot);
+ BOOT_LOG_INF("Image %u slot %" PRIu32 " switch to SRAM",
+ (unsigned)BOOT_CURR_IMG(state), slot);
+ area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
+ rc = flash_area_open(area_id, (const struct flash_area **)&fap);
+
+ if (rc == 0) {
+ /* Switch to image SRAM */
+
+ if (IS_RAM_BOOTABLE_SECURE(hdr)) {
+ fap->fa_device_id = INTERNAL_S_SRAM;
+ }
+ else {
+ fap->fa_device_id = INTERNAL_NS_SRAM;
+ }
+
+ if (hdr->ih_load_addr < flash_devices[fap->fa_device_id].address) {
+ return -1;
+ }
+ fap->fa_off = hdr->ih_load_addr - flash_devices[fap->fa_device_id].address;
+ /* Image is already decrepted, so clear encrypted flags in the header */
+ CLEAR_ENCRYPT_FLAGS(hdr);
+ }
+
+ return rc;
+}
#endif /* MCUBOOT_RAM_LOAD */
#if (BOOT_IMAGE_NUMBER > 1)
@@ -3323,6 +3562,141 @@
#endif /* (MCUBOOT_DEPENDENCY_CHECK) */
#endif /* (BOOT_IMAGE_NUMBER > 1) */
+static const uint8_t slot_table[] = {BOOT_PRIMARY_SLOT, BOOT_SECONDARY_SLOT};
+
+/**
+ * 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_int
+boot_load_and_validate_images_xip(struct boot_loader_state *state)
+{
+ uint32_t active_slot = NO_ACTIVE_SLOT;
+ int rc = -1;
+ fih_int fih_rc = FIH_FAILURE;
+
+ struct boot_swap_state swap_state[BOOT_NUM_SLOTS];
+
+ /* Go over all the images and try to load one */
+ IMAGES_ITER(BOOT_CURR_IMG(state))
+ {
+#if BOOT_IMAGE_NUMBER > 1
+ if (state->img_mask[BOOT_CURR_IMG(state)]) {
+ continue;
+ }
+#endif
+
+ for (uint32_t i = 0; i < BOOT_NUM_SLOTS; i++) {
+ active_slot = slot_table[i];
+
+ /* Save the number of the active slot. */
+ state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
+
+ 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[active_slot] = false;
+ state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
+ continue;
+ }
+
+
+ rc = boot_get_swap_state(state, active_slot, &swap_state[i]);
+
+ if (rc == 0) {
+ /* Proceed with inactive state */
+ if (swap_state[i].image_inactive == BOOT_FLAG_SET) {
+ state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
+ state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
+
+
+ if (swap_state[i].copy_done == BOOT_FLAG_SET && swap_state[i].image_ok == BOOT_FLAG_SET)
+ {
+ state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[active_slot] = true;
+ }
+ else
+ {
+ FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
+ if (fih_eq(fih_rc, FIH_SUCCESS)) {
+ state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[active_slot] = true;
+ }
+ }
+ continue;
+
+ } else {
+ /* Proceed with revert state */
+ if (boot_select_or_erase(state) != 0) {
+ /* The selected image slot has been erased. */
+ state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
+ state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
+ continue;
+ }
+ }
+ }
+ }
+
+ active_slot = NO_ACTIVE_SLOT;
+
+ for (int i = 0; i < BOOT_NUM_SLOTS; i++) {
+ if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[i] == true) {
+ if (swap_state[i].copy_done == BOOT_FLAG_UNSET)
+ {
+ active_slot = i;
+ break;
+ }
+ }
+ }
+
+ if (active_slot == NO_ACTIVE_SLOT)
+ {
+ active_slot = find_slot_with_highest_version(state);
+ }
+
+ if (active_slot != NO_ACTIVE_SLOT)
+ {
+ #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
+ FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
+ #else
+ fih_rc = FIH_SUCCESS;
+ #endif
+
+ if (fih_eq(fih_rc, FIH_SUCCESS)) {
+ state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[active_slot] = true;
+ state->slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
+ }
+ }
+ else
+ {
+ bool dead_state = true;
+ for (int i = 0; i < BOOT_NUM_SLOTS; i++) {
+ if (state->slot_usage[BOOT_CURR_IMG(state)].slot_available[i] == false) {
+ dead_state = false;
+ break;
+ }
+ }
+
+ if (dead_state == false) {
+ for (int i = 0; i < BOOT_NUM_SLOTS; i++) {
+ if (state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[i] == true) {
+ state->slot_usage[BOOT_CURR_IMG(state)].slot_available[i] = true;
+ state->slot_usage[BOOT_CURR_IMG(state)].active_slot = i;
+
+ fih_rc = FIH_SUCCESS;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ FIH_RET(fih_rc);
+}
+
/**
* Tries to load a slot for all the images with validation.
*
@@ -3335,9 +3709,7 @@
{
uint32_t active_slot;
int rc;
-#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
fih_int fih_rc = FIH_FAILURE;
-#endif
/* Go over all the images and try to load one */
IMAGES_ITER(BOOT_CURR_IMG(state)) {
@@ -3351,7 +3723,7 @@
/* A slot is already active, go to next image. */
break;
}
-
+
/* Ram load assumes to find the highest version of available slots
* and load it. Also dependency check feature verifies version
* of first slot of dependent image and assumes to load from the
@@ -3400,6 +3772,12 @@
/* The selected image slot has been erased. */
state->slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
state->slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
+
+ FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
+ if (fih_eq(fih_rc, FIH_SUCCESS)) {
+ state->slot_usage[BOOT_CURR_IMG(state)].slot_validated[active_slot] = true;
+ }
+
continue;
}
#endif /* MCUBOOT_DIRECT_XIP_REVERT */
@@ -3423,9 +3801,14 @@
(unsigned)BOOT_CURR_IMG(state));
FIH_RET(FIH_FAILURE);
}
+
+ if (boot_switch_to_sram_image(state, active_slot) != 0) {
+ FIH_RET(FIH_FAILURE);
+ }
#endif /* MCUBOOT_RAM_LOAD */
#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
+
if (!fih_eq(fih_rc, FIH_SUCCESS)) {
/* Image is invalid. */
#ifdef MCUBOOT_RAM_LOAD
@@ -3436,10 +3819,10 @@
/* Since active_slot is set BOOT_PRIMARY_SLOT only, then after its deletion
* no sense to check BOOT_SECONDARY_SLOT. So go outside with an error */
BOOT_LOG_ERR("BOOT slot of image %u has been removed from SRAM",
- (unsigned)BOOT_CURR_IMG(state));
+ (unsigned)BOOT_CURR_IMG(state));
FIH_RET(FIH_FAILURE);
}
-#endif
+#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
/* Valid image loaded from a slot, go to next image. */
break;
}
@@ -3508,7 +3891,12 @@
#if (BOOT_IMAGE_NUMBER > 1)
while (true) {
#endif
+
+#if defined(MCUBOOT_DIRECT_XIP)
+ FIH_CALL(boot_load_and_validate_images_xip, fih_rc, state);
+#else
FIH_CALL(boot_load_and_validate_images, fih_rc, state);
+#endif
if (!fih_eq(fih_rc, FIH_SUCCESS)) {
goto out;
}
@@ -3580,7 +3968,11 @@
boot_state_clear(NULL);
+#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
+ FIH_CALL(context_boot_go_ram, fih_rc, &boot_data, rsp);
+#else
FIH_CALL(context_boot_go_flash, fih_rc, &boot_data, rsp);
+#endif
FIH_RET(fih_rc);
}
@@ -3613,7 +4005,7 @@
FIH_RET(fih_rc);
}
-#if defined(MCUBOOT_RAM_LOAD)
+#if defined(MCUBOOT_RAM_LOAD) || defined(MCUBOOT_DIRECT_XIP)
/**
* Prepares the booting process, considering only a single image. This function
* moves images around in flash as appropriate, and tells you what address to
@@ -3661,3 +4053,343 @@
(void)memset(&boot_data, 0, sizeof(struct boot_loader_state));
}
}
+
+fih_int
+context_validate_slot_flash(struct boot_loader_state *state, int image_slot)
+{
+ fih_int fih_rc = FIH_FAILURE;
+
+ struct boot_status bs = {0};
+ int rc = boot_read_image_headers(state, false, &bs);
+
+ if (rc == 0) {
+ FIH_CALL(boot_soft_validate_slot, fih_rc, state, image_slot, &bs);
+ }
+
+ FIH_RET(fih_rc);
+}
+
+/**
+ * Prepares the booting process, considering only a single image. This function
+ * moves images around in flash as appropriate, and tells you what address to
+ * boot from.
+ *
+ * @param rsp On success, indicates how booting should occur.
+ *
+ * @param image_id The image ID to prepare the boot process for.
+ *
+ * @return FIH_SUCCESS on success; nonzero on failure.
+ */
+fih_int
+boot_validate_slot_for_image_id(uint32_t image_id, uint32_t slot_id)
+{
+ fih_int fih_rc = FIH_FAILURE;
+
+ if (image_id >= BOOT_IMAGE_NUMBER) {
+ FIH_RET(FIH_FAILURE);
+ }
+
+#if BOOT_IMAGE_NUMBER > 1
+ (void)memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
+ boot_data.img_mask[image_id] = 0;
+#endif
+
+ FIH_CALL(context_validate_slot_flash, fih_rc, &boot_data, slot_id);
+ FIH_RET(fih_rc);
+}
+
+int boot_get_image_version(uint32_t image_id, uint32_t slot_id, struct image_version *image_version)
+{
+ int rc = -1;
+ struct boot_status bs = {0};
+
+ if (image_id < BOOT_IMAGE_NUMBER) {
+#if BOOT_IMAGE_NUMBER > 1
+ (void)memset(&boot_data.img_mask, 1, BOOT_IMAGE_NUMBER);
+ boot_data.img_mask[image_id] = 0;
+#endif
+
+ if (boot_read_image_headers(&boot_data, false, &bs) == 0) {
+ struct image_header *hdr = boot_img_hdr(&boot_data, slot_id);
+
+ if (hdr->ih_magic == IMAGE_MAGIC) {
+ *image_version = hdr->ih_ver;
+ rc = 0;
+ } else {
+ /* Image magic is not valid - fill with flash area erase value */
+ const struct flash_area *fa = BOOT_IMG_AREA(&boot_data, slot_id);
+ memset(image_version, flash_area_erased_val(fa), sizeof(struct image_version));
+ }
+ }
+ }
+ return rc;
+}
+
+#if defined(MCUBOOT_DIRECT_XIP)
+
+int boot_read_image_header(struct boot_loader_state *state, int slot,
+ struct image_header *out_hdr, struct boot_status *bs)
+{
+ (void) bs;
+ (void) state;
+ const struct flash_area *fap = NULL;
+ int rc = -1;
+ int area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
+
+ do {
+ rc = flash_area_open(area_id, &fap);
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ break;
+ }
+
+ rc = flash_area_read(fap, 0, out_hdr, sizeof *out_hdr);
+ if (rc < 0) {
+ rc = BOOT_EFLASH;
+ break;
+ }
+
+ flash_area_close(fap);
+ } while (false);
+
+ return rc;
+}
+
+int
+boot_set_inactive_slot(uint32_t image_id, uint32_t slot_id)
+{
+ const struct flash_area *fap = NULL;
+ int fa_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
+ int rc = flash_area_open(fa_id, &fap);
+
+ if (rc == 0)
+ {
+ rc = boot_write_image_inv(fap);
+ }
+ flash_area_close(fap);
+
+ return rc;
+}
+
+static
+int boot_read_slot_flag(uint32_t image_id, uint32_t slot_id, int (* fn)(const struct flash_area *, uint8_t *))
+{
+ uint8_t flag = 0U;
+ const struct flash_area *fap = NULL;
+ int fa_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
+ int rc = flash_area_open(fa_id, &fap);
+
+ if (rc == 0)
+ {
+ rc = fn(fap, &flag);
+ }
+
+ if (rc == 0)
+ {
+ rc = -1;
+
+ if (flag == BOOT_FLAG_SET)
+ {
+ rc = 1;
+ }
+ else
+ {
+ rc = 0;
+ }
+ }
+
+ flash_area_close(fap);
+
+ return rc;
+}
+
+int
+boot_is_slot_inactive(uint32_t image_id, uint32_t slot_id)
+{
+ int rc = boot_read_slot_flag(image_id, slot_id, &boot_read_image_inactive);
+
+ return rc;
+}
+
+int
+boot_is_slot_booted(uint32_t image_id, uint32_t slot_id)
+{
+ int rc = boot_read_slot_flag(image_id, slot_id, &boot_read_copy_done);
+
+ return rc;
+}
+
+int
+boot_is_slot_confirmed(uint32_t image_id, uint32_t slot_id)
+{
+ int rc = boot_read_slot_flag(image_id, slot_id, &boot_read_image_ok);
+
+ return rc;
+}
+
+int
+boot_set_pending_slot(uint32_t image_id, uint32_t slot_id)
+{
+ const struct flash_area *fap = NULL;
+ int fa_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
+ int rc = flash_area_open(fa_id, &fap);
+
+ uint32_t off;
+
+ off = boot_image_inactive_off(fap);
+
+ if (rc == 0)
+ {
+ rc = flash_area_erase(fap, off, BOOT_MAX_ALIGN);
+ }
+ flash_area_close(fap);
+
+ return rc;
+}
+
+int
+boot_set_revert_slot(uint32_t image_id, uint32_t slot_id)
+{
+ int rc = boot_set_pending_slot(image_id, slot_id);
+
+ if (rc == 0)
+ {
+ const struct flash_area *fap = NULL;
+ int fa_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
+
+ rc = flash_area_open(fa_id, &fap);
+
+ if (rc == 0)
+ {
+ rc = boot_write_copy_done(fap);
+ }
+
+ flash_area_close(fap);
+ }
+
+ return rc;
+}
+
+int
+boot_find_image_tlv_info(uint32_t image_id, uint32_t slot_id, uint16_t type, uint16_t* len, uint32_t* off)
+{
+ struct boot_loader_state *state = &boot_data;
+ struct boot_status bs = {0};
+ struct image_tlv_iter it = {0};
+ int rc = -1;
+
+ if (image_id < BOOT_IMAGE_NUMBER) {
+#if BOOT_IMAGE_NUMBER > 1
+ (void)memset(state->img_mask, 1, BOOT_IMAGE_NUMBER);
+ state->img_mask[image_id] = 0;
+#endif
+ if (boot_read_image_headers(state, false, &bs) == 0) {
+ int area_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
+ struct image_header* hdr = boot_img_hdr(state, slot_id);
+ const struct flash_area *fap = NULL;
+
+ rc = flash_area_open(area_id, &fap);
+
+ if (rc == 0)
+ {
+ rc = bootutil_tlv_iter_begin(&it, hdr, fap, type, false);
+ }
+
+ if (rc == 0)
+ {
+ rc = bootutil_tlv_iter_next(&it, off, len, NULL);
+ }
+
+ flash_area_close(fap);
+ }
+ }
+
+ return rc;
+}
+
+int boot_read_image_tlv_value(uint32_t image_id, uint32_t slot_id, uint16_t type, uint8_t *buf, uint32_t buf_len, uint32_t *read_len)
+{
+ int rc = -1;
+
+ uint16_t tlv_len = 0;
+ uint32_t tlv_off = 0;
+ uint32_t tmp_len = 0;
+
+ if (buf != NULL && buf_len > 0U) {
+ rc = boot_find_image_tlv_info(image_id, slot_id, type, &tlv_len, &tlv_off);
+
+ if (rc == 0) {
+ int area_id = flash_area_id_from_multi_image_slot(image_id, slot_id);
+ const struct flash_area *fap = NULL;
+
+ tmp_len = tlv_len;
+
+ if (tlv_len > buf_len) {
+ tmp_len = buf_len;
+ }
+
+ rc = flash_area_open(area_id, &fap);
+
+ if (rc == 0) {
+ rc = flash_area_read(fap, tlv_off, buf, tmp_len);
+ }
+
+ if (rc == 0) {
+ if (read_len != NULL) {
+ *read_len = tmp_len;
+ }
+ }
+
+ flash_area_close(fap);
+ }
+ }
+
+ return rc;
+}
+
+int
+boot_get_slot_state(uint32_t image_id, uint32_t slot_id, boot_slot_state_t* state)
+{
+ int rc = 0;
+
+ if (boot_is_slot_inactive(image_id, slot_id) == 1)
+ {
+ *state = MCUBOOT_SLOT_STATE_INACTIVE;
+ }
+ else if ((boot_is_slot_booted(image_id, slot_id) == 1) && (boot_is_slot_confirmed(image_id, slot_id) == 0))
+ {
+ *state = MCUBOOT_SLOT_STATE_VERIFYING;
+ }
+ else if (boot_is_slot_booted(image_id, slot_id) == 0)
+ {
+ *state = MCUBOOT_SLOT_STATE_PENDING;
+ }
+ else if ((boot_is_slot_booted(image_id, slot_id) == 1) && (boot_is_slot_confirmed(image_id, slot_id) == 1))
+ {
+ *state = MCUBOOT_SLOT_STATE_ACTIVE;
+ }
+
+ return rc;
+}
+
+int
+boot_get_image_state(uint32_t image_id, uint32_t slot_id, boot_slot_state_t* state)
+{
+ int rc = -1;
+ fih_int fih_rc;
+
+ FIH_CALL(boot_validate_slot_for_image_id, fih_rc, image_id, slot_id);
+
+ if (fih_eq(fih_rc, FIH_SUCCESS)) {
+ rc = boot_get_slot_state(image_id, slot_id, state);
+ }
+ else
+ {
+ rc = 0;
+ *state = MCUBOOT_SLOT_STATE_NO_IMAGE;
+ }
+
+ return rc;
+}
+
+#endif
diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c
index 8b55d2a..000f4df 100644
--- a/boot/bootutil/src/swap_scratch.c
+++ b/boot/bootutil/src/swap_scratch.c
@@ -33,7 +33,7 @@
BOOT_LOG_MODULE_DECLARE(mcuboot);
-#ifndef MCUBOOT_SWAP_USING_MOVE
+#if !defined(MCUBOOT_SWAP_USING_MOVE) && !defined(MCUBOOT_DIRECT_XIP)
#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
/*
diff --git a/boot/bootutil/src/swap_status.c b/boot/bootutil/src/swap_status.c
index d5be7c4..5c40754 100644
--- a/boot/bootutil/src/swap_status.c
+++ b/boot/bootutil/src/swap_status.c
@@ -4,7 +4,7 @@
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
- * Copyright (c) 2020 Cypress Semiconductors
+ * Copyright (c) 2025 Cypress Semiconductors
*
* Original license:
*
diff --git a/boot/bootutil/src/swap_status.h b/boot/bootutil/src/swap_status.h
index 9cc8362..ee8ce9b 100644
--- a/boot/bootutil/src/swap_status.h
+++ b/boot/bootutil/src/swap_status.h
@@ -4,7 +4,7 @@
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
- * Copyright (c) 2020 Cypress Semiconductors
+ * Copyright (c) 2025 Cypress Semiconductors
*
* Original license:
*
diff --git a/boot/bootutil/src/swap_status_misc.c b/boot/bootutil/src/swap_status_misc.c
index 2794a6f..aecd353 100644
--- a/boot/bootutil/src/swap_status_misc.c
+++ b/boot/bootutil/src/swap_status_misc.c
@@ -4,7 +4,7 @@
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
- * Copyright (c) 2020 Cypress Semiconductors
+ * Copyright (c) 2025 Cypress Semiconductors
*
* Original license:
*
diff --git a/boot/bootutil/src/swap_status_part.c b/boot/bootutil/src/swap_status_part.c
index 6498787..da516a6 100644
--- a/boot/bootutil/src/swap_status_part.c
+++ b/boot/bootutil/src/swap_status_part.c
@@ -4,7 +4,7 @@
* Copyright (c) 2017-2019 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
* Copyright (c) 2019-2020 Arm Limited
- * Copyright (c) 2020 Cypress Semiconductors
+ * Copyright (c) 2025 Cypress Semiconductors
*
* Original license:
*