Boot: Save image sequence number to image trailer

Overload the swap_type field in image trailer to store as an addition
the image sequence number. It indicates which image's swap was
interrupted. It is required by multi image boot to determine which
image the trailer belongs to if boot status is found on scratch area
when the swap operation is resumed.

Change-Id: I6820fd8277931aff4f0db408376eae8b42a030ed
Signed-off-by: Tamas Ban <tamas.ban@arm.com>
Signed-off-by: David Vincze <david.vincze@arm.com>
diff --git a/boot/bootutil/src/bootutil_misc.c b/boot/bootutil/src/bootutil_misc.c
index 8cab4c4..041f6a2 100644
--- a/boot/bootutil/src/bootutil_misc.c
+++ b/boot/bootutil/src/bootutil_misc.c
@@ -17,6 +17,10 @@
  * under the License.
  */
 
+/*
+ * Modifications are Copyright (c) 2019 Arm Limited.
+ */
+
 #include <assert.h>
 #include <string.h>
 #include <inttypes.h>
@@ -194,7 +198,7 @@
 }
 
 uint32_t
-boot_swap_type_off(const struct flash_area *fap)
+boot_swap_info_off(const struct flash_area *fap)
 {
     return fap->fa_size - BOOT_MAGIC_SZ - BOOT_MAX_ALIGN * 3;
 }
@@ -232,6 +236,7 @@
 {
     uint32_t magic[BOOT_MAGIC_ARR_SZ];
     uint32_t off;
+    uint8_t swap_info;
     int rc;
 
     off = boot_magic_off(fap);
@@ -245,14 +250,19 @@
         state->magic = boot_magic_decode(magic);
     }
 
-    off = boot_swap_type_off(fap);
-    rc = flash_area_read_is_empty(fap, off, &state->swap_type,
-            sizeof state->swap_type);
+    off = boot_swap_info_off(fap);
+    rc = flash_area_read_is_empty(fap, off, &swap_info, sizeof swap_info);
     if (rc < 0) {
         return BOOT_EFLASH;
     }
+
+    /* Extract the swap type and image number */
+    state->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
+    state->image_num = BOOT_GET_IMAGE_NUM(swap_info);
+
     if (rc == 1 || state->swap_type > BOOT_SWAP_TYPE_REVERT) {
         state->swap_type = BOOT_SWAP_TYPE_NONE;
+        state->image_num = 0;
     }
 
     off = boot_copy_done_off(fap);
@@ -494,14 +504,18 @@
  * resume in case of an unexpected reset.
  */
 int
-boot_write_swap_type(const struct flash_area *fap, uint8_t swap_type)
+boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
+                     uint8_t image_num)
 {
     uint32_t off;
+    uint8_t swap_info;
 
-    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);
+    BOOT_SET_SWAP_INFO(swap_info, image_num, swap_type);
+    off = boot_swap_info_off(fap);
+    BOOT_LOG_DBG("writing swap_info; fa_id=%d off=0x%x (0x%x), swap_type=0x%x"
+                 " image_num=0x%x",
+                 fap->fa_id, off, fap->fa_off + off, swap_type, image_num);
+    return boot_write_trailer_byte(fap, off, swap_info);
 }
 
 int
@@ -648,7 +662,7 @@
             } else {
                 swap_type = BOOT_SWAP_TYPE_TEST;
             }
-            rc = boot_write_swap_type(fap, swap_type);
+            rc = boot_write_swap_info(fap, swap_type, 0);
         }
 
         flash_area_close(fap);
diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h
index d2871ee..bc35a72 100644
--- a/boot/bootutil/src/bootutil_priv.h
+++ b/boot/bootutil/src/bootutil_priv.h
@@ -17,6 +17,10 @@
  * under the License.
  */
 
+/*
+ * Modifications are Copyright (c) 2019 Arm Limited.
+ */
+
 #ifndef H_BOOTUTIL_PRIV_
 #define H_BOOTUTIL_PRIV_
 
@@ -106,7 +110,7 @@
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *  |                      Swap size (4 octets)                     |
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *  |   Swap type   |           0xff padding (7 octets)             |
+ *  |   Swap info   |           0xff padding (7 octets)             |
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *  |   Copy done   |           0xff padding (7 octets)             |
  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -127,11 +131,27 @@
     uint8_t swap_type;  /* One of the BOOT_SWAP_TYPE_[...] values. */
     uint8_t copy_done;  /* One of the BOOT_FLAG_[...] values. */
     uint8_t image_ok;   /* One of the BOOT_FLAG_[...] values. */
+    uint8_t image_num;  /* Boot status belongs to this image */
 };
 
 #define BOOT_MAX_IMG_SECTORS       MCUBOOT_MAX_IMG_SECTORS
 
 /*
+ * Extract the swap type and image number from image trailers's swap_info
+ * filed.
+ */
+#define BOOT_GET_SWAP_TYPE(swap_info)    ((swap_info) & 0x0F)
+#define BOOT_GET_IMAGE_NUM(swap_info)    ((swap_info) >> 4)
+
+/* Construct the swap_info field from swap type and image number */
+#define BOOT_SET_SWAP_INFO(swap_info, image, type)  {                          \
+                                                    assert((image) < 0xF);     \
+                                                    assert((type)  < 0xF);     \
+                                                    (swap_info) = (image) << 4 \
+                                                                | (type);      \
+                                                    }
+
+/*
  * The current flashmap API does not check the amount of space allocated when
  * loading sector data from the flash device, allowing for smaller counts here
  * would most surely incur in overruns.
@@ -194,7 +214,7 @@
 uint32_t boot_trailer_sz(uint8_t min_write_sz);
 int boot_status_entries(const struct flash_area *fap);
 uint32_t boot_status_off(const struct flash_area *fap);
-uint32_t boot_swap_type_off(const struct flash_area *fap);
+uint32_t boot_swap_info_off(const struct flash_area *fap);
 int boot_read_swap_state(const struct flash_area *fap,
                          struct boot_swap_state *state);
 int boot_read_swap_state_by_id(int flash_area_id,
@@ -204,7 +224,8 @@
 int boot_schedule_test_swap(void);
 int boot_write_copy_done(const struct flash_area *fap);
 int boot_write_image_ok(const struct flash_area *fap);
-int boot_write_swap_type(const struct flash_area *fap, uint8_t swap_type);
+int boot_write_swap_info(const struct flash_area *fap, uint8_t swap_type,
+                         uint8_t image_num);
 int boot_write_swap_size(const struct flash_area *fap, uint32_t swap_size);
 int boot_read_swap_size(uint32_t *swap_size);
 #ifdef MCUBOOT_ENC_IMAGES
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index c6ec34f..fcbf082 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -17,6 +17,10 @@
  * under the License.
  */
 
+/*
+ * Modifications are Copyright (c) 2019 Arm Limited.
+ */
+
 /**
  * This file provides an interface to the boot loader.  Functions defined in
  * this file should only be called while the boot loader is running.
@@ -522,6 +526,7 @@
 {
     const struct flash_area *fap;
     uint32_t off;
+    uint8_t swap_info;
     int status_loc;
     int area_id;
     int rc;
@@ -561,13 +566,15 @@
 
     rc = boot_read_status_bytes(fap, bs);
     if (rc == 0) {
-        off = boot_swap_type_off(fap);
-        rc = flash_area_read_is_empty(fap, off, &bs->swap_type,
-                                      sizeof bs->swap_type);
+        off = boot_swap_info_off(fap);
+        rc = flash_area_read_is_empty(fap, off, &swap_info, sizeof swap_info);
         if (rc == 1) {
-            bs->swap_type = BOOT_SWAP_TYPE_NONE;
+            BOOT_SET_SWAP_INFO(swap_info, 0, BOOT_SWAP_TYPE_NONE);
             rc = 0;
         }
+
+        /* Extract the swap type info */
+        bs->swap_type = BOOT_GET_SWAP_TYPE(swap_info);
     }
 
     flash_area_close(fap);
@@ -974,7 +981,9 @@
     assert(rc == 0);
 
     if (bs->swap_type != BOOT_SWAP_TYPE_NONE) {
-        rc = boot_write_swap_type(fap, bs->swap_type);
+        rc = boot_write_swap_info(fap,
+                                  bs->swap_type,
+                                  0);
         assert(rc == 0);
     }
 
@@ -1194,8 +1203,9 @@
             }
 
             if (swap_state.swap_type != BOOT_SWAP_TYPE_NONE) {
-                rc = boot_write_swap_type(fap_primary_slot,
-                                          swap_state.swap_type);
+                rc = boot_write_swap_info(fap_primary_slot,
+                                          swap_state.swap_type,
+                                          0);
                 assert(rc == 0);
             }