Infineon: Add cyw20829 platform, shared slot feature, json memory map, psoc6 xip
Based in 1.8.0 release of MCUBoot library
This commit adds CYW20829 Infineon platform support with following capabilities:
1. Overwrite and swap upgrade mode support
2. Multi-image with up to 4 images
3. Hardware security counter is supported for CYW20829 platform
Add XIP support for PSOC6 platform - place BOOT slot in external memory and execute it in place using SMIF in XIP mode
and some new features for Infineon devices.
1. Shared upgrade slot feature - use one shared area for upgrade slots of multiple images
2. Memory map defined using JSON file - define memory regions for bootloader and user app in conventional way using JSON file
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index e4c0a3f..7794b5a 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2016-2020 Linaro LTD
* Copyright (c) 2016-2019 JUUL Labs
- * Copyright (c) 2019-2020 Arm Limited
+ * Copyright (c) 2019-2021 Arm Limited
*
* Original license:
*
@@ -35,7 +35,6 @@
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
-#include <os/os_malloc.h>
#include "bootutil/bootutil.h"
#include "bootutil/image.h"
#include "bootutil_priv.h"
@@ -44,14 +43,20 @@
#include "bootutil/security_cnt.h"
#include "bootutil/boot_record.h"
#include "bootutil/fault_injection_hardening.h"
+#include "bootutil/ramload.h"
+#include "bootutil/boot_hooks.h"
#ifdef MCUBOOT_ENC_IMAGES
#include "bootutil/enc_key.h"
#endif
+#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
+#include <os/os_malloc.h>
+#endif
+
#include "mcuboot_config/mcuboot_config.h"
-MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
+BOOT_LOG_MODULE_DECLARE(mcuboot);
static struct boot_loader_state boot_data;
@@ -61,6 +66,22 @@
#define IMAGES_ITER(x)
#endif
+#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
+struct slot_usage_t {
+ /* Index of the slot chosen to be loaded */
+ uint32_t active_slot;
+ bool slot_available[BOOT_NUM_SLOTS];
+#if defined(MCUBOOT_RAM_LOAD)
+ /* Image destination and size for the active slot */
+ uint32_t img_dst;
+ uint32_t img_sz;
+#elif defined(MCUBOOT_DIRECT_XIP_REVERT)
+ /* Swap status for the active slot */
+ struct boot_swap_state swap_state;
+#endif
+};
+#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
+
/*
* This macro allows some control on the allocation of local variables.
* When running natively on a target, we don't want to allocated huge
@@ -82,7 +103,12 @@
int i;
for (i = 0; i < BOOT_NUM_SLOTS; i++) {
- rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs);
+ rc = BOOT_HOOK_CALL(boot_read_image_header_hook, BOOT_HOOK_REGULAR,
+ BOOT_CURR_IMG(state), i, boot_img_hdr(state, i));
+ if (rc == BOOT_HOOK_REGULAR)
+ {
+ rc = boot_read_image_header(state, i, boot_img_hdr(state, i), bs);
+ }
if (rc != 0) {
/* If `require_all` is set, fail on any single fail, otherwise
* if at least the first slot's header was read successfully,
@@ -101,6 +127,101 @@
return 0;
}
+/**
+ * Saves boot status and shared data for current image.
+ *
+ * @param state Boot loader status information.
+ * @param active_slot Index of the slot will be loaded for current image.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static int
+boot_add_shared_data(struct boot_loader_state *state,
+ uint32_t active_slot)
+{
+#if defined(MCUBOOT_MEASURED_BOOT) || defined(MCUBOOT_DATA_SHARING)
+ int rc;
+
+#ifdef MCUBOOT_MEASURED_BOOT
+ rc = boot_save_boot_status(BOOT_CURR_IMG(state),
+ boot_img_hdr(state, active_slot),
+ BOOT_IMG_AREA(state, active_slot));
+ if (rc != 0) {
+ BOOT_LOG_ERR("Failed to add image data to shared area");
+ return rc;
+ }
+#endif /* MCUBOOT_MEASURED_BOOT */
+
+#ifdef MCUBOOT_DATA_SHARING
+ rc = boot_save_shared_data(boot_img_hdr(state, active_slot),
+ BOOT_IMG_AREA(state, active_slot));
+ if (rc != 0) {
+ BOOT_LOG_ERR("Failed to add data to shared memory area.");
+ return rc;
+ }
+#endif /* MCUBOOT_DATA_SHARING */
+
+ return 0;
+
+#else /* MCUBOOT_MEASURED_BOOT || MCUBOOT_DATA_SHARING */
+ (void) (state);
+ (void) (active_slot);
+
+ return 0;
+#endif
+}
+
+/**
+ * Fills rsp to indicate how booting should occur.
+ *
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ * Only used in MCUBOOT_DIRECT_XIP and MCUBOOT_RAM_LOAD
+ * @param rsp boot_rsp struct to fill.
+ */
+static void
+fill_rsp(struct boot_loader_state *state, void *slot_usage,
+ struct boot_rsp *rsp)
+{
+ uint32_t active_slot;
+
+#if (BOOT_IMAGE_NUMBER > 1)
+ /* Always boot from Image 0. */
+ BOOT_CURR_IMG(state) = 0;
+#endif
+
+#if defined(MCUBOOT_DIRECT_XIP) || defined(MCUBOOT_RAM_LOAD)
+ active_slot = ((struct slot_usage_t *)slot_usage)[BOOT_CURR_IMG(state)].active_slot;
+#else
+ (void) (slot_usage);
+ active_slot = BOOT_PRIMARY_SLOT;
+#endif
+
+ rsp->br_flash_dev_id = flash_area_get_device_id(BOOT_IMG_AREA(state, active_slot));
+ rsp->br_image_off = boot_img_slot_off(state, active_slot);
+ rsp->br_hdr = boot_img_hdr(state, active_slot);
+}
+
+/**
+ * Closes all flash areas.
+ *
+ * @param state Boot loader status information.
+ */
+static void
+close_all_flash_areas(struct boot_loader_state *state)
+{
+ uint32_t slot;
+
+ IMAGES_ITER(BOOT_CURR_IMG(state)) {
+#if MCUBOOT_SWAP_USING_SCRATCH
+ flash_area_close(BOOT_SCRATCH_AREA(state));
+#endif
+ for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
+ flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
+ }
+ }
+}
+
#if !defined(MCUBOOT_DIRECT_XIP)
/*
* Compute the total size of the given image. Includes the size of
@@ -110,7 +231,7 @@
static int
boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
{
- const struct flash_area *fap;
+ const struct flash_area *fap = NULL;
struct image_tlv_info info;
uint32_t off;
uint32_t protect_tlv_size;
@@ -170,18 +291,22 @@
static uint32_t
boot_write_sz(struct boot_loader_state *state)
{
- uint32_t elem_sz;
+ size_t elem_sz;
#if MCUBOOT_SWAP_USING_SCRATCH
- uint32_t align;
+ size_t align;
#endif
/* Figure out what size to write update status update as. The size depends
* on what the minimum write size is for scratch area, active image slot.
* We need to use the bigger of those 2 values.
*/
+
elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
+ assert(elem_sz != 0u);
+
#if MCUBOOT_SWAP_USING_SCRATCH
align = flash_area_align(BOOT_SCRATCH_AREA(state));
+ assert(align != 0u);
if (align > elem_sz) {
elem_sz = align;
}
@@ -190,51 +315,20 @@
return elem_sz;
}
-#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
static int
boot_initialize_area(struct boot_loader_state *state, int flash_area)
{
- int num_sectors = BOOT_MAX_IMG_SECTORS;
- int rc;
-
- if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
- rc = flash_area_to_sectors(flash_area, &num_sectors,
- BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors);
- BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors = (size_t)num_sectors;
-
- } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
- rc = flash_area_to_sectors(flash_area, &num_sectors,
- BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors);
- BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors = (size_t)num_sectors;
-
-#if MCUBOOT_SWAP_USING_SCRATCH
- } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
- rc = flash_area_to_sectors(flash_area, &num_sectors,
- state->scratch.sectors);
- state->scratch.num_sectors = (size_t)num_sectors;
-#endif
-
- } else {
- return BOOT_EFLASH;
- }
-
- return rc;
-}
-#else /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
-static int
-boot_initialize_area(struct boot_loader_state *state, int flash_area)
-{
- uint32_t num_sectors;
- struct flash_sector *out_sectors;
+ uint32_t num_sectors = BOOT_MAX_IMG_SECTORS;
+ boot_sector_t *out_sectors;
size_t *out_num_sectors;
int rc;
num_sectors = BOOT_MAX_IMG_SECTORS;
- if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
+ if (flash_area == (int) FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
- } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
+ } else if (flash_area == (int) FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
#if MCUBOOT_SWAP_USING_SCRATCH
@@ -251,14 +345,18 @@
return BOOT_EFLASH;
}
+#ifdef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
+#else
+ _Static_assert(sizeof(int) <= sizeof(uint32_t), "Fix needed");
+ rc = flash_area_to_sectors(flash_area, (int *)&num_sectors, out_sectors);
+#endif /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
if (rc != 0) {
return rc;
}
*out_num_sectors = num_sectors;
return 0;
}
-#endif /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
/**
* Determines the sector layout of both image slots and the scratch area.
@@ -281,7 +379,8 @@
rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
if (rc != 0) {
- return BOOT_EFLASH;
+ /* We need to differentiate from the primary image issue */
+ return BOOT_EFLASH_SEC;
}
#if MCUBOOT_SWAP_USING_STATUS
@@ -307,9 +406,11 @@
boot_status_reset(struct boot_status *bs)
{
#ifdef MCUBOOT_ENC_IMAGES
- memset(&bs->enckey, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_KEY_SIZE);
+ (void)memset(&bs->enckey, BOOT_UNINITIALIZED_KEY_FILL,
+ BOOT_NUM_SLOTS * BOOT_ENC_KEY_SIZE);
#if MCUBOOT_SWAP_SAVE_ENCTLV
- memset(&bs->enctlv, 0xff, BOOT_NUM_SLOTS * BOOT_ENC_TLV_ALIGN_SIZE);
+ (void)memset(&bs->enctlv, BOOT_UNINITIALIZED_TLV_FILL,
+ BOOT_NUM_SLOTS * BOOT_ENC_TLV_ALIGN_SIZE);
#endif
#endif /* MCUBOOT_ENC_IMAGES */
@@ -343,12 +444,12 @@
int
boot_write_status(const struct boot_loader_state *state, struct boot_status *bs)
{
- const struct flash_area *fap;
+ const struct flash_area *fap = NULL;
uint32_t off;
int area_id;
int rc;
uint8_t buf[BOOT_MAX_ALIGN];
- uint8_t align;
+ size_t align;
uint8_t erased_val;
/* NOTE: The first sector copied (that is the last sector on slot) contains
@@ -378,8 +479,13 @@
off = boot_status_off(fap) +
boot_status_internal_off(bs, BOOT_WRITE_SZ(state));
align = flash_area_align(fap);
+ if (align == 0u) {
+ rc = BOOT_EFLASH;
+ goto done;
+ }
+
erased_val = flash_area_erased_val(fap);
- memset(buf, erased_val, BOOT_MAX_ALIGN);
+ (void)memset(buf, erased_val, BOOT_MAX_ALIGN);
buf[0] = bs->state;
rc = flash_area_write(fap, off, buf, align);
@@ -421,14 +527,24 @@
image_index = BOOT_CURR_IMG(state);
-#ifdef MCUBOOT_ENC_IMAGES
+/* In the case of ram loading the image has already been decrypted as it is
+ * decrypted when copied in ram */
+#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_RAM_LOAD)
if (MUST_DECRYPT(fap, image_index, hdr)) {
- rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
+ rc = flash_area_id_to_multi_image_slot(image_index, fap->fa_id);
if (rc < 0) {
FIH_RET(fih_rc);
}
- if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), 1, bs)) {
- FIH_RET(fih_rc);
+ else {
+ uint8_t slot = (uint8_t)rc;
+
+ rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap, bs);
+ if (rc < 0) {
+ FIH_RET(fih_rc);
+ }
+ if (0 == rc && boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs)) {
+ FIH_RET(fih_rc);
+ }
}
}
#endif
@@ -490,7 +606,7 @@
return false;
}
- if (size >= fap->fa_size) {
+ if (size >= flash_area_get_size(fap)) {
return false;
}
@@ -516,7 +632,7 @@
static int
boot_check_header_erased(struct boot_loader_state *state, int slot)
{
- const struct flash_area *fap;
+ const struct flash_area *fap = NULL;
struct image_header *hdr;
uint8_t erased_val;
int area_id;
@@ -542,8 +658,6 @@
#if (BOOT_IMAGE_NUMBER > 1) || \
defined(MCUBOOT_DIRECT_XIP) || \
defined(MCUBOOT_RAM_LOAD) || \
- defined(MCUBOOT_SWAP_USING_SCRATCH) || \
- defined(MCUBOOT_SWAP_USING_MOVE) || \
(defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_DOWNGRADE_PREVENTION))
/**
* Compare image version numbers not including the build number
@@ -597,13 +711,21 @@
* does not match the slot address.
*/
static bool
-boot_rom_address_check(struct boot_loader_state *state, size_t slot)
+boot_rom_address_check(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
{
- const struct image_header *hdr = boot_img_hdr(state, slot);
- uint32_t f_off = boot_img_slot_off(state, slot);
+ uint32_t active_slot;
+ const struct image_header *hdr;
+ uint32_t f_off;
+
+ active_slot = slot_usage[BOOT_CURR_IMG(state)].active_slot;
+ hdr = boot_img_hdr(state, active_slot);
+ f_off = boot_img_slot_off(state, active_slot);
+
if (hdr->ih_flags & IMAGE_F_ROM_FIXED && hdr->ih_load_addr != f_off) {
- BOOT_LOG_WRN("Image in %s slot at 0x%x has been built for offset 0x%x"\
- ", skipping", slot == 0 ? "primary" : "secondary", f_off,
+ BOOT_LOG_WRN("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);
/* If there is address mismatch, the image is not bootable from this
@@ -627,7 +749,7 @@
boot_validate_slot(struct boot_loader_state *state, int slot,
struct boot_status *bs)
{
- const struct flash_area *fap;
+ const struct flash_area *fap = NULL;
struct image_header *hdr;
int area_id;
fih_int fih_rc = FIH_FAILURE;
@@ -639,7 +761,7 @@
FIH_RET(fih_rc);
}
- BOOT_LOG_DBG("> boot_validate_slot: fa_id = %d", fap->fa_id);
+ BOOT_LOG_DBG("> boot_validate_slot: fa_id = %u", (unsigned)fap->fa_id);
hdr = boot_img_hdr(state, slot);
if (boot_check_header_erased(state, slot) == 0 ||
@@ -677,7 +799,7 @@
&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");
- flash_area_erase(fap, 0, fap->fa_size);
+ flash_area_erase(fap, 0, flash_area_get_size(fap));
/* Image in the secondary slot does not satisfy version requirement.
* Erase the image and continue booting from the primary slot.
*/
@@ -686,12 +808,16 @@
}
}
#endif
-
- FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
+ BOOT_HOOK_CALL_FIH(boot_image_check_hook, fih_int_encode(BOOT_HOOK_REGULAR),
+ fih_rc, BOOT_CURR_IMG(state), slot);
+ if (fih_eq(fih_rc, fih_int_encode(BOOT_HOOK_REGULAR)))
+ {
+ FIH_CALL(boot_image_check, fih_rc, state, hdr, fap, bs);
+ }
if (!boot_is_header_valid(hdr, fap) || fih_not_eq(fih_rc, FIH_SUCCESS)) {
if ((slot != BOOT_PRIMARY_SLOT) || ARE_SLOTS_EQUIVALENT()) {
BOOT_LOG_DBG(" * Image in the secondary slot is invalid. Erase the image");
- flash_area_erase(fap, 0, fap->fa_size);
+ flash_area_erase(fap, 0, flash_area_get_size(fap));
/* Image is invalid, erase it to prevent further unnecessary
* attempts to validate and boot it.
*/
@@ -732,7 +858,11 @@
{
const struct flash_area *fap = NULL;
uint32_t img_security_cnt;
+ void * custom_data = NULL;
int rc;
+#ifdef CYW20829
+ uint8_t buff[REPROV_PACK_SIZE];
+#endif /* CYW20829 */
rc = flash_area_open(flash_area_id_from_multi_image_slot(image_index, slot),
&fap);
@@ -746,10 +876,13 @@
goto done;
}
- rc = boot_nv_security_counter_update(image_index, img_security_cnt);
- if (rc != 0) {
- goto done;
+#ifdef CYW20829
+ rc = bootutil_get_img_reprov_packet(hdr, fap, buff);
+ if (rc == 0) {
+ custom_data = (void *)buff;
}
+#endif /* CYW20829 */
+ rc = boot_nv_security_counter_update(image_index, img_security_cnt, custom_data);
done:
flash_area_close(fap);
@@ -790,6 +923,7 @@
return swap_type;
}
+#endif
/**
* Erases a region of flash.
@@ -807,6 +941,7 @@
return flash_area_erase(fap, off, sz);
}
+#if !defined(MCUBOOT_DIRECT_XIP) && !defined(MCUBOOT_RAM_LOAD)
/**
* Copies the contents of one flash region to another. You must erase the
* destination region prior to calling this function.
@@ -830,7 +965,7 @@
uint32_t bytes_copied;
int chunk_sz;
int rc;
-#ifdef MCUBOOT_ENC_IMAGES
+#if defined (MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_ENC_IMAGES_XIP)
uint32_t off;
uint32_t tlv_off;
size_t blk_off;
@@ -840,9 +975,20 @@
uint8_t image_index;
#endif
- TARGET_STATIC uint8_t buf[1024];
+/* NOTE:
+ * Default value 1024 is not suitable for platforms with larger erase size.
+ * Give user ability to define platform tolerant chunk size. In most cases
+ * it would be flash erase alignment.
+ */
+#ifdef MCUBOOT_PLATFORM_CHUNK_SIZE
+ #define MCUBOOT_CHUNK_SIZE MCUBOOT_PLATFORM_CHUNK_SIZE
+#else
+ #define MCUBOOT_CHUNK_SIZE 1024
+#endif
-#if !defined(MCUBOOT_ENC_IMAGES)
+ TARGET_STATIC uint8_t buf[MCUBOOT_CHUNK_SIZE] __attribute__((aligned(4)));
+
+#if !defined(MCUBOOT_ENC_IMAGES) || defined(MCUBOOT_ENC_IMAGES_XIP)
(void)state;
#endif
@@ -859,28 +1005,28 @@
return BOOT_EFLASH;
}
-#ifdef MCUBOOT_ENC_IMAGES
+#if defined(MCUBOOT_ENC_IMAGES) && !defined(MCUBOOT_ENC_IMAGES_XIP)
image_index = BOOT_CURR_IMG(state);
- if ((fap_src->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
- fap_dst->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
+ if ((flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_PRIMARY(image_index) ||
+ flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
- !(fap_src->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index) &&
- fap_dst->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
- !(fap_src->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index) &&
- fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)))
+ !(flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_PRIMARY(image_index) &&
+ flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) &&
+ !(flash_area_get_id(fap_src) == FLASH_AREA_IMAGE_SECONDARY(image_index) &&
+ flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_SECONDARY(image_index)))
{
/* assume the primary slot as src, needs encryption */
hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
#if !defined(MCUBOOT_SWAP_USING_MOVE)
off = off_src;
- if (fap_dst->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
+ if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
/* might need decryption (metadata from the secondary slot) */
hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
off = off_dst;
}
#else
off = off_dst;
- if (fap_dst->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
+ if (flash_area_get_id(fap_dst) == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
}
#endif
@@ -909,10 +1055,11 @@
blk_sz = tlv_off - (off + bytes_copied);
}
}
- if(0 != blk_sz) {
- boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
- (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
- blk_off, &buf[idx]);
+ rc = boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
+ (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
+ blk_off, &buf[idx]);
+ if (rc != 0) {
+ return rc;
}
}
}
@@ -954,8 +1101,8 @@
size_t size;
size_t this_size;
size_t last_sector;
- const struct flash_area *fap_primary_slot;
- const struct flash_area *fap_secondary_slot;
+ const struct flash_area *fap_primary_slot = NULL;
+ const struct flash_area *fap_secondary_slot = NULL;
uint8_t image_index;
#if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
@@ -987,12 +1134,9 @@
assert (rc == 0);
sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
- BOOT_LOG_DBG(" * primary slot sectors: %d", sect_count);
+ BOOT_LOG_DBG(" * primary slot sectors: %lu", (unsigned long)sect_count);
for (sect = 0, size = 0; sect < sect_count; sect++) {
this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
- /* BOOT_LOG_DBG(" * primary slot erase region (0x%0lx / 0x%0lx): sector = %d, off = %0x, size = %d",
- fap_primary_slot->fa_off, fap_primary_slot->fa_size,
- sect, size, this_size); */
rc = boot_erase_region(fap_primary_slot, size, this_size);
assert(rc == 0);
@@ -1036,8 +1180,7 @@
}
#endif
- BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%x bytes",
- size);
+ BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%lx bytes", (unsigned long)size);
rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
if (rc != 0) {
return rc;
@@ -1050,6 +1193,12 @@
}
#endif
+ rc = BOOT_HOOK_CALL(boot_copy_region_post_hook, 0, BOOT_CURR_IMG(state),
+ BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT), size);
+ if (rc != 0) {
+ return rc;
+ }
+
#ifdef MCUBOOT_HW_ROLLBACK_PROT
/* Update the stored security counter with the new image's security counter
* value. Both slots hold the new image at this point, but the secondary
@@ -1112,12 +1261,11 @@
#ifdef MCUBOOT_ENC_IMAGES
const struct flash_area *fap;
uint8_t slot;
- uint8_t i;
#endif
uint32_t size;
uint32_t copy_size;
uint8_t image_index;
- int rc;
+ int rc = -1;
/* FIXME: just do this if asked by user? */
@@ -1148,7 +1296,8 @@
rc = 0;
}
} else {
- memset(bs->enckey[0], 0xff, BOOT_ENC_KEY_SIZE);
+ (void)memset(bs->enckey[0], BOOT_UNINITIALIZED_KEY_FILL,
+ BOOT_ENC_KEY_SIZE);
}
#endif
@@ -1172,7 +1321,8 @@
rc = 0;
}
} else {
- memset(bs->enckey[1], 0xff, BOOT_ENC_KEY_SIZE);
+ (void)memset(bs->enckey[1], BOOT_UNINITIALIZED_KEY_FILL,
+ BOOT_ENC_KEY_SIZE);
}
#endif
@@ -1194,16 +1344,14 @@
#ifdef MCUBOOT_ENC_IMAGES
for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
rc = boot_read_enc_key(image_index, slot, bs);
- assert(rc == 0);
+ assert(0 == rc);
- for (i = 0; i < BOOT_ENC_KEY_SIZE; i++) {
- if (bs->enckey[slot][i] != 0xff) {
- break;
- }
- }
-
- if (i != BOOT_ENC_KEY_SIZE) {
- boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs);
+ /* Set only an initialized key */
+ if (!bootutil_buffer_is_filled(bs->enckey[slot],
+ BOOT_UNINITIALIZED_KEY_FILL,
+ BOOT_ENC_KEY_SIZE)) {
+ rc = boot_enc_set_key(BOOT_CURR_ENC(state), slot, bs);
+ assert(rc == 0);
}
}
#endif
@@ -1219,7 +1367,7 @@
}
#endif
- return 0;
+ return rc;
}
#endif
@@ -1368,7 +1516,12 @@
if (rc == 0) {
/* All dependencies've been satisfied, continue with next image. */
BOOT_CURR_IMG(state)++;
- } else if (rc == BOOT_EBADVERSION) {
+ } else {
+#if (USE_SHARED_SLOT == 1)
+ /* Disable an upgrading of this image.*/
+ BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
+ BOOT_CURR_IMG(state)++;
+#else
/* Cannot upgrade due to non-met dependencies, so disable all
* image upgrades.
*/
@@ -1377,9 +1530,7 @@
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
}
break;
- } else {
- /* Other error happened, images are inconsistent */
- return rc;
+#endif /* (USE_SHARED_SLOT == 1) */
}
}
return rc;
@@ -1401,7 +1552,7 @@
uint8_t swap_type;
#endif
- BOOT_LOG_DBG("> boot_perform_update: bs->idx = %d", bs->idx);
+ BOOT_LOG_DBG("> boot_perform_update: bs->idx = %" PRIu32, bs->idx);
/* At this point there are no aborted swaps. */
#if defined(MCUBOOT_OVERWRITE_ONLY)
@@ -1415,6 +1566,21 @@
rc = boot_check_header_erased(state, BOOT_PRIMARY_SLOT);
FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, bs);
if (rc == 0 || fih_not_eq(fih_rc, FIH_SUCCESS)) {
+ /* Initialize swap status partition for primary slot, because
+ * in swap mode it is needed to properly complete copying the image
+ * to the primary slot.
+ */
+ const struct flash_area *fap_primary_slot = NULL;
+
+ rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state)),
+ &fap_primary_slot);
+ assert(rc == 0);
+
+ rc = swap_status_init(state, fap_primary_slot, bs);
+ assert(rc == 0);
+
+ flash_area_close(fap_primary_slot);
+
rc = boot_copy_image(state, bs);
} else {
rc = boot_swap_image(state, bs);
@@ -1598,27 +1764,33 @@
int rc;
fih_int fih_rc = FIH_FAILURE;
- BOOT_LOG_DBG("> boot_prepare_image_for_update: image = %d", BOOT_CURR_IMG(state));
+ BOOT_LOG_DBG("> boot_prepare_image_for_update: image = %u",
+ (unsigned)BOOT_CURR_IMG(state));
/* Determine the sector layout of the image slots and scratch area. */
rc = boot_read_sectors(state);
if (rc != 0) {
- BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
- " - too small?", BOOT_MAX_IMG_SECTORS);
+ BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%u"
+ " - too small?", (unsigned int) BOOT_MAX_IMG_SECTORS);
/* Unable to determine sector layout, continue with next image
* if there is one.
*/
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
- return;
+ if (rc == BOOT_EFLASH)
+ {
+ /* Only return on error from the primary image flash */
+ return;
+ }
}
/* Attempt to read an image header from each slot. */
rc = boot_read_image_headers(state, false, NULL);
- BOOT_LOG_DBG(" * Read an image (%d) header from each slot: rc = %d", BOOT_CURR_IMG(state), rc);
+ BOOT_LOG_DBG(" * Read an image (%u) header from each slot: rc = %d",
+ (unsigned)BOOT_CURR_IMG(state), rc);
if (rc != 0) {
/* Continue with next image if there is one. */
BOOT_LOG_WRN("Failed reading image headers; Image=%u",
- BOOT_CURR_IMG(state));
+ (unsigned)BOOT_CURR_IMG(state));
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
return;
}
@@ -1633,7 +1805,7 @@
rc = swap_read_status(state, bs);
if (rc != 0) {
BOOT_LOG_WRN("Failed reading boot status; Image=%u",
- BOOT_CURR_IMG(state));
+ (unsigned)BOOT_CURR_IMG(state));
/* Continue with next image if there is one. */
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
return;
@@ -1646,7 +1818,8 @@
* have been updated in the previous function call.
*/
rc = boot_read_image_headers(state, !boot_status_is_reset(bs), bs);
- BOOT_LOG_DBG(" * re-read image(%d) headers: rc = %d.", BOOT_CURR_IMG(state), rc);
+ BOOT_LOG_DBG(" * re-read image(%u) headers: rc = %d.",
+ (unsigned)BOOT_CURR_IMG(state), rc);
#ifdef MCUBOOT_BOOTSTRAP
/* When bootstrapping it's OK to not have image magic in the primary slot */
if (rc != 0 && (BOOT_CURR_IMG(state) != BOOT_PRIMARY_SLOT ||
@@ -1748,6 +1921,50 @@
BOOT_LOG_DBG("< boot_prepare_image_for_update");
}
+/**
+ * Updates the security counter for the current image.
+ *
+ * @param state Boot loader status information.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static int
+boot_update_hw_rollback_protection(struct boot_loader_state *state)
+{
+#ifdef MCUBOOT_HW_ROLLBACK_PROT
+ int rc;
+
+ /* Update the stored security counter with the active image's security
+ * counter value. It will only be updated if the new security counter is
+ * greater than the stored value.
+ *
+ * In case of a successful image swapping when the swap type is TEST the
+ * security counter can be increased only after a reset, when the swap
+ * type is NONE and the image has marked itself "OK" (the image_ok flag
+ * has been set). This way a "revert" can be performed when it's
+ * necessary.
+ */
+ if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
+ rc = boot_update_security_counter(
+ BOOT_CURR_IMG(state),
+ BOOT_PRIMARY_SLOT,
+ boot_img_hdr(state, BOOT_PRIMARY_SLOT));
+ if (rc != 0) {
+ BOOT_LOG_ERR("Security counter update failed after image "
+ "validation.");
+ return rc;
+ }
+ }
+
+ return 0;
+
+#else /* MCUBOOT_HW_ROLLBACK_PROT */
+ (void) (state);
+
+ return 0;
+#endif
+}
+
fih_int
context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
{
@@ -1773,7 +1990,8 @@
TARGET_STATIC boot_sector_t status_sectors[BOOT_MAX_SWAP_STATUS_SECTORS];
#endif
- memset(state, 0, sizeof(struct boot_loader_state));
+ (void)memset(&bs, 0, sizeof(bs));
+ (void)memset(state, 0, sizeof(struct boot_loader_state));
has_upgrade = false;
#if (BOOT_IMAGE_NUMBER == 1)
@@ -1870,7 +2088,7 @@
/* Set the previously determined swap type */
bs.swap_type = BOOT_SWAP_TYPE(state);
- BOOT_LOG_DBG(" * process swap_type = %d", bs.swap_type);
+ BOOT_LOG_DBG(" * process swap_type = %u", (unsigned)bs.swap_type);
switch (BOOT_SWAP_TYPE(state)) {
case BOOT_SWAP_TYPE_NONE:
@@ -1879,8 +2097,14 @@
case BOOT_SWAP_TYPE_TEST: /* fallthrough */
case BOOT_SWAP_TYPE_PERM: /* fallthrough */
case BOOT_SWAP_TYPE_REVERT:
- BOOT_LOG_DBG(" * perform update...", bs.swap_type);
- rc = boot_perform_update(state, &bs);
+ BOOT_LOG_DBG(" * perform update, mode %u...", (unsigned)bs.swap_type);
+ rc = BOOT_HOOK_CALL(boot_perform_update_hook, BOOT_HOOK_REGULAR,
+ BOOT_CURR_IMG(state), &(BOOT_IMG(state, 1).hdr),
+ BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT));
+ if (rc == BOOT_HOOK_REGULAR)
+ {
+ rc = boot_perform_update(state, &bs);
+ }
assert(rc == 0);
break;
@@ -1890,7 +2114,8 @@
* pretending we just reverted back to primary slot.
*/
#ifndef MCUBOOT_OVERWRITE_ONLY
- BOOT_LOG_DBG(" * update failed! Set image_ok manually for image(%d)", BOOT_CURR_IMG(state));
+ BOOT_LOG_DBG(" * update failed! Set image_ok manually for image(%u)",
+ (unsigned)BOOT_CURR_IMG(state));
/* image_ok needs to be explicitly set to avoid a new revert. */
rc = swap_set_image_ok(BOOT_CURR_IMG(state));
if (rc != 0) {
@@ -1933,7 +2158,7 @@
}
#ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
- FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, NULL);
+ FIH_CALL(boot_validate_slot, fih_rc, state, BOOT_PRIMARY_SLOT, &bs);
if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
goto out;
}
@@ -1943,57 +2168,33 @@
* the magic number on the image is OK.
*/
if (BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic != IMAGE_MAGIC) {
- BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
- &boot_img_hdr(state,BOOT_PRIMARY_SLOT)->ih_magic,
- BOOT_CURR_IMG(state));
+ BOOT_LOG_ERR("bad image magic 0x%" PRIx32 "; Image=%u",
+ BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic,
+ (unsigned)BOOT_CURR_IMG(state));
rc = BOOT_EBADIMAGE;
goto out;
}
#endif /* MCUBOOT_VALIDATE_PRIMARY_SLOT */
-#ifdef MCUBOOT_HW_ROLLBACK_PROT
- /* Update the stored security counter with the active image's security
- * counter value. It will only be updated if the new security counter is
- * greater than the stored value.
- *
- * In case of a successful image swapping when the swap type is TEST the
- * security counter can be increased only after a reset, when the swap
- * type is NONE and the image has marked itself "OK" (the image_ok flag
- * has been set). This way a "revert" can be performed when it's
- * necessary.
- */
- if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
- rc = boot_update_security_counter(
- BOOT_CURR_IMG(state),
- BOOT_PRIMARY_SLOT,
- boot_img_hdr(state, BOOT_PRIMARY_SLOT));
- if (rc != 0) {
- BOOT_LOG_ERR("Security counter update failed after image "
- "validation.");
- goto out;
+#ifdef MCUBOOT_ENC_IMAGES_XIP
+ if (0 == BOOT_CURR_IMG(state)) {
+ if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_PRIMARY_SLOT)))
+ {
+ (void)memcpy((uint8_t*)rsp->xip_iv, BOOT_CURR_ENC(state)->aes_iv, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
+ (void)memcpy((uint8_t*)rsp->xip_key, bs.enckey[BOOT_CURR_IMG(state)], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE);
}
}
-#endif /* MCUBOOT_HW_ROLLBACK_PROT */
+#endif /* MCUBOOT_ENC_IMAGES_XIP */
-#ifdef MCUBOOT_MEASURED_BOOT
- rc = boot_save_boot_status(BOOT_CURR_IMG(state),
- boot_img_hdr(state, BOOT_PRIMARY_SLOT),
- BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
+ rc = boot_update_hw_rollback_protection(state);
if (rc != 0) {
- BOOT_LOG_ERR("Failed to add Image %u data to shared memory area",
- BOOT_CURR_IMG(state));
goto out;
}
-#endif /* MCUBOOT_MEASURED_BOOT */
-#ifdef MCUBOOT_DATA_SHARING
- rc = boot_save_shared_data(boot_img_hdr(state, BOOT_PRIMARY_SLOT),
- BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
+ rc = boot_add_shared_data(state, BOOT_PRIMARY_SLOT);
if (rc != 0) {
- BOOT_LOG_ERR("Failed to add data to shared memory area.");
goto out;
}
-#endif /* MCUBOOT_DATA_SHARING */
}
#if (BOOT_IMAGE_NUMBER > 1)
@@ -2001,27 +2202,21 @@
BOOT_CURR_IMG(state) = 0;
#endif
+ rsp->br_flash_dev_id = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
+ rsp->br_image_off = boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
+ rsp->br_hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
/*
* Since the boot_status struct stores plaintext encryption keys, reset
* them here to avoid the possibility of jumping into an image that could
* easily recover them.
*/
- memset(&bs, 0, sizeof(struct boot_status));
+ (void)memset(&bs, 0, sizeof(struct boot_status));
- rsp->br_flash_dev_id = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
- rsp->br_image_off = boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
- rsp->br_hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
+ fill_rsp(state, NULL, rsp);
fih_rc = FIH_SUCCESS;
out:
- IMAGES_ITER(BOOT_CURR_IMG(state)) {
-#if MCUBOOT_SWAP_USING_SCRATCH
- flash_area_close(BOOT_SCRATCH_AREA(state));
-#endif
- for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
- flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
- }
- }
+ close_all_flash_areas(state);
if (rc) {
fih_rc = fih_int_encode(rc);
@@ -2040,6 +2235,10 @@
int rc;
fih_int fih_rc = FIH_FAILURE;
+ if ((loader_slot < 0) || (split_slot < 0)) {
+ FIH_RET(FIH_FAILURE);
+ }
+
sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
if (sectors == NULL) {
FIH_RET(FIH_FAILURE);
@@ -2100,92 +2299,180 @@
#else /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */
+#define NO_ACTIVE_SLOT UINT32_MAX
+
/**
- * Iterates over all slots and determines which contain a firmware image.
+ * Opens all flash areas and checks which contain an image with a valid header.
*
- * @param state Boot loader status information.
- * @param slot_usage Pointer to an array, which aim is to carry information
- * about slots that contain an image. After return the
- * corresponding array elements are set to a non-zero
- * value if the given slots are in use (contain a firmware
- * image), otherwise they are set to zero.
- * @param slot_cnt The number of slots, which can contain firmware images.
- * (Equal to or smaller than the size of the
- * slot_usage array.)
+ * @param state Boot loader status information.
+ * @param slot_usage Structure to fill with information about the available
+ * slots.
*
- * @return The number of found images.
+ * @return 0 on success; nonzero on failure.
+ */
+static int
+boot_get_slot_usage(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
+{
+ uint32_t slot;
+ int fa_id;
+ int rc;
+ struct image_header *hdr = NULL;
+
+ IMAGES_ITER(BOOT_CURR_IMG(state)) {
+ /* Open all the slots */
+ for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
+ fa_id = flash_area_id_from_multi_image_slot(
+ BOOT_CURR_IMG(state), slot);
+ rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
+ assert(rc == 0);
+ }
+
+ /* Attempt to read an image header from each slot. */
+ rc = boot_read_image_headers(state, false, NULL);
+ if (rc != 0) {
+ BOOT_LOG_WRN("Failed reading image headers.");
+ return rc;
+ }
+
+ /* Check headers in all slots */
+ for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
+ hdr = boot_img_hdr(state, slot);
+
+ if (boot_is_header_valid(hdr, BOOT_IMG_AREA(state, slot))) {
+ slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = true;
+ BOOT_LOG_IMAGE_INFO(slot, hdr);
+ } else {
+ slot_usage[BOOT_CURR_IMG(state)].slot_available[slot] = false;
+ BOOT_LOG_INF("Image %u %s slot: Image not found",
+ (unsigned)BOOT_CURR_IMG(state),
+ (slot == BOOT_PRIMARY_SLOT)
+ ? "Primary" : "Secondary");
+ }
+ }
+
+ slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
+ }
+
+ return 0;
+}
+
+/**
+ * Finds the slot containing the image with the highest version number for the
+ * current image.
+ *
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ *
+ * @return NO_ACTIVE_SLOT if no available slot found, number of
+ * the found slot otherwise.
*/
static uint32_t
-boot_get_slot_usage(struct boot_loader_state *state, uint8_t slot_usage[],
- uint32_t slot_cnt)
+find_slot_with_highest_version(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
{
- struct image_header *hdr = NULL;
- uint32_t image_cnt = 0;
uint32_t slot;
+ uint32_t candidate_slot = NO_ACTIVE_SLOT;
+ int rc;
- memset(slot_usage, 0, slot_cnt);
-
- for (slot = 0; slot < slot_cnt; slot++) {
- hdr = boot_img_hdr(state, slot);
-
- if (boot_is_header_valid(hdr, BOOT_IMG_AREA(state, slot))) {
- slot_usage[slot] = 1;
- image_cnt++;
- BOOT_LOG_IMAGE_INFO(slot, hdr);
- } else {
- BOOT_LOG_INF("%s slot: Image not found", (slot == BOOT_PRIMARY_SLOT)
- ? "Primary" : "Secondary");
+ for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
+ if (slot_usage[BOOT_CURR_IMG(state)].slot_available[slot]) {
+ if (candidate_slot == NO_ACTIVE_SLOT) {
+ candidate_slot = slot;
+ } else {
+ rc = boot_version_cmp(
+ &boot_img_hdr(state, slot)->ih_ver,
+ &boot_img_hdr(state, candidate_slot)->ih_ver);
+ if (rc == 1) {
+ /* The version of the image being examined is greater than
+ * the version of the current candidate.
+ */
+ candidate_slot = slot;
+ }
+ }
}
}
- return image_cnt;
+ return candidate_slot;
}
-#ifdef MCUBOOT_DIRECT_XIP_REVERT
+#ifdef MCUBOOT_HAVE_LOGGING
/**
- * Checks whether the image in the given slot was previously selected to run.
- * Erases the image if it was selected but its execution failed, otherwise marks
- * it as selected if it has not been before.
+ * Prints the state of the loaded images.
*
- * @param state Image metadata from the image trailer. This function fills
- * this struct with the data read from the image trailer.
- * @param slot Image slot number.
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ */
+static void
+print_loaded_images(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
+{
+ uint32_t active_slot;
+
+ (void)state;
+
+ IMAGES_ITER(BOOT_CURR_IMG(state)) {
+ active_slot = slot_usage[BOOT_CURR_IMG(state)].active_slot;
+
+ BOOT_LOG_INF("Image %u loaded from the %s slot",
+ (unsigned)BOOT_CURR_IMG(state),
+ (active_slot == BOOT_PRIMARY_SLOT) ?
+ "primary" : "secondary");
+ }
+}
+#endif
+
+#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
+/**
+ * Checks whether the active slot of the current image was previously selected
+ * to run. Erases the image if it was selected but its execution failed,
+ * otherwise marks it as selected if it has not been before.
*
- * @return 0 on success; nonzero on failure.
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ *
+ * @return 0 on success; nonzero on failure.
*/
static int
-boot_select_or_erase(struct boot_swap_state *state, uint32_t slot)
+boot_select_or_erase(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
{
const struct flash_area *fap;
int fa_id;
int rc;
+ uint32_t active_slot;
+ struct boot_swap_state* active_swap_state;
- fa_id = flash_area_id_from_image_slot(slot);
+ active_slot = slot_usage[BOOT_CURR_IMG(state)].active_slot;
+
+ 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);
- memset(state, 0, sizeof(struct boot_swap_state));
- rc = boot_read_swap_state(fap, state);
+ active_swap_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 (state->magic != BOOT_MAGIC_GOOD ||
- (state->copy_done == BOOT_FLAG_SET &&
- state->image_ok != BOOT_FLAG_SET)) {
+ if (active_swap_state->magic != BOOT_MAGIC_GOOD ||
+ (active_swap_state->copy_done == BOOT_FLAG_SET &&
+ active_swap_state->image_ok != BOOT_FLAG_SET)) {
/*
* A reboot happened without the image being confirmed at
* runtime or its trailer is corrupted/invalid. Erase the image
* to prevent it from being selected again on the next reboot.
*/
BOOT_LOG_DBG("Erasing faulty image in the %s slot.",
- (slot == BOOT_PRIMARY_SLOT) ? "primary" : "secondary");
- rc = flash_area_erase(fap, 0, fap->fa_size);
+ (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 (state->copy_done != BOOT_FLAG_SET) {
- if (state->copy_done == BOOT_FLAG_BAD) {
+ 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'.");
}
@@ -2198,7 +2485,7 @@
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.", (slot == BOOT_PRIMARY_SLOT) ?
+ "the %s slot.", (active_slot == BOOT_PRIMARY_SLOT) ?
"primary" : "secondary");
rc = 0;
}
@@ -2208,29 +2495,54 @@
return rc;
}
-#endif /* MCUBOOT_DIRECT_XIP_REVERT */
+#endif /* MCUBOOT_DIRECT_XIP && MCUBOOT_DIRECT_XIP_REVERT */
#ifdef MCUBOOT_RAM_LOAD
+#ifndef MULTIPLE_EXECUTABLE_RAM_REGIONS
#if !defined(IMAGE_EXECUTABLE_RAM_START) || !defined(IMAGE_EXECUTABLE_RAM_SIZE)
#error "Platform MUST define executable RAM bounds in case of RAM_LOAD"
#endif
+#endif
/**
- * Verifies that the image in a slot will be loaded within the predefined bounds
- * that are allowed to be used by executable images.
+ * Verifies that the active slot of the current image can be loaded within the
+ * predefined bounds that are allowed to be used by executable images.
*
- * @param img_dst The address to which the image is going to be copied.
- * @param img_sz The size of the image.
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
*
- * @return 0 on success; nonzero on failure.
+ * @return 0 on success; nonzero on failure.
*/
static int
-boot_verify_ram_load_address(uint32_t img_dst, uint32_t img_sz)
+boot_verify_ram_load_address(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
{
+ uint32_t img_dst;
+ uint32_t img_sz;
uint32_t img_end_addr;
+ uint32_t exec_ram_start;
+ uint32_t exec_ram_size;
- if (img_dst < IMAGE_EXECUTABLE_RAM_START) {
+ (void)state;
+
+#ifdef MULTIPLE_EXECUTABLE_RAM_REGIONS
+ int rc;
+
+ rc = boot_get_image_exec_ram_info(BOOT_CURR_IMG(state), &exec_ram_start,
+ &exec_ram_size);
+ if (rc != 0) {
+ return BOOT_EBADSTATUS;
+ }
+#else
+ exec_ram_start = IMAGE_EXECUTABLE_RAM_START;
+ exec_ram_size = IMAGE_EXECUTABLE_RAM_SIZE;
+#endif
+
+ img_dst = slot_usage[BOOT_CURR_IMG(state)].img_dst;
+ img_sz = slot_usage[BOOT_CURR_IMG(state)].img_sz;
+
+ if (img_dst < exec_ram_start) {
return BOOT_EBADIMAGE;
}
@@ -2238,17 +2550,121 @@
return BOOT_EBADIMAGE;
}
- if (img_end_addr > (IMAGE_EXECUTABLE_RAM_START +
- IMAGE_EXECUTABLE_RAM_SIZE)) {
+ if (img_end_addr > (exec_ram_start + exec_ram_size)) {
return BOOT_EBADIMAGE;
}
return 0;
}
+#ifdef MCUBOOT_ENC_IMAGES
+
/**
- * Copies an image from a slot in the flash to an SRAM address.
+ * Copies and decrypts an image from a slot in the flash to an SRAM address.
*
+ * @param state Boot loader status information.
+ * @param slot The flash slot of the image to be copied to SRAM.
+ * @param hdr The image header.
+ * @param src_sz Size of the image.
+ * @param img_dst Pointer to the address at which the image needs to be
+ * copied to SRAM.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static int
+boot_decrypt_and_copy_image_to_sram(struct boot_loader_state *state,
+ uint32_t slot, struct image_header *hdr,
+ uint32_t src_sz, uint32_t img_dst)
+{
+ /* The flow for the decryption and copy of the image is as follows :
+ * 1. The whole image is copied to the RAM (header + payload + TLV).
+ * 2. The encryption key is loaded from the TLV in flash.
+ * 3. The image is then decrypted chunk by chunk in RAM (1 chunk
+ * is 1024 bytes). Only the payload section is decrypted.
+ * 4. The image is authenticated in RAM.
+ */
+ const struct flash_area *fap_src = NULL;
+ 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);
+
+ image_index = BOOT_CURR_IMG(state);
+ area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
+ rc = flash_area_open(area_id, &fap_src);
+ if (rc != 0){
+ return BOOT_EFLASH;
+ }
+
+ tlv_off = BOOT_TLV_OFF(hdr);
+
+ /* Copying the whole image in RAM */
+ rc = flash_area_read(fap_src, 0, ram_dst, src_sz);
+ if (rc != 0) {
+ goto done;
+ }
+
+ rc = boot_enc_load(BOOT_CURR_ENC(state), image_index, hdr, fap_src, &bs);
+ if (rc < 0) {
+ goto done;
+ }
+
+ /* if rc > 0 then the key has already been loaded */
+ if (rc == 0 && boot_enc_set_key(BOOT_CURR_ENC(state), slot, &bs)) {
+ goto done;
+ }
+
+ /* Starting at the end of the header as the header section is not encrypted */
+ while (bytes_copied < tlv_off) { /* TLV section copied previously */
+ if (src_sz - bytes_copied > max_sz) {
+ chunk_sz = max_sz;
+ } else {
+ chunk_sz = src_sz - bytes_copied;
+ }
+
+ cur_dst = ram_dst + bytes_copied;
+ blk_sz = chunk_sz;
+ idx = 0;
+ if (bytes_copied + chunk_sz > tlv_off) {
+ /* Going over TLV section
+ * Part of the chunk is encrypted payload */
+ blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
+ blk_sz = tlv_off - (bytes_copied);
+ boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
+ (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
+ blk_off, cur_dst);
+ } else {
+ /* Image encrypted payload section */
+ blk_off = ((bytes_copied) - hdr->ih_hdr_size) & 0xf;
+ boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
+ (bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
+ blk_off, cur_dst);
+ }
+
+ bytes_copied += chunk_sz;
+ }
+ rc = 0;
+
+done:
+ flash_area_close(fap_src);
+
+ return rc;
+}
+
+#endif /* MCUBOOT_ENC_IMAGES */
+/**
+ * Copies a slot of the current image into SRAM.
+ *
+ * @param state Boot loader status information.
* @param slot The flash slot of the image to be copied to SRAM.
* @param img_dst The address at which the image needs to be copied to
* SRAM.
@@ -2257,18 +2673,26 @@
* @return 0 on success; nonzero on failure.
*/
static int
-boot_copy_image_to_sram(int slot, uint32_t img_dst, uint32_t img_sz)
+boot_copy_image_to_sram(struct boot_loader_state *state, int slot,
+ uint32_t img_dst, uint32_t img_sz)
{
int rc;
const struct flash_area *fap_src = NULL;
+ int area_id;
- rc = flash_area_open(flash_area_id_from_image_slot(slot), &fap_src);
+#if (BOOT_IMAGE_NUMBER == 1)
+ (void)state;
+#endif
+
+ area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
+
+ rc = flash_area_open(area_id, &fap_src);
if (rc != 0) {
return BOOT_EFLASH;
}
/* Direct copy from flash to its new location in SRAM. */
- rc = flash_area_read(fap_src, 0, (void *)img_dst, img_sz);
+ rc = flash_area_read(fap_src, 0, (void *)(IMAGE_RAM_BASE + img_dst), img_sz);
if (rc != 0) {
BOOT_LOG_INF("Error whilst copying image from Flash to SRAM: %d", rc);
}
@@ -2278,50 +2702,142 @@
return rc;
}
+#if (BOOT_IMAGE_NUMBER > 1)
/**
- * Copies an image from a slot in the flash to an SRAM address. The load
- * address and image size is extracted from the image header.
+ * Checks if two memory regions (A and B) are overlap or not.
*
- * @param state Boot loader status information.
- * @param slot The flash slot of the image to be copied to SRAM.
- * @param hdr Pointer to the image header structure of the image
- * @param img_dst Pointer to the address at which the image needs to be
- * copied to SRAM.
- * @param img_sz Pointer to the size of the image that needs to be
- * copied to SRAM.
+ * @param start_a Start of the A region.
+ * @param end_a End of the A region.
+ * @param start_b Start of the B region.
+ * @param end_b End of the B region.
*
- * @return 0 on success; nonzero on failure.
+ * @return true if there is overlap; false otherwise.
+ */
+static bool
+do_regions_overlap(uint32_t start_a, uint32_t end_a,
+ uint32_t start_b, uint32_t end_b)
+{
+ if (start_b > end_a) {
+ return false;
+ } else if (start_b >= start_a) {
+ return true;
+ } else if (end_b > start_a) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Checks if the image we want to load to memory overlap with an already
+ * ramloaded image.
+ *
+ * @param slot_usage Information about the active and available slots.
+ * @param image_id_to_check The ID of the image we would like to load.
+ *
+ * @return 0 if there is no overlap; nonzero otherwise.
*/
static int
-boot_load_image_to_sram(struct boot_loader_state *state, uint32_t slot,
- struct image_header *hdr, uint32_t *img_dst,
- uint32_t *img_sz)
+boot_check_ram_load_overlapping(struct slot_usage_t slot_usage[],
+ uint32_t image_id_to_check)
{
+ uint32_t i;
+
+ uint32_t start_a;
+ uint32_t end_a;
+ uint32_t start_b;
+ uint32_t end_b;
+
+ start_a = slot_usage[image_id_to_check].img_dst;
+ /* Safe to add here, values are already verified in
+ * boot_verify_ram_load_address() */
+ end_a = start_a + slot_usage[image_id_to_check].img_sz;
+
+ for (i = 0; i < BOOT_IMAGE_NUMBER; i++) {
+ if (slot_usage[i].active_slot == NO_ACTIVE_SLOT
+ || i == image_id_to_check) {
+ continue;
+ }
+
+ start_b = slot_usage[i].img_dst;
+ /* Safe to add here, values are already verified in
+ * boot_verify_ram_load_address() */
+ end_b = start_b + slot_usage[i].img_sz;
+
+ if (do_regions_overlap(start_a, end_a, start_b, end_b)) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+/**
+ * Loads the active slot of the current image into SRAM. The load address and
+ * image size is extracted from the image header.
+ *
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static int
+boot_load_image_to_sram(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
+{
+ uint32_t active_slot;
+ struct image_header *hdr = NULL;
+ uint32_t img_dst;
+ uint32_t img_sz;
int rc;
+ active_slot = slot_usage[BOOT_CURR_IMG(state)].active_slot;
+ hdr = boot_img_hdr(state, active_slot);
+
if (hdr->ih_flags & IMAGE_F_RAM_LOAD) {
- *img_dst = hdr->ih_load_addr;
+ img_dst = hdr->ih_load_addr;
- rc = boot_read_image_size(state, slot, img_sz);
+ rc = boot_read_image_size(state, active_slot, &img_sz);
if (rc != 0) {
return rc;
}
- rc = boot_verify_ram_load_address(*img_dst, *img_sz);
+ slot_usage[BOOT_CURR_IMG(state)].img_dst = img_dst;
+ slot_usage[BOOT_CURR_IMG(state)].img_sz = img_sz;
+
+ rc = boot_verify_ram_load_address(state, slot_usage);
if (rc != 0) {
- BOOT_LOG_INF("Image RAM load address 0x%x is invalid.", *img_dst);
+ BOOT_LOG_INF("Image RAM load address 0x%" PRIx32 " is invalid.", img_dst);
return rc;
}
+#if (BOOT_IMAGE_NUMBER > 1)
+ rc = boot_check_ram_load_overlapping(slot_usage, BOOT_CURR_IMG(state));
+ if (rc != 0) {
+ BOOT_LOG_INF("Image RAM loading to address 0x%" PRIx32
+ " would overlap with another image.", img_dst);
+ return rc;
+ }
+#endif
+#ifdef MCUBOOT_ENC_IMAGES
+ /* decrypt image if encrypted and copy it to RAM */
+ if (IS_ENCRYPTED(hdr)) {
+ rc = boot_decrypt_and_copy_image_to_sram(state, active_slot, hdr, img_sz, img_dst);
+ } else {
+ rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
+ }
+#else
/* Copy image to the load address from where it currently resides in
* flash.
*/
- rc = boot_copy_image_to_sram(slot, *img_dst, *img_sz);
+ rc = boot_copy_image_to_sram(state, active_slot, img_dst, img_sz);
+#endif
if (rc != 0) {
- BOOT_LOG_INF("RAM loading to 0x%x is failed.", *img_dst);
+ BOOT_LOG_INF("RAM loading to 0x%" PRIx32 " is failed.", img_dst);
} else {
- BOOT_LOG_INF("RAM loading to 0x%x is succeeded.", *img_dst);
+ BOOT_LOG_INF("RAM loading to 0x%" PRIx32 " is succeeded.", img_dst);
}
} else {
/* Only images that support IMAGE_F_RAM_LOAD are allowed if
@@ -2330,114 +2846,277 @@
rc = BOOT_EBADIMAGE;
}
+ if (rc != 0) {
+ slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
+ slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
+ }
+
return rc;
}
/**
* Removes an image from SRAM, by overwriting it with zeros.
*
- * @param img_dst The address of the image that needs to be removed from
- * SRAM.
- * @param img_sz The size of the image that needs to be removed from
- * SRAM.
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static inline int
+boot_remove_image_from_sram(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
+{
+ (void)state;
+
+ BOOT_LOG_INF("Removing image from SRAM at address 0x%" PRIx32,
+ slot_usage[BOOT_CURR_IMG(state)].img_dst);
+
+ memset((void*)(IMAGE_RAM_BASE + slot_usage[BOOT_CURR_IMG(state)].img_dst),
+ 0, slot_usage[BOOT_CURR_IMG(state)].img_sz);
+
+ slot_usage[BOOT_CURR_IMG(state)].img_dst = 0;
+ slot_usage[BOOT_CURR_IMG(state)].img_sz = 0;
+
+ return 0;
+}
+
+/**
+ * Removes an image from flash by erasing the corresponding flash area
+ *
+ * @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_remove_image_from_sram(uint32_t img_dst, uint32_t img_sz)
+boot_remove_image_from_flash(struct boot_loader_state *state, uint32_t slot)
{
- BOOT_LOG_INF("Removing image from SRAM at address 0x%x", img_dst);
- memset((void*)img_dst, 0, img_sz);
+ int area_id;
+ int rc;
+ const struct flash_area *fap;
- return 0;
+ (void)state;
+
+ BOOT_LOG_INF("Removing image %u slot %" PRIu32 " from flash",
+ (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, &fap);
+ if (rc == 0) {
+ flash_area_erase(fap, 0, flash_area_get_size(fap));
+ }
+
+ return rc;
}
#endif /* MCUBOOT_RAM_LOAD */
-fih_int
-context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
+#if (BOOT_IMAGE_NUMBER > 1)
+/**
+ * Checks the image dependency whether it is satisfied.
+ *
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ * @param dep Image dependency which has to be verified.
+ *
+ * @return 0 if dependencies are met; nonzero otherwise.
+ */
+static int
+boot_verify_slot_dependency(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[],
+ struct image_dependency *dep)
{
- struct image_header *hdr = NULL;
- struct image_header *selected_image_header = NULL;
- uint8_t slot_usage[BOOT_NUM_SLOTS];
- uint32_t selected_slot;
- uint32_t slot;
- uint32_t img_cnt;
- uint32_t i;
- int fa_id;
+ struct image_version *dep_version;
+ uint32_t dep_slot;
int rc;
-#ifdef MCUBOOT_RAM_LOAD
- uint32_t img_dst;
- uint32_t img_sz;
- uint32_t img_loaded = 0;
-#endif /* MCUBOOT_RAM_LOAD */
-#ifdef MCUBOOT_DIRECT_XIP_REVERT
- struct boot_swap_state slot_state;
-#endif /* MCUBOOT_DIRECT_XIP_REVERT */
- fih_int fih_rc = FIH_FAILURE;
- memset(state, 0, sizeof(struct boot_loader_state));
-
- /* Open primary and secondary image areas for the duration
- * of this call.
+ /* Determine the source of the image which is the subject of
+ * the dependency and get it's version.
*/
- for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
- fa_id = flash_area_id_from_image_slot(slot);
- rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
- assert(rc == 0);
+ dep_slot = slot_usage[dep->image_id].active_slot;
+ dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
+
+ rc = boot_version_cmp(dep_version, &dep->image_min_version);
+ if (rc >= 0) {
+ /* Dependency satisfied. */
+ rc = 0;
}
- /* Attempt to read an image header from each slot. */
- rc = boot_read_image_headers(state, false, NULL);
+ return rc;
+}
+
+/**
+ * Reads all dependency TLVs of an image and verifies one after another to see
+ * if they are all satisfied.
+ *
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ *
+ * @return 0 if dependencies are met; nonzero otherwise.
+ */
+static int
+boot_verify_slot_dependencies(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
+{
+ uint32_t active_slot;
+ const struct flash_area *fap;
+ struct image_tlv_iter it;
+ struct image_dependency dep;
+ uint32_t off;
+ uint16_t len;
+ int area_id;
+ int rc;
+
+ active_slot = slot_usage[BOOT_CURR_IMG(state)].active_slot;
+
+ area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state),
+ active_slot);
+ rc = flash_area_open(area_id, &fap);
if (rc != 0) {
- BOOT_LOG_WRN("Failed reading image headers.");
- goto out;
+ rc = BOOT_EFLASH;
+ goto done;
}
- img_cnt = boot_get_slot_usage(state, slot_usage,
- sizeof(slot_usage)/sizeof(slot_usage[0]));
+ rc = bootutil_tlv_iter_begin(&it, boot_img_hdr(state, active_slot), fap,
+ IMAGE_TLV_DEPENDENCY, true);
+ if (rc != 0) {
+ goto done;
+ }
- if (img_cnt) {
- /* Select the newest and valid image. */
- for (i = 0; i < img_cnt; i++) {
- selected_slot = 0;
+ while (true) {
+ rc = bootutil_tlv_iter_next(&it, &off, &len, NULL);
+ if (rc < 0) {
+ return -1;
+ } else if (rc > 0) {
+ rc = 0;
+ break;
+ }
- /* Iterate over all the slots that are in use (contain an image)
- * and select the one that holds the newest image.
- */
- for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
- if (slot_usage[slot]) {
- hdr = boot_img_hdr(state, slot);
- if (selected_image_header != NULL) {
- rc = boot_version_cmp(&hdr->ih_ver,
- &selected_image_header->ih_ver);
- if (rc < 1) {
- /* The version of the image being examined wasn't
- * greater than the currently selected image's
- * version.
- */
- continue;
- }
- }
- /* Check if image has IMAGE_F_ROM_FIXED flag set and
- * is in proper slot.
- */
- if (boot_rom_address_check(state, slot) != 0) {
- continue;
- }
- selected_slot = slot;
- selected_image_header = hdr;
- }
+ if (len != sizeof(dep)) {
+ rc = BOOT_EBADIMAGE;
+ goto done;
+ }
+
+ rc = LOAD_IMAGE_DATA(boot_img_hdr(state, active_slot),
+ fap, off, &dep, len);
+ if (rc != 0) {
+ rc = BOOT_EFLASH;
+ goto done;
+ }
+
+ if (dep.image_id >= BOOT_IMAGE_NUMBER) {
+ rc = BOOT_EBADARGS;
+ goto done;
+ }
+
+ rc = boot_verify_slot_dependency(state, slot_usage, &dep);
+ if (rc != 0) {
+ /* Dependency not satisfied. */
+ goto done;
+ }
+ }
+
+done:
+ flash_area_close(fap);
+ return rc;
+}
+
+/**
+ * Checks the dependency of all the active slots. If an image found with
+ * invalid or not satisfied dependencies the image is removed from SRAM (in
+ * case of MCUBOOT_RAM_LOAD strategy) and its slot is set to unavailable.
+ *
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ *
+ * @return 0 if dependencies are met; nonzero otherwise.
+ */
+static int
+boot_verify_dependencies(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
+{
+ int rc = -1;
+ uint32_t active_slot;
+
+ IMAGES_ITER(BOOT_CURR_IMG(state)) {
+ rc = boot_verify_slot_dependencies(state, slot_usage);
+ if (rc != 0) {
+ /* Dependencies not met or invalid dependencies. */
+
+#ifdef MCUBOOT_RAM_LOAD
+ boot_remove_image_from_sram(state, slot_usage);
+#endif /* MCUBOOT_RAM_LOAD */
+
+ active_slot = slot_usage[BOOT_CURR_IMG(state)].active_slot;
+ slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
+ slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
+
+ return rc;
+ }
+ }
+
+ return rc;
+}
+#endif /* (BOOT_IMAGE_NUMBER > 1) */
+
+/**
+ * Tries to load a slot for all the images with validation.
+ *
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+fih_int
+boot_load_and_validate_images(struct boot_loader_state *state,
+ struct slot_usage_t slot_usage[])
+{
+ uint32_t active_slot;
+ int rc;
+ fih_int fih_rc;
+
+ /* Go over all the images and try to load one */
+ 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 = 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,
+ slot_usage);
+ if (active_slot == NO_ACTIVE_SLOT) {
+ BOOT_LOG_INF("No slot to load for image %u",
+ (unsigned)BOOT_CURR_IMG(state));
+ FIH_RET(FIH_FAILURE);
+ }
+
+ /* Save the number of the active slot. */
+ slot_usage[BOOT_CURR_IMG(state)].active_slot = active_slot;
+
+#ifdef MCUBOOT_DIRECT_XIP
+ rc = boot_rom_address_check(state, slot_usage);
+ if (rc != 0) {
+ /* The image is placed in an unsuitable slot. */
+ slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
+ slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
+ continue;
}
#ifdef MCUBOOT_DIRECT_XIP_REVERT
- rc = boot_select_or_erase(&slot_state, selected_slot);
+ rc = boot_select_or_erase(state, slot_usage);
if (rc != 0) {
/* The selected image slot has been erased. */
- slot_usage[selected_slot] = 0;
- selected_image_header = NULL;
+ slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
+ 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
@@ -2445,111 +3124,146 @@
* when loading images from external (untrusted) flash to internal
* (trusted) RAM and image is authenticated before copying.
*/
- rc = boot_load_image_to_sram(state, selected_slot,
- selected_image_header, &img_dst,
- &img_sz);
+ rc = boot_load_image_to_sram(state, slot_usage);
if (rc != 0 ) {
- /* Image loading failed try the next one. */
- slot_usage[selected_slot] = 0;
- selected_image_header = NULL;
+ /* Image cannot be ramloaded. */
+ boot_remove_image_from_flash(state, active_slot);
+ slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
+ slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
continue;
- } else {
- img_loaded = 1;
}
#endif /* MCUBOOT_RAM_LOAD */
- FIH_CALL(boot_validate_slot, fih_rc, state, selected_slot, NULL);
- if (fih_eq(fih_rc, FIH_SUCCESS)) {
- /* If a valid image is found then there is no reason to check
- * the rest of the images, as each of them has a smaller version
- * number.
- */
- break;
- }
+
+ FIH_CALL(boot_validate_slot, fih_rc, state, active_slot, NULL);
+ if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+ /* Image is invalid. */
#ifdef MCUBOOT_RAM_LOAD
- else if (img_loaded) {
- /* If an image is found to be invalid then it is removed from
- * RAM to prevent it being a shellcode vector.
- */
- boot_remove_image_from_sram(img_dst, img_sz);
- img_loaded = 0;
- }
+ boot_remove_image_from_sram(state, slot_usage);
#endif /* MCUBOOT_RAM_LOAD */
- /* The selected image is invalid, mark its slot as "unused"
- * and start over.
- */
- slot_usage[selected_slot] = 0;
- selected_image_header = NULL;
- }
-
- if (fih_not_eq(fih_rc, FIH_SUCCESS) || (selected_image_header == NULL)) {
- /* If there was no valid image at all */
- goto out;
- }
-
-#ifdef MCUBOOT_HW_ROLLBACK_PROT
- /* Update the stored security counter with the newer (active) image's
- * security counter value.
- */
-#ifdef MCUBOOT_DIRECT_XIP_REVERT
- /* When the 'revert' mechanism is enabled in direct-xip mode, the
- * security counter can be increased only after reboot, if the image
- * has been confirmed at runtime (the image_ok flag has been set).
- * This way a 'revert' can be performed when it's necessary.
- */
- if (slot_state.image_ok == BOOT_FLAG_SET) {
-#endif
- rc = boot_update_security_counter(0, selected_slot,
- selected_image_header);
- if (rc != 0) {
- BOOT_LOG_ERR("Security counter update failed after image "
- "validation.");
- goto out;
+ slot_usage[BOOT_CURR_IMG(state)].slot_available[active_slot] = false;
+ slot_usage[BOOT_CURR_IMG(state)].active_slot = NO_ACTIVE_SLOT;
+ continue;
}
-#ifdef MCUBOOT_DIRECT_XIP_REVERT
+
+ /* Valid image loaded from a slot, go to next image. */
+ break;
}
+ }
+
+ FIH_RET(FIH_SUCCESS);
+}
+
+/**
+ * Updates the security counter for the current image.
+ *
+ * @param state Boot loader status information.
+ * @param slot_usage Information about the active and available slots.
+ *
+ * @return 0 on success; nonzero on failure.
+ */
+static int
+boot_update_hw_rollback_protection(struct boot_loader_state *state,
+ const struct slot_usage_t slot_usage[])
+{
+#ifdef MCUBOOT_HW_ROLLBACK_PROT
+ int rc;
+
+ /* Update the stored security counter with the newer (active) image's
+ * security counter value.
+ */
+#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
+ /* When the 'revert' mechanism is enabled in direct-xip mode, the
+ * security counter can be increased only after reboot, if the image
+ * has been confirmed at runtime (the image_ok flag has been set).
+ * This way a 'revert' can be performed when it's necessary.
+ */
+ if (slot_usage[BOOT_CURR_IMG(state)].swap_state.image_ok == BOOT_FLAG_SET) {
#endif
-#endif /* MCUBOOT_HW_ROLLBACK_PROT */
-
-#ifdef MCUBOOT_MEASURED_BOOT
- rc = boot_save_boot_status(0, selected_image_header,
- BOOT_IMG_AREA(state, selected_slot));
+ rc = boot_update_security_counter(BOOT_CURR_IMG(state),
+ slot_usage[BOOT_CURR_IMG(state)].active_slot,
+ boot_img_hdr(state, slot_usage[BOOT_CURR_IMG(state)].active_slot));
if (rc != 0) {
- BOOT_LOG_ERR("Failed to add image data to shared area");
+ BOOT_LOG_ERR("Security counter update failed after image "
+ "validation.");
+ return rc;
}
-#endif /* MCUBOOT_MEASURED_BOOT */
+#if defined(MCUBOOT_DIRECT_XIP) && defined(MCUBOOT_DIRECT_XIP_REVERT)
+ }
+#endif
-#ifdef MCUBOOT_DATA_SHARING
- rc = boot_save_shared_data(selected_image_header,
- BOOT_IMG_AREA(state, selected_slot));
- if (rc != 0) {
- BOOT_LOG_ERR("Failed to add data to shared memory area.");
- }
-#endif /* MCUBOOT_DATA_SHARING */
+ return 0;
- BOOT_LOG_INF("Booting image from the %s slot",
- (selected_slot == BOOT_PRIMARY_SLOT) ?
- "primary" : "secondary");
+#else /* MCUBOOT_HW_ROLLBACK_PROT */
+ (void) (state);
+ (void) (slot_usage);
+ return 0;
+#endif
+}
- rsp->br_flash_dev_id =
- BOOT_IMG_AREA(state, selected_slot)->fa_device_id;
- rsp->br_image_off = boot_img_slot_off(state, selected_slot);
- rsp->br_hdr = selected_image_header;
- } else {
- /* No candidate image available */
- rc = BOOT_EBADIMAGE;
+fih_int
+context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
+{
+ struct slot_usage_t slot_usage[BOOT_IMAGE_NUMBER];
+ int rc;
+ fih_int fih_rc = fih_int_encode(0);
+
+ memset(state, 0, sizeof(struct boot_loader_state));
+ memset(slot_usage, 0, sizeof(struct slot_usage_t) * BOOT_IMAGE_NUMBER);
+
+ rc = boot_get_slot_usage(state, slot_usage);
+ if (rc != 0) {
goto out;
}
+#if (BOOT_IMAGE_NUMBER > 1)
+ while (true) {
+#endif
+ FIH_CALL(boot_load_and_validate_images, fih_rc, state, slot_usage);
+ if (fih_not_eq(fih_rc, FIH_SUCCESS)) {
+ goto out;
+ }
+
+#if (BOOT_IMAGE_NUMBER > 1)
+ rc = boot_verify_dependencies(state, slot_usage);
+ if (rc != 0) {
+ /* Dependency check failed for an image, it has been removed from
+ * SRAM in case of MCUBOOT_RAM_LOAD strategy, and set to
+ * unavailable. Try to load an image from another slot.
+ */
+ continue;
+ }
+ /* Dependency check was successful. */
+ break;
+ }
+#endif
+
+ IMAGES_ITER(BOOT_CURR_IMG(state)) {
+ rc = boot_update_hw_rollback_protection(state, slot_usage);
+ if (rc != 0) {
+ goto out;
+ }
+
+ rc = boot_add_shared_data(state, slot_usage[BOOT_CURR_IMG(state)].active_slot);
+ if (rc != 0) {
+ goto out;
+ }
+ }
+
+ /* All image loaded successfully. */
+#ifdef MCUBOOT_HAVE_LOGGING
+ print_loaded_images(state, slot_usage);
+#endif
+
+ fill_rsp(state, slot_usage, rsp);
+
out:
- for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
- flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
- }
+ close_all_flash_areas(state);
- if (rc) {
- fih_rc = fih_int_encode(rc);
- }
+ if (fih_eq(fih_rc, FIH_SUCCESS)) {
+ fih_rc = fih_int_encode(rc);
+ }
- FIH_RET(fih_rc);
+ FIH_RET(fih_rc);
}
#endif /* MCUBOOT_DIRECT_XIP || MCUBOOT_RAM_LOAD */