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/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h
index 70a1b0d..6b298f4 100644
--- a/boot/bootutil/src/bootutil_priv.h
+++ b/boot/bootutil/src/bootutil_priv.h
@@ -62,16 +62,24 @@
 /** Number of image slots in flash; currently limited to two. */
 #define BOOT_NUM_SLOTS                  2
 
-#if !defined(MCUBOOT_OVERWRITE_ONLY)
+#if defined(MCUBOOT_OVERWRITE_ONLY) && defined(MCUBOOT_SWAP_USING_MOVE)
+#error "Please enable only one of MCUBOOT_OVERWRITE_ONLY or MCUBOOT_SWAP_USING_MOVE"
+#endif
+
+#if !defined(MCUBOOT_OVERWRITE_ONLY) && !defined(MCUBOOT_SWAP_USING_MOVE)
 #define MCUBOOT_SWAP_USING_SCRATCH 1
 #endif
 
+#define BOOT_STATUS_OP_MOVE     1
+#define BOOT_STATUS_OP_SWAP     2
+
 /*
  * Maintain state of copy progress.
  */
 struct boot_status {
     uint32_t idx;         /* Which area we're operating on */
     uint8_t state;        /* Which part of the swapping process are we at */
+    uint8_t op;           /* What operation are we performing? */
     uint8_t use_scratch;  /* Are status bytes ever written to scratch? */
     uint8_t swap_type;    /* The type of swap in effect */
     uint32_t swap_size;   /* Total size of swapped image */
@@ -178,8 +186,15 @@
 #error "Too few sectors, please increase BOOT_MAX_IMG_SECTORS to at least 32"
 #endif
 
-/** Maximum number of image sectors supported by the bootloader. */
+#if MCUBOOT_SWAP_USING_MOVE
+#define BOOT_STATUS_MOVE_STATE_COUNT    1
+#define BOOT_STATUS_SWAP_STATE_COUNT    2
+#define BOOT_STATUS_STATE_COUNT         (BOOT_STATUS_MOVE_STATE_COUNT + BOOT_STATUS_SWAP_STATE_COUNT)
+#else
 #define BOOT_STATUS_STATE_COUNT         3
+#endif
+
+/** Maximum number of image sectors supported by the bootloader. */
 #define BOOT_STATUS_MAX_ENTRIES         BOOT_MAX_IMG_SECTORS
 
 #define BOOT_PRIMARY_SLOT               0
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.
          */
diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c
new file mode 100644
index 0000000..6955474
--- /dev/null
+++ b/boot/bootutil/src/swap_move.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2019 JUUL Labs
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bootutil/bootutil.h"
+#include "bootutil_priv.h"
+#include "swap_priv.h"
+#include "bootutil/bootutil_log.h"
+
+#include "mcuboot_config/mcuboot_config.h"
+
+MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
+
+#ifdef MCUBOOT_SWAP_USING_MOVE
+
+#if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
+/*
+ * FIXME: this might have to be updated for threaded sim
+ */
+int boot_status_fails = 0;
+#define BOOT_STATUS_ASSERT(x)                \
+    do {                                     \
+        if (!(x)) {                          \
+            boot_status_fails++;             \
+        }                                    \
+    } while (0)
+#else
+#define BOOT_STATUS_ASSERT(x) ASSERT(x)
+#endif
+
+static uint32_t g_last_idx = UINT32_MAX;
+
+int
+boot_read_image_header(struct boot_loader_state *state, int slot,
+                       struct image_header *out_hdr, struct boot_status *bs)
+{
+    const struct flash_area *fap;
+    uint32_t off;
+    uint32_t sz;
+    int area_id;
+    int rc;
+
+#if (BOOT_IMAGE_NUMBER == 1)
+    (void)state;
+#endif
+
+    off = 0;
+    if (bs) {
+        sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
+        if (bs->op == BOOT_STATUS_OP_MOVE) {
+            if (slot == 0 && bs->idx > g_last_idx) {
+                /* second sector */
+                off = sz;
+            }
+        } else if (bs->op == BOOT_STATUS_OP_SWAP) {
+            if (bs->idx > 1 && bs->idx <= g_last_idx) {
+                if (slot == 0) {
+                    slot = 1;
+                } else {
+                    slot = 0;
+                }
+            } else if (bs->idx == 1) {
+                if (slot == 0) {
+                    off = sz;
+                }
+                if (slot == 1 && bs->state == 2) {
+                    slot = 0;
+                }
+            }
+        }
+    }
+
+    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
+    rc = flash_area_open(area_id, &fap);
+    if (rc != 0) {
+        rc = BOOT_EFLASH;
+        goto done;
+    }
+
+    rc = flash_area_read(fap, off, out_hdr, sizeof *out_hdr);
+    if (rc != 0) {
+        rc = BOOT_EFLASH;
+        goto done;
+    }
+
+    /* We only know where the headers are located when bs is valid */
+    if (bs != NULL && out_hdr->ih_magic != IMAGE_MAGIC) {
+        rc = -1;
+        goto done;
+    }
+
+    rc = 0;
+
+done:
+    flash_area_close(fap);
+    return rc;
+}
+
+int
+swap_read_status_bytes(const struct flash_area *fap,
+        struct boot_loader_state *state, struct boot_status *bs)
+{
+    uint32_t off;
+    uint8_t status;
+    int max_entries;
+    int found_idx;
+    uint8_t write_sz;
+    int move_entries;
+    int rc;
+    int last_rc;
+    int erased_sections;
+    int i;
+
+    max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
+    if (max_entries < 0) {
+        return BOOT_EBADARGS;
+    }
+
+    erased_sections = 0;
+    found_idx = -1;
+    /* skip erased sectors at the end */
+    last_rc = 1;
+    write_sz = BOOT_WRITE_SZ(state);
+    off = boot_status_off(fap);
+    for (i = max_entries; i > 0; i--) {
+        rc = flash_area_read_is_empty(fap, off + (i - 1) * write_sz, &status, 1);
+        if (rc < 0) {
+            return BOOT_EFLASH;
+        }
+
+        if (rc == 1) {
+            if (rc != last_rc) {
+                erased_sections++;
+            }
+        } else {
+            if (found_idx == -1) {
+                found_idx = i;
+            }
+        }
+        last_rc = rc;
+    }
+
+    if (erased_sections > 1) {
+        /* This means there was an error writing status on the last
+         * swap. Tell user and move on to validation!
+         */
+        BOOT_LOG_ERR("Detected inconsistent status!");
+
+#if !defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
+        /* With validation of the primary slot disabled, there is no way
+         * to be sure the swapped primary slot is OK, so abort!
+         */
+        assert(0);
+#endif
+    }
+
+    move_entries = BOOT_MAX_IMG_SECTORS * BOOT_STATUS_MOVE_STATE_COUNT;
+    if (found_idx == -1) {
+        /* no swap status found; nothing to do */
+    } else if (found_idx < move_entries) {
+        bs->op = BOOT_STATUS_OP_MOVE;
+        bs->idx = (found_idx  / BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_IDX_0;
+        bs->state = (found_idx % BOOT_STATUS_MOVE_STATE_COUNT) + BOOT_STATUS_STATE_0;;
+    } else {
+        bs->op = BOOT_STATUS_OP_SWAP;
+        bs->idx = ((found_idx - move_entries) / BOOT_STATUS_SWAP_STATE_COUNT) + BOOT_STATUS_IDX_0;
+        bs->state = ((found_idx - move_entries) % BOOT_STATUS_SWAP_STATE_COUNT) + BOOT_STATUS_STATE_0;
+    }
+
+    return 0;
+}
+
+uint32_t
+boot_status_internal_off(const struct boot_status *bs, int elem_sz)
+{
+    uint32_t off;
+    int idx_sz;
+
+    idx_sz = elem_sz * ((bs->op == BOOT_STATUS_OP_MOVE) ?
+            BOOT_STATUS_MOVE_STATE_COUNT : BOOT_STATUS_SWAP_STATE_COUNT);
+
+    off = ((bs->op == BOOT_STATUS_OP_MOVE) ?
+               0 : (BOOT_MAX_IMG_SECTORS * BOOT_STATUS_MOVE_STATE_COUNT * elem_sz)) +
+           (bs->idx - BOOT_STATUS_IDX_0) * idx_sz +
+           (bs->state - BOOT_STATUS_STATE_0) * elem_sz;
+
+    return off;
+}
+
+int
+boot_slots_compatible(struct boot_loader_state *state)
+{
+    size_t num_sectors;
+    size_t i;
+
+    num_sectors = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
+    if (num_sectors != boot_img_num_sectors(state, BOOT_SECONDARY_SLOT)) {
+        BOOT_LOG_WRN("Cannot upgrade: slots don't have same amount of sectors");
+        return 0;
+    }
+
+    if (num_sectors > BOOT_MAX_IMG_SECTORS) {
+        BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
+        return 0;
+    }
+
+    for (i = 0; i < num_sectors; i++) {
+        if (boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i) !=
+                boot_img_sector_size(state, BOOT_SECONDARY_SLOT, i)) {
+            BOOT_LOG_WRN("Cannot upgrade: not same sector layout");
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+#define BOOT_LOG_SWAP_STATE(area, state)                            \
+    BOOT_LOG_INF("%s: magic=%s, swap_type=0x%x, copy_done=0x%x, "   \
+                 "image_ok=0x%x",                                   \
+                 (area),                                            \
+                 ((state)->magic == BOOT_MAGIC_GOOD ? "good" :      \
+                  (state)->magic == BOOT_MAGIC_UNSET ? "unset" :    \
+                  "bad"),                                           \
+                 (state)->swap_type,                                \
+                 (state)->copy_done,                                \
+                 (state)->image_ok)
+
+int
+swap_status_source(struct boot_loader_state *state)
+{
+    struct boot_swap_state state_primary_slot;
+    int rc;
+    uint8_t source;
+    uint8_t image_index;
+
+#if (BOOT_IMAGE_NUMBER == 1)
+    (void)state;
+#endif
+
+    image_index = BOOT_CURR_IMG(state);
+
+    rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
+            &state_primary_slot);
+    assert(rc == 0);
+
+    BOOT_LOG_SWAP_STATE("Primary image", &state_primary_slot);
+
+    if (state_primary_slot.magic == BOOT_MAGIC_GOOD &&
+            state_primary_slot.copy_done == BOOT_FLAG_UNSET) {
+
+        source = BOOT_STATUS_SOURCE_PRIMARY_SLOT;
+
+        BOOT_LOG_INF("Boot source: primary slot");
+        return source;
+    }
+
+    BOOT_LOG_INF("Boot source: none");
+    return BOOT_STATUS_SOURCE_NONE;
+}
+
+/*
+ * "Moves" the sector located at idx - 1 to idx.
+ */
+static void
+boot_move_sector_up(int idx, uint32_t sz, struct boot_loader_state *state,
+        struct boot_status *bs, const struct flash_area *fap_pri,
+        const struct flash_area *fap_sec)
+{
+    uint32_t new_off;
+    uint32_t old_off;
+    int rc;
+
+    /*
+     * FIXME: assuming sectors of size == sz, a single off variable
+     * would be enough
+     */
+
+    /* Calculate offset from start of image area. */
+    new_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
+    old_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
+
+    if (bs->idx == BOOT_STATUS_IDX_0) {
+        rc = swap_erase_trailer_sectors(state, fap_pri);
+        assert(rc == 0);
+
+        rc = swap_status_init(state, fap_pri, bs);
+        assert(rc == 0);
+
+        rc = swap_erase_trailer_sectors(state, fap_sec);
+        assert(rc == 0);
+    }
+
+    rc = boot_erase_region(fap_pri, new_off, sz);
+    assert(rc == 0);
+
+    rc = boot_copy_region(state, fap_pri, fap_pri, old_off, new_off, sz);
+    assert(rc == 0);
+
+    rc = boot_write_status(state, bs);
+
+    bs->idx++;
+    BOOT_STATUS_ASSERT(rc == 0);
+}
+
+static void
+boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
+        struct boot_status *bs, const struct flash_area *fap_pri,
+        const struct flash_area *fap_sec)
+{
+    uint32_t pri_off;
+    uint32_t pri_up_off;
+    uint32_t sec_off;
+    int rc;
+
+    pri_up_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
+    pri_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx - 1);
+    sec_off = boot_img_sector_off(state, BOOT_SECONDARY_SLOT, idx - 1);
+
+    if (bs->state == BOOT_STATUS_STATE_0) {
+        rc = boot_erase_region(fap_pri, pri_off, sz);
+        assert(rc == 0);
+
+        rc = boot_copy_region(state, fap_sec, fap_pri, sec_off, pri_off, sz);
+        assert(rc == 0);
+
+        rc = boot_write_status(state, bs);
+        bs->state = BOOT_STATUS_STATE_1;
+        BOOT_STATUS_ASSERT(rc == 0);
+    }
+
+    if (bs->state == BOOT_STATUS_STATE_1) {
+        rc = boot_erase_region(fap_sec, sec_off, sz);
+        assert(rc == 0);
+
+        rc = boot_copy_region(state, fap_pri, fap_sec, pri_up_off, sec_off, sz);
+        assert(rc == 0);
+
+        rc = boot_write_status(state, bs);
+        bs->idx++;
+        bs->state = BOOT_STATUS_STATE_0;
+        BOOT_STATUS_ASSERT(rc == 0);
+    }
+}
+
+/*
+ * When starting a revert the swap status exists in the primary slot, and
+ * the status in the secondary slot is erased. To start the swap, the status
+ * area in the primary slot must be re-initialized; if during the small
+ * window of time between re-initializing it and writing the first metadata
+ * a reset happens, the swap process is broken and cannot be resumed.
+ *
+ * This function handles the issue by making the revert look like a permanent
+ * upgrade (by initializing the secondary slot).
+ */
+void
+fixup_revert(const struct boot_loader_state *state, struct boot_status *bs,
+        const struct flash_area *fap_sec, uint8_t sec_id)
+{
+    struct boot_swap_state swap_state;
+    int rc;
+
+#if (BOOT_IMAGE_NUMBER == 1)
+    (void)state;
+#endif
+
+    /* No fixup required */
+    if (bs->swap_type != BOOT_SWAP_TYPE_REVERT ||
+        bs->op != BOOT_STATUS_OP_MOVE ||
+        bs->idx != BOOT_STATUS_IDX_0) {
+        return;
+    }
+
+    rc = boot_read_swap_state_by_id(sec_id, &swap_state);
+    assert(rc == 0);
+
+    BOOT_LOG_SWAP_STATE("Secondary image", &swap_state);
+
+    if (swap_state.magic == BOOT_MAGIC_UNSET) {
+        rc = swap_erase_trailer_sectors(state, fap_sec);
+        assert(rc == 0);
+
+        rc = boot_write_image_ok(fap_sec);
+        assert(rc == 0);
+
+        rc = boot_write_swap_size(fap_sec, bs->swap_size);
+        assert(rc == 0);
+
+#ifdef MCUBOOT_ENC_IMAGES
+        rc = boot_write_enc_key(fap_sec, 0, bs->enckey[0]);
+        assert(rc == 0);
+
+        rc = boot_write_enc_key(fap_sec, 1, bs->enckey[1]);
+        assert(rc == 0);
+#endif
+
+        rc = boot_write_magic(fap_sec);
+        assert(rc == 0);
+    }
+}
+
+void
+swap_run(struct boot_loader_state *state, struct boot_status *bs,
+         uint32_t copy_size)
+{
+    uint32_t sz;
+    uint32_t idx;
+    uint32_t slot_size;
+    uint8_t image_index;
+    const struct flash_area *fap_pri;
+    const struct flash_area *fap_sec;
+    int rc;
+
+    slot_size = 0;
+    g_last_idx = 0;
+
+    //FIXME: assume all sectors of same size and just do math here...
+    sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
+    while (1) {
+        slot_size += sz;
+        /* Skip to next sector because all sectors will be moved up. */
+        g_last_idx++;
+        if (slot_size >= copy_size) {
+            break;
+        }
+    }
+
+    image_index = BOOT_CURR_IMG(state);
+
+    rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap_pri);
+    assert (rc == 0);
+
+    rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY(image_index), &fap_sec);
+    assert (rc == 0);
+
+    fixup_revert(state, bs, fap_sec, FLASH_AREA_IMAGE_SECONDARY(image_index));
+
+    /* FIXME: assure last sector does not overrun trailer */
+
+    if (bs->op == BOOT_STATUS_OP_MOVE) {
+        idx = g_last_idx;
+        while (idx > 0) {
+            if (idx <= (g_last_idx - bs->idx + 1)) {
+                boot_move_sector_up(idx, sz, state, bs, fap_pri, fap_sec);
+            }
+            idx--;
+        }
+        bs->idx = BOOT_STATUS_IDX_0;
+    }
+
+    bs->op = BOOT_STATUS_OP_SWAP;
+
+    idx = 1;
+    while (idx <= g_last_idx) {
+        if (idx >= bs->idx) {
+            boot_swap_sectors(idx, sz, state, bs, fap_pri, fap_sec);
+        }
+        idx++;
+    }
+
+    flash_area_close(fap_pri);
+    flash_area_close(fap_sec);
+}
+
+#endif
diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c
index bf638bf..588bd28 100644
--- a/boot/bootutil/src/swap_scratch.c
+++ b/boot/bootutil/src/swap_scratch.c
@@ -29,7 +29,7 @@
 
 MCUBOOT_LOG_MODULE_DECLARE(mcuboot);
 
-#if MCUBOOT_SWAP_USING_SCRATCH
+#if !defined(MCUBOOT_SWAP_USING_MOVE)
 
 #if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT)
 /*
@@ -175,7 +175,9 @@
     size_t num_sectors_secondary;
     size_t sz0, sz1;
     size_t primary_slot_sz, secondary_slot_sz;
+#ifndef MCUBOOT_OVERWRITE_ONLY
     size_t scratch_sz;
+#endif
     size_t i, j;
     int8_t smaller;
 
@@ -187,7 +189,9 @@
         return 0;
     }
 
+#ifndef MCUBOOT_OVERWRITE_ONLY
     scratch_sz = boot_scratch_area_size(state);
+#endif
 
     /*
      * The following loop scans all sectors in a linear fashion, assuring that
@@ -228,6 +232,7 @@
             smaller = 2;
             j++;
         }
+#ifndef MCUBOOT_OVERWRITE_ONLY
         if (sz0 == sz1) {
             primary_slot_sz += sz0;
             secondary_slot_sz += sz1;
@@ -240,6 +245,7 @@
             }
             smaller = sz0 = sz1 = 0;
         }
+#endif
     }
 
     if ((i != num_sectors_primary) ||
@@ -412,6 +418,7 @@
     return BOOT_STATUS_SOURCE_NONE;
 }
 
+#ifndef MCUBOOT_OVERWRITE_ONLY
 /**
  * Calculates the number of sectors the scratch area can contain.  A "last"
  * source sector is specified because images are copied backwards in flash
@@ -710,5 +717,6 @@
     }
 
 }
+#endif
 
 #endif