bootutil: add swap without scratch strategy
This implements a swap upgrade that does not use a scratch area. It
works by first moving all sectors in the primary slot up one position,
and then looping on moving sector of index X of the secondary slot to
index X of the primary slot, followed by moving sector X+1 of the
primary slot to X on the secondary slot, for each sector X.
The idea behind this implementation was initially suggested by Jehudi
Maes (@Laczen) and implemented on his own bootloader (ZEPboot).
Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index 1635efc..36ea754 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -286,6 +286,7 @@
boot_status_reset(struct boot_status *bs)
{
memset(bs, 0, sizeof *bs);
+ bs->op = BOOT_STATUS_OP_MOVE;
bs->idx = BOOT_STATUS_IDX_0;
bs->state = BOOT_STATUS_STATE_0;
bs->swap_type = BOOT_SWAP_TYPE_NONE;
@@ -294,7 +295,9 @@
bool
boot_status_is_reset(const struct boot_status *bs)
{
- return (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0);
+ return (bs->op == BOOT_STATUS_OP_MOVE &&
+ bs->idx == BOOT_STATUS_IDX_0 &&
+ bs->state == BOOT_STATUS_STATE_0);
}
/**
@@ -650,16 +653,25 @@
#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_SECONDARY(image_index) ||
+ fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(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);
+#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);
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);
+ }
+#endif
if (IS_ENCRYPTED(hdr)) {
blk_sz = chunk_sz;
idx = 0;
@@ -1357,6 +1369,21 @@
}
#endif
+#ifdef MCUBOOT_SWAP_USING_MOVE
+ /*
+ * 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);
+ if (rc != 0) {
+ /* Continue with next image if there is one. */
+ BOOT_LOG_WRN("Failed reading image headers; Image=%u",
+ BOOT_CURR_IMG(state));
+ BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
+ return;
+ }
+#endif
+
/* Determine if we rebooted in the middle of an image swap
* operation. If a partial swap was detected, complete it.
*/