boot: Add free space check for swap without scratch

Add a missing test which ensures that there is enough free sectors to
perform an upgrade when using the move strategy; this basically checks
that the sectors used by the trailer don't overlap the last sector
required for a move up operation.

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 99c94dd..d58ed41 100644
--- a/boot/bootutil/src/bootutil_priv.h
+++ b/boot/bootutil/src/bootutil_priv.h
@@ -280,6 +280,7 @@
                      const struct flash_area *fap_dst,
                      uint32_t off_src, uint32_t off_dst, uint32_t sz);
 int boot_erase_region(const struct flash_area *fap, uint32_t off, uint32_t sz);
+bool boot_status_is_reset(const struct boot_status *bs);
 
 #ifdef MCUBOOT_ENC_IMAGES
 int boot_write_enc_key(const struct flash_area *fap, uint8_t slot,
diff --git a/boot/bootutil/src/swap_move.c b/boot/bootutil/src/swap_move.c
index b18c206..689e987 100644
--- a/boot/bootutil/src/swap_move.c
+++ b/boot/bootutil/src/swap_move.c
@@ -418,27 +418,51 @@
          uint32_t copy_size)
 {
     uint32_t sz;
+    uint32_t sector_sz;
     uint32_t idx;
-    uint32_t slot_size;
+    uint32_t trailer_sz;
+    uint32_t first_trailer_idx;
     uint8_t image_index;
     const struct flash_area *fap_pri;
     const struct flash_area *fap_sec;
     int rc;
 
-    slot_size = 0;
+    sz = 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);
+    sector_sz = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, 0);
     while (1) {
-        slot_size += sz;
+        sz += sector_sz;
         /* Skip to next sector because all sectors will be moved up. */
         g_last_idx++;
-        if (slot_size >= copy_size) {
+        if (sz >= copy_size) {
             break;
         }
     }
 
+    /*
+     * When starting a new swap upgrade, check that there is enough space.
+     */
+    if (boot_status_is_reset(bs)) {
+        sz = 0;
+        trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
+        first_trailer_idx = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
+
+        while (1) {
+            sz += sector_sz;
+            if  (sz >= trailer_sz) {
+                break;
+            }
+            first_trailer_idx--;
+        }
+
+        if (g_last_idx >= first_trailer_idx) {
+            BOOT_LOG_WRN("Not enough free space to run swap upgrade");
+            bs->swap_type = BOOT_SWAP_TYPE_NONE;
+            return;
+        }
+    }
+
     image_index = BOOT_CURR_IMG(state);
 
     rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index), &fap_pri);
@@ -449,13 +473,11 @@
 
     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);
+                boot_move_sector_up(idx, sector_sz, state, bs, fap_pri, fap_sec);
             }
             idx--;
         }
@@ -467,7 +489,7 @@
     idx = 1;
     while (idx <= g_last_idx) {
         if (idx >= bs->idx) {
-            boot_swap_sectors(idx, sz, state, bs, fap_pri, fap_sec);
+            boot_swap_sectors(idx, sector_sz, state, bs, fap_pri, fap_sec);
         }
         idx++;
     }