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);
             }
 
diff --git a/docs/design.md b/docs/design.md
index f469d45..d86d89d 100644
--- a/docs/design.md
+++ b/docs/design.md
@@ -266,7 +266,7 @@
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                      Swap size (4 octets)                     |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-    |   Swap type   |           0xff padding (7 octets)             |
+    |   Swap info   |           0xff padding (7 octets)             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |   Copy done   |           0xff padding (7 octets)             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -319,10 +319,17 @@
    this location for easier recovery in case of a reset while performing the
    swap.
 
-4. Swap type: A single byte indicating the type of swap operation in progress.
-   When mcuboot resumes an interrupted swap, it uses this field to determine
-   the type of operation to perform.  This field contains one of the following
-   values:
+4. Swap info: A single byte which encodes the following informations:
+    - Swap type: Stored in bits 0-3. Indicating the type of swap operation in
+    progress. When mcuboot resumes an interrupted swap, it uses this field to
+    determine the type of operation to perform. This field contains one of the
+    following values in the table below.
+    - Image number: Stored in bits 4-7. It has always 0 value at single image
+    boot. In case of multi image boot it indicates, which image was swapped when
+    interrupt happened. The same scratch area is used during in case of all
+    image swap operation. Therefore this field is used to determine which image
+    the trailer belongs to if boot status is found on scratch area when the swap
+    operation is resumed.
 
 | Name                      | Value |
 | ------------------------- | ----- |
@@ -439,8 +446,9 @@
 
 If mcuboot determines that it is resuming an interrupted swap (i.e., a reset
 occurred mid-swap), it fully determines the operation to resume by reading the
-`swap type` field from the active trailer.  The set of tables in the previous
-section are not necessary in the resume case.
+`swap info` field from the active trailer and extracting the swap type from bits
+0-3. The set of tables in the previous section are not necessary in the resume
+case.
 
 ## High-Level Operation
 
@@ -687,13 +695,13 @@
 
 If the swap status region indicates that the images are not contiguous, mcuboot
 determines the type of swap operation that was interrupted by reading the `swap
-type` field in the active image trailer, and then resumes the operation.  In
-other words, it applies the procedure defined in the previous section, moving
-image 1 into the primary slot and image 0 into the secondary slot. If the boot
-status indicates that an image part is present in the scratch area, this part
-is copied into the correct location by starting at step e or step h in the
-area-swap procedure, depending on whether the part belongs to image 0 or image
-1.
+info` field in the active image trailer and extarcting the swap type from bits
+0-3 then resumes the operation. In other words, it applies the procedure defined
+in the previous section, moving image 1 into the primary slot and image 0 into
+the secondary slot. If the boot status indicates that an image part is present
+in the scratch area, this part is copied into the correct location by starting
+at step e or step h in the area-swap procedure, depending on whether the part
+belongs to image 0 or image 1.
 
 After the swap operation has been completed, the boot loader proceeds as though
 it had just been started.