Implement new swap scheme for devices with large erase size using scratch with status area
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index e1f1e54..e4c0a3f 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -106,7 +106,7 @@
* Compute the total size of the given image. Includes the size of
* the TLVs.
*/
-#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
+#if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
static int
boot_read_image_size(struct boot_loader_state *state, int slot, uint32_t *size)
{
@@ -166,6 +166,7 @@
#endif /* !MCUBOOT_OVERWRITE_ONLY */
#if !defined(MCUBOOT_RAM_LOAD)
+
static uint32_t
boot_write_sz(struct boot_loader_state *state)
{
@@ -241,6 +242,11 @@
out_sectors = state->scratch.sectors;
out_num_sectors = &state->scratch.num_sectors;
#endif
+#if MCUBOOT_SWAP_USING_STATUS
+ } else if (flash_area == FLASH_AREA_IMAGE_SWAP_STATUS) {
+ out_sectors = state->status.sectors;
+ out_num_sectors = &state->status.num_sectors;
+#endif
} else {
return BOOT_EFLASH;
}
@@ -278,6 +284,13 @@
return BOOT_EFLASH;
}
+#if MCUBOOT_SWAP_USING_STATUS
+ rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SWAP_STATUS);
+ if (rc != 0) {
+ return BOOT_EFLASH;
+ }
+#endif
+
#if MCUBOOT_SWAP_USING_SCRATCH
rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
if (rc != 0) {
@@ -318,6 +331,7 @@
bs->state == BOOT_STATUS_STATE_0);
}
+#ifndef MCUBOOT_SWAP_USING_STATUS
/**
* Writes the supplied boot status to the flash file system. The boot status
* contains the current state of an in-progress image copy operation.
@@ -381,6 +395,9 @@
return rc;
}
#endif /* !MCUBOOT_RAM_LOAD */
+
+#endif /* MCUBOOT_SWAP_USING_STATUS */
+
#endif /* !MCUBOOT_DIRECT_XIP */
/*
@@ -525,6 +542,8 @@
#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
@@ -620,6 +639,8 @@
FIH_RET(fih_rc);
}
+ BOOT_LOG_DBG("> boot_validate_slot: fa_id = %d", fap->fa_id);
+
hdr = boot_img_hdr(state, slot);
if (boot_check_header_erased(state, slot) == 0 ||
(hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
@@ -635,11 +656,14 @@
* through mcumgr; so we just get rid of the trailer here, if the header
* is erased.
*/
+ BOOT_LOG_DBG(" * Fix the secondary slot when image is invalid.");
if (slot != BOOT_PRIMARY_SLOT) {
+ BOOT_LOG_DBG(" * Erase secondary image trailer.");
swap_erase_trailer_sectors(state, fap);
}
#endif
+ BOOT_LOG_DBG(" * No bootable image in slot(%d); continue booting from the primary slot.", slot);
/* No bootable image in slot; continue booting from the primary slot. */
fih_rc = fih_int_encode(1);
goto out;
@@ -666,6 +690,7 @@
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);
/* Image is invalid, erase it to prevent further unnecessary
* attempts to validate and boot it.
@@ -679,9 +704,11 @@
goto out;
}
+ /* Image in the secondary slot is valid. */
+
out:
flash_area_close(fap);
-
+ BOOT_LOG_DBG("< boot_validate_slot = %d", fih_int_decode(fih_rc));
FIH_RET(fih_rc);
}
@@ -834,23 +861,27 @@
#ifdef MCUBOOT_ENC_IMAGES
image_index = BOOT_CURR_IMG(state);
- if ((fap_src->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index) ||
- fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) &&
+ if ((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_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))) {
- /* assume the secondary slot as src, needs decryption */
- hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
+ fap_dst->fa_id == 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_SECONDARY(image_index)) {
- /* might need encryption (metadata from the primary slot) */
- hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
+ if (fap_dst->fa_id == 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_SECONDARY(image_index)) {
- hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
+ if (fap_dst->fa_id == FLASH_AREA_IMAGE_PRIMARY(image_index)) {
+ hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
}
#endif
if (IS_ENCRYPTED(hdr)) {
@@ -859,8 +890,13 @@
if (off + bytes_copied < hdr->ih_hdr_size) {
/* do not decrypt header */
blk_off = 0;
- blk_sz = chunk_sz - hdr->ih_hdr_size;
- idx = hdr->ih_hdr_size;
+ if(chunk_sz > hdr->ih_hdr_size) {
+ blk_sz = chunk_sz - hdr->ih_hdr_size;
+ idx = hdr->ih_hdr_size - (off + bytes_copied);
+ } else {
+ /* still in header-area, no need to decrypt */
+ blk_sz = 0;
+ }
} else {
blk_off = ((off + bytes_copied) - hdr->ih_hdr_size) & 0xf;
}
@@ -873,9 +909,11 @@
blk_sz = tlv_off - (off + bytes_copied);
}
}
- boot_encrypt(BOOT_CURR_ENC(state), image_index, fap_src,
+ 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]);
+ }
}
}
#endif
@@ -949,8 +987,12 @@
assert (rc == 0);
sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
+ BOOT_LOG_DBG(" * primary slot sectors: %d", 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);
@@ -994,7 +1036,7 @@
}
#endif
- BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
+ BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%x bytes",
size);
rc = boot_copy_region(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
if (rc != 0) {
@@ -1326,7 +1368,7 @@
if (rc == 0) {
/* All dependencies've been satisfied, continue with next image. */
BOOT_CURR_IMG(state)++;
- } else {
+ } else if (rc == BOOT_EBADVERSION) {
/* Cannot upgrade due to non-met dependencies, so disable all
* image upgrades.
*/
@@ -1335,6 +1377,9 @@
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
}
break;
+ } else {
+ /* Other error happened, images are inconsistent */
+ return rc;
}
}
return rc;
@@ -1356,6 +1401,8 @@
uint8_t swap_type;
#endif
+ BOOT_LOG_DBG("> boot_perform_update: bs->idx = %d", bs->idx);
+
/* At this point there are no aborted swaps. */
#if defined(MCUBOOT_OVERWRITE_ONLY)
rc = boot_copy_image(state, bs);
@@ -1551,6 +1598,8 @@
int rc;
fih_int fih_rc = FIH_FAILURE;
+ BOOT_LOG_DBG("> boot_prepare_image_for_update: image = %d", BOOT_CURR_IMG(state));
+
/* Determine the sector layout of the image slots and scratch area. */
rc = boot_read_sectors(state);
if (rc != 0) {
@@ -1565,6 +1614,7 @@
/* 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);
if (rc != 0) {
/* Continue with next image if there is one. */
BOOT_LOG_WRN("Failed reading image headers; Image=%u",
@@ -1590,12 +1640,13 @@
}
#endif
-#ifdef MCUBOOT_SWAP_USING_MOVE
+#if defined (MCUBOOT_SWAP_USING_MOVE) || defined(MCUBOOT_SWAP_USING_SCRATCH)
/*
* Must re-read image headers because the boot status might
* 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);
#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 ||
@@ -1603,7 +1654,6 @@
#else
if (rc != 0) {
#endif
-
/* Continue with next image if there is one. */
BOOT_LOG_WRN("Failed reading image headers; Image=%u",
BOOT_CURR_IMG(state));
@@ -1642,6 +1692,8 @@
/* Swap has finished set to NONE */
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
} else {
+ BOOT_LOG_DBG(" * There was no partial swap, determine swap type.");
+
/* There was no partial swap, determine swap type. */
if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
@@ -1693,6 +1745,7 @@
/* In that case if slots are not compatible. */
BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
}
+ BOOT_LOG_DBG("< boot_prepare_image_for_update");
}
fih_int
@@ -1716,6 +1769,9 @@
#if MCUBOOT_SWAP_USING_SCRATCH
TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
#endif
+#if MCUBOOT_SWAP_USING_STATUS
+ TARGET_STATIC boot_sector_t status_sectors[BOOT_MAX_SWAP_STATUS_SECTORS];
+#endif
memset(state, 0, sizeof(struct boot_loader_state));
has_upgrade = false;
@@ -1747,6 +1803,9 @@
#if MCUBOOT_SWAP_USING_SCRATCH
state->scratch.sectors = scratch_sectors;
#endif
+#if MCUBOOT_SWAP_USING_STATUS
+ state->status.sectors = status_sectors;
+#endif
/* Open primary and secondary image areas for the duration
* of this call.
@@ -1762,6 +1821,7 @@
assert(rc == 0);
#endif
+ BOOT_LOG_DBG(" * boot_prepare_image_for_update...");
/* Determine swap type and complete swap if it has been aborted. */
boot_prepare_image_for_update(state, &bs);
@@ -1810,6 +1870,8 @@
/* Set the previously determined swap type */
bs.swap_type = BOOT_SWAP_TYPE(state);
+ BOOT_LOG_DBG(" * process swap_type = %d", bs.swap_type);
+
switch (BOOT_SWAP_TYPE(state)) {
case BOOT_SWAP_TYPE_NONE:
break;
@@ -1817,6 +1879,7 @@
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);
assert(rc == 0);
break;
@@ -1827,6 +1890,7 @@
* 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));
/* image_ok needs to be explicitly set to avoid a new revert. */
rc = swap_set_image_ok(BOOT_CURR_IMG(state));
if (rc != 0) {