bootutil: keep image areas open while bootloading

Keep both image areas and the scratch area open while we are
bootloading. This fixes up a hack and will make it easier to use
flash_area_get_sectors() later.

Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
diff --git a/boot/bootutil/src/bootutil_priv.h b/boot/bootutil/src/bootutil_priv.h
index ba5471d..a5eb2df 100644
--- a/boot/bootutil/src/bootutil_priv.h
+++ b/boot/bootutil/src/bootutil_priv.h
@@ -106,11 +106,12 @@
 struct boot_loader_state {
     struct {
         struct image_header hdr;
+        const struct flash_area *area;
         struct flash_area *sectors;
         int num_sectors;
     } imgs[BOOT_NUM_SLOTS];
 
-    struct flash_area scratch_sector;
+    const struct flash_area *scratch_area;
 
     uint8_t write_sz;
 };
@@ -135,6 +136,10 @@
  * Accessors for the contents of struct boot_loader_state.
  */
 
+/* These are macros so they can be used as lvalues. */
+#define BOOT_IMG_AREA(state, slot) ((state)->imgs[(slot)].area)
+#define BOOT_SCRATCH_AREA(state) ((state)->scratch_area)
+
 static inline struct image_header*
 boot_img_hdr(struct boot_loader_state *state, size_t slot)
 {
@@ -144,13 +149,13 @@
 static inline uint8_t
 boot_img_fa_device_id(struct boot_loader_state *state, size_t slot)
 {
-    return state->imgs[slot].sectors[0].fa_device_id;
+    return state->imgs[slot].area->fa_device_id;
 }
 
 static inline uint8_t
 boot_scratch_fa_device_id(struct boot_loader_state *state)
 {
-    return state->scratch_sector.fa_device_id;
+    return state->scratch_area->fa_device_id;
 }
 
 static inline size_t
@@ -184,23 +189,17 @@
 static inline uint32_t
 boot_img_slot_off(struct boot_loader_state *state, size_t slot)
 {
-    /*
-     * When using flash_area_to_sectors(), "sectors" are actually
-     * flash areas. Flash areas have offsets relative to the beginning
-     * of their flash device.
-     */
-    return state->imgs[slot].sectors[0].fa_off;
+    return state->imgs[slot].area->fa_off;
 }
 
 static inline size_t boot_scratch_area_size(struct boot_loader_state *state)
 {
-    return state->scratch_sector.fa_size;
+    return state->scratch_area->fa_size;
 }
 
 static inline int
 boot_initialize_area(struct boot_loader_state *state, int flash_area)
 {
-    const struct flash_area *scratch;
     int num_sectors = BOOT_MAX_IMG_SECTORS;
     size_t slot;
     int rc;
@@ -212,17 +211,6 @@
     case FLASH_AREA_IMAGE_1:
         slot = 1;
         break;
-    case FLASH_AREA_IMAGE_SCRATCH:
-        /*
-         * Special case, handle hackishly by getting area pointer and
-         * leaving the area open.
-         */
-        rc = flash_area_open(flash_area, &scratch);
-        if (rc != 0) {
-            return rc;
-        }
-        state->scratch_sector = *scratch;
-        return 0;
     default:
         return BOOT_EFLASH;
     }
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index 18db4af..5990b80 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -335,11 +335,6 @@
         return BOOT_EFLASH;
     }
 
-    rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_SCRATCH);
-    if (rc != 0) {
-        return BOOT_EFLASH;
-    }
-
     boot_data.write_sz = boot_write_sz();
 
     return 0;
@@ -1203,6 +1198,7 @@
     int swap_type;
     int slot;
     int rc;
+    int fa_id;
 
     /* The array of slot sectors are defined here (as opposed to file scope) so
      * that they don't get allocated for non-boot-loader apps.  This is
@@ -1214,16 +1210,26 @@
     boot_data.imgs[0].sectors = slot0_sectors;
     boot_data.imgs[1].sectors = slot1_sectors;
 
+    /* Open boot_data image areas for the duration of this call. */
+    for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
+        fa_id = flash_area_id_from_image_slot(slot);
+        rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
+        assert(rc == 0);
+    }
+    rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
+                         &BOOT_SCRATCH_AREA(&boot_data));
+    assert(rc == 0);
+
     /* Determine the sector layout of the image slots and scratch area. */
     rc = boot_read_sectors();
     if (rc != 0) {
-        return rc;
+        goto out;
     }
 
     /* Attempt to read an image header from each slot. */
     rc = boot_read_image_headers();
     if (rc != 0) {
-        return rc;
+        goto out;
     }
 
     /* If the image slots aren't compatible, no swap is possible.  Just boot
@@ -1233,7 +1239,7 @@
         rc = boot_swap_if_needed(&swap_type);
         assert(rc == 0);
         if (rc != 0) {
-            return rc;
+            goto out;
         }
     } else {
         swap_type = BOOT_SWAP_TYPE_NONE;
@@ -1245,7 +1251,8 @@
         rc = boot_validate_slot(0);
         assert(rc == 0);
         if (rc != 0) {
-            return BOOT_EBADIMAGE;
+            rc = BOOT_EBADIMAGE;
+            goto out;
         }
 #endif
         slot = 0;
@@ -1282,30 +1289,38 @@
     rsp->br_image_addr = boot_img_slot_off(&boot_data, 0);
     rsp->br_hdr = boot_img_hdr(&boot_data, slot);
 
-    return 0;
+ out:
+    flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
+    for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
+        flash_area_close(BOOT_IMG_AREA(&boot_data, BOOT_NUM_SLOTS - 1 - slot));
+    }
+    return rc;
 }
 
 int
 split_go(int loader_slot, int split_slot, void **entry)
 {
-    const struct flash_area *loader_fap;
-    const struct flash_area *app_fap;
     struct flash_area *sectors;
     uintptr_t entry_val;
     int loader_flash_id;
-    int app_flash_id;
+    int split_flash_id;
     int rc;
 
-    app_fap = NULL;
-    loader_fap = NULL;
-
     sectors = malloc(BOOT_MAX_IMG_SECTORS * 2 * sizeof *sectors);
     if (sectors == NULL) {
-        rc = SPLIT_GO_ERR;
-        goto done;
+        return SPLIT_GO_ERR;
     }
-    boot_data.imgs[0].sectors = sectors + 0;
-    boot_data.imgs[1].sectors = sectors + BOOT_MAX_IMG_SECTORS;
+    boot_data.imgs[loader_slot].sectors = sectors + 0;
+    boot_data.imgs[split_slot].sectors = sectors + BOOT_MAX_IMG_SECTORS;
+
+    loader_flash_id = flash_area_id_from_image_slot(loader_slot);
+    rc = flash_area_open(loader_flash_id,
+                         &BOOT_IMG_AREA(&boot_data, split_slot));
+    assert(rc == 0);
+    split_flash_id = flash_area_id_from_image_slot(split_slot);
+    rc = flash_area_open(split_flash_id,
+                         &BOOT_IMG_AREA(&boot_data, split_slot));
+    assert(rc == 0);
 
     /* Determine the sector layout of the image slots and scratch area. */
     rc = boot_read_sectors();
@@ -1319,28 +1334,14 @@
         goto done;
     }
 
-    app_flash_id = flash_area_id_from_image_slot(split_slot);
-    rc = flash_area_open(app_flash_id, &app_fap);
-    if (rc != 0) {
-        rc = BOOT_EFLASH;
-        goto done;
-    }
-
-    loader_flash_id = flash_area_id_from_image_slot(loader_slot);
-    rc = flash_area_open(loader_flash_id, &loader_fap);
-    if (rc != 0) {
-        rc = BOOT_EFLASH;
-        goto done;
-    }
-
     /* Don't check the bootable image flag because we could really call a
      * bootable or non-bootable image.  Just validate that the image check
      * passes which is distinct from the normal check.
      */
     rc = split_image_check(boot_img_hdr(&boot_data, split_slot),
-                           app_fap,
+                           BOOT_IMG_AREA(&boot_data, split_slot),
                            boot_img_hdr(&boot_data, loader_slot),
-                           loader_fap);
+                           BOOT_IMG_AREA(&boot_data, loader_slot));
     if (rc != 0) {
         rc = SPLIT_GO_NON_MATCHING;
         goto done;
@@ -1352,8 +1353,8 @@
     rc = SPLIT_GO_OK;
 
 done:
+    flash_area_close(BOOT_IMG_AREA(&boot_data, split_slot));
+    flash_area_close(BOOT_IMG_AREA(&boot_data, loader_slot));
     free(sectors);
-    flash_area_close(app_fap);
-    flash_area_close(loader_fap);
     return rc;
 }