Boot: Sync MCUBoot code base

This patch performs a partial synchronization between the MCUBoot files
in TF-M and in the original repository. The hash of the source commit
in the original MCUBoot repo: 3c469bc698a9767859ed73cd0201c44161204d5c.

Change-Id: I244b47f21ebdfc73381accc007ee88737f7ccdf7
Signed-off-by: David Vincze <david.vincze@arm.com>
diff --git a/bl2/ext/mcuboot/bootutil/src/bootutil_misc.c b/bl2/ext/mcuboot/bootutil/src/bootutil_misc.c
index b4c6ee7..5ad8bcf 100644
--- a/bl2/ext/mcuboot/bootutil/src/bootutil_misc.c
+++ b/bl2/ext/mcuboot/bootutil/src/bootutil_misc.c
@@ -112,27 +112,45 @@
     return BOOT_FLAG_SET;
 }
 
+/**
+ * Determines if a status source table is satisfied by the specified magic
+ * code.
+ *
+ * @param tbl_val               A magic field from a status source table.
+ * @param val                   The magic value in a trailer, encoded as a
+ *                                  BOOT_MAGIC_[...].
+ *
+ * @return                      1 if the two values are compatible;
+ *                              0 otherwise.
+ */
+int
+boot_magic_compatible_check(uint8_t tbl_val, uint8_t val)
+{
+    switch (tbl_val) {
+    case BOOT_MAGIC_ANY:
+        return 1;
+
+    case BOOT_MAGIC_NOTGOOD:
+        return val != BOOT_MAGIC_GOOD;
+
+    default:
+        return tbl_val == val;
+    }
+}
+
 uint32_t
-boot_slots_trailer_sz(uint8_t min_write_sz)
+boot_trailer_sz(uint8_t min_write_sz)
 {
     return /* state for all sectors */
            BOOT_STATUS_MAX_ENTRIES * BOOT_STATUS_STATE_COUNT * min_write_sz +
-           BOOT_MAX_ALIGN * 3 /* copy_done + image_ok + swap_size */        +
-           BOOT_MAGIC_SZ;
-}
-
-static uint32_t
-boot_scratch_trailer_sz(uint8_t min_write_sz)
-{
-    return BOOT_STATUS_STATE_COUNT * min_write_sz +  /* state for one sector */
-           BOOT_MAX_ALIGN * 2                     +  /* image_ok + swap_size */
+           /* swap_type + copy_done + image_ok + swap_size */
+           BOOT_MAX_ALIGN * 4 +
            BOOT_MAGIC_SZ;
 }
 
 static uint32_t
 boot_magic_off(const struct flash_area *fap)
 {
-    assert(offsetof(struct image_trailer, magic) == 16);
     return fap->fa_size - BOOT_MAGIC_SZ;
 }
 
@@ -158,43 +176,34 @@
 
     elem_sz = flash_area_align(fap);
 
-    if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
-        off_from_end = boot_scratch_trailer_sz(elem_sz);
-    } else {
-        off_from_end = boot_slots_trailer_sz(elem_sz);
-    }
+    off_from_end = boot_trailer_sz(elem_sz);
 
     assert(off_from_end <= fap->fa_size);
     return fap->fa_size - off_from_end;
 }
 
+uint32_t
+boot_swap_type_off(const struct flash_area *fap)
+{
+    return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3;
+}
+
 static uint32_t
 boot_copy_done_off(const struct flash_area *fap)
 {
-    assert(fap->fa_id != FLASH_AREA_IMAGE_SCRATCH);
-    assert(offsetof(struct image_trailer, copy_done) == 0);
     return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
 }
 
 static uint32_t
 boot_image_ok_off(const struct flash_area *fap)
 {
-    assert(offsetof(struct image_trailer, image_ok) == 8);
     return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN;
 }
 
 static uint32_t
 boot_swap_size_off(const struct flash_area *fap)
 {
-    /*
-     * The "swap_size" field if located just before the trailer.
-     * The scratch slot doesn't store "copy_done"...
-     */
-    if (fap->fa_id == FLASH_AREA_IMAGE_SCRATCH) {
-        return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 2;
-    }
-
-    return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3;
+    return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 4;
 }
 
 int
@@ -216,22 +225,31 @@
         state->magic = boot_magic_decode(magic);
     }
 
-    if (fap->fa_id != FLASH_AREA_IMAGE_SCRATCH) {
-        off = boot_copy_done_off(fap);
-        rc = flash_area_read_is_empty(fap, off, &state->copy_done,
-                                      sizeof state->copy_done);
-        if (rc < 0) {
-            return BOOT_EFLASH;
-        }
-        if (rc == 1) {
-            state->copy_done = BOOT_FLAG_UNSET;
-        } else {
-            state->copy_done = boot_flag_decode(state->copy_done);
-        }
+    off = boot_swap_type_off(fap);
+    rc = flash_area_read_is_empty(fap, off, &state->swap_type,
+            sizeof state->swap_type);
+    if (rc < 0) {
+        return BOOT_EFLASH;
+    }
+    if (rc == 1 || state->swap_type > BOOT_SWAP_TYPE_REVERT) {
+        state->swap_type = BOOT_SWAP_TYPE_NONE;
+    }
+
+    off = boot_copy_done_off(fap);
+    rc = flash_area_read_is_empty(fap, off, &state->copy_done,
+            sizeof state->copy_done);
+    if (rc < 0) {
+        return BOOT_EFLASH;
+    }
+    if (rc == 1) {
+        state->copy_done = BOOT_FLAG_UNSET;
+    } else {
+        state->copy_done = boot_flag_decode(state->copy_done);
     }
 
     off = boot_image_ok_off(fap);
-    rc = flash_area_read_is_empty(fap, off, &state->image_ok, sizeof state->image_ok);
+    rc = flash_area_read_is_empty(fap, off, &state->image_ok,
+                                  sizeof state->image_ok);
     if (rc < 0) {
         return BOOT_EFLASH;
     }
@@ -341,6 +359,8 @@
 
     off = boot_magic_off(fap);
 
+    BOOT_LOG_DBG("writing magic; fa_id=%d off=0x%x (0x%x)",
+                 fap->fa_id, off, fap->fa_off + off);
     rc = flash_area_write(fap, off, boot_img_magic, BOOT_MAGIC_SZ);
     if (rc != 0) {
         return BOOT_EFLASH;
@@ -350,30 +370,19 @@
 }
 
 static int
-boot_write_flag(int flag, const struct flash_area *fap)
+boot_write_trailer_byte(const struct flash_area *fap, uint32_t off,
+                        uint8_t val)
 {
-    uint32_t off;
-    int rc;
     uint8_t buf[BOOT_MAX_ALIGN];
     uint8_t align;
     uint8_t erased_val;
-
-    switch (flag) {
-    case BOOT_FLAG_COPY_DONE:
-        off = boot_copy_done_off(fap);
-        break;
-    case BOOT_FLAG_IMAGE_OK:
-        off = boot_image_ok_off(fap);
-        break;
-    default:
-        return BOOT_EBADARGS;
-    }
+    int rc;
 
     align = flash_area_align(fap);
     assert(align <= BOOT_MAX_ALIGN);
     erased_val = flash_area_erased_val(fap);
     memset(buf, erased_val, BOOT_MAX_ALIGN);
-    buf[0] = BOOT_FLAG_SET;
+    buf[0] = val;
 
     rc = flash_area_write(fap, off, buf, align);
     if (rc != 0) {
@@ -386,13 +395,39 @@
 int
 boot_write_copy_done(const struct flash_area *fap)
 {
-    return boot_write_flag(BOOT_FLAG_COPY_DONE, fap);
+    uint32_t off;
+
+    off = boot_copy_done_off(fap);
+    BOOT_LOG_DBG("writing copy_done; fa_id=%d off=0x%x (0x%x)",
+                 fap->fa_id, off, fap->fa_off + off);
+    return boot_write_trailer_byte(fap, off, BOOT_FLAG_SET);
 }
 
 int
 boot_write_image_ok(const struct flash_area *fap)
 {
-    return boot_write_flag(BOOT_FLAG_IMAGE_OK, fap);
+    uint32_t off;
+
+    off = boot_image_ok_off(fap);
+    BOOT_LOG_DBG("writing image_ok; fa_id=%d off=0x%x (0x%x)",
+                 fap->fa_id, off, fap->fa_off + off);
+    return boot_write_trailer_byte(fap, off, BOOT_FLAG_SET);
+}
+
+/**
+ * Writes the specified value to the `swap-type` field of an image trailer.
+ * This value is persisted so that the boot loader knows what swap operation to
+ * resume in case of an unexpected reset.
+ */
+int
+boot_write_swap_type(const struct flash_area *fap, uint8_t swap_type)
+{
+    uint32_t off;
+
+    off = boot_swap_type_off(fap);
+    BOOT_LOG_DBG("writing swap_type; fa_id=%d off=0x%x (0x%x), swap_type=0x%x",
+                 fap->fa_id, off, fap->fa_off + off, swap_type);
+    return boot_write_trailer_byte(fap, off, swap_type);
 }
 
 int
@@ -414,6 +449,9 @@
     memset(buf, erased_val, BOOT_MAX_ALIGN);
     memcpy(buf, (uint8_t *)&swap_size, sizeof(swap_size));
 
+    BOOT_LOG_DBG("writing swap_size; fa_id=%d off=0x%x (0x%x)",
+                 fap->fa_id, off, fap->fa_off + off);
+
     rc = flash_area_write(fap, off, buf, align);
     if (rc != 0) {
         return BOOT_EFLASH;
@@ -445,10 +483,10 @@
     for (i = 0; i < BOOT_SWAP_TABLES_COUNT; i++) {
         table = boot_swap_tables + i;
 
-        if ((table->magic_primary_slot == BOOT_MAGIC_ANY     ||
-                table->magic_primary_slot == primary_slot.magic) &&
-            (table->magic_secondary_slot == BOOT_MAGIC_ANY   ||
-                table->magic_secondary_slot == secondary_slot.magic) &&
+        if (boot_magic_compatible_check(table->magic_primary_slot,
+                                        primary_slot.magic) &&
+            boot_magic_compatible_check(table->magic_secondary_slot,
+                                        secondary_slot.magic) &&
             (table->image_ok_primary_slot == BOOT_FLAG_ANY   ||
                 table->image_ok_primary_slot == primary_slot.image_ok) &&
             (table->image_ok_secondary_slot == BOOT_FLAG_ANY ||
@@ -487,6 +525,7 @@
 {
     const struct flash_area *fap = NULL;
     struct boot_swap_state state_secondary_slot;
+    uint8_t swap_type;
     int rc;
 
     rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SECONDARY,
@@ -512,13 +551,34 @@
             rc = boot_write_image_ok(fap);
         }
 
+        if (rc == 0) {
+            if (permanent) {
+                swap_type = BOOT_SWAP_TYPE_PERM;
+            } else {
+                swap_type = BOOT_SWAP_TYPE_TEST;
+            }
+            rc = boot_write_swap_type(fap, swap_type);
+        }
+
         flash_area_close(fap);
         return rc;
 
+    case BOOT_MAGIC_BAD:
+        /* The image slot is corrupt.  There is no way to recover, so erase the
+         * slot to allow future upgrades.
+         */
+        rc = flash_area_open(FLASH_AREA_IMAGE_SECONDARY, &fap);
+        if (rc != 0) {
+            return BOOT_EFLASH;
+        }
+
+        flash_area_erase(fap, 0, fap->fa_size);
+        flash_area_close(fap);
+        return BOOT_EBADIMAGE;
+
     default:
-        /* XXX: Temporary assert. */
         assert(0);
-        return -1;
+        return BOOT_EBADIMAGE;
     }
 }