Update bootutil to reduce amount of global state

The boot loader state currently exists as global variable (boot_data)
which is accessed by all routines; this updates all routines that
require access to the state to receive it by parameter.

Variables that are declared as "static" (globals) were #ifdef'ed to
only use static when building a native bootloader, to avoid stack
allocation. When bootutil is built to run in the simulator they are
stack allocated to avoid thread share.

Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/boot/bootutil/src/loader.c b/boot/bootutil/src/loader.c
index a01492f..80bebd7 100644
--- a/boot/bootutil/src/loader.c
+++ b/boot/bootutil/src/loader.c
@@ -54,7 +54,23 @@
 #define IMAGES_ITER(x)
 #endif
 
+/*
+ * This macro allows some control on the allocation of local variables.
+ * When running natively on a target, we don't want to allocated huge
+ * variables on the stack, so make them global instead. For the simulator
+ * we want to run as many threads as there are tests, and it's safer
+ * to just make those variables stack allocated.
+ */
+#if !defined(__BOOTSIM__)
+#define TARGET_STATIC static
+#else
+#define TARGET_STATIC
+#endif
+
 #if defined(MCUBOOT_VALIDATE_PRIMARY_SLOT) && !defined(MCUBOOT_OVERWRITE_ONLY)
+/*
+ * FIXME: this might have to be updated for threaded sim
+ */
 static int boot_status_fails = 0;
 #define BOOT_STATUS_ASSERT(x)                \
     do {                                     \
@@ -165,7 +181,7 @@
  *              be read from.
  */
 static int
-boot_status_source(void)
+boot_status_source(struct boot_loader_state *state)
 {
     const struct boot_status_table *table;
     struct boot_swap_state state_scratch;
@@ -179,7 +195,7 @@
     (void)state;
 #endif
 
-    image_index = BOOT_CURR_IMG(&boot_data);
+    image_index = BOOT_CURR_IMG(state);
     rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_PRIMARY(image_index),
             &state_primary_slot);
     assert(rc == 0);
@@ -208,7 +224,7 @@
              * currently examined image.
              */
             if (source == BOOT_STATUS_SOURCE_SCRATCH &&
-                state_scratch.image_num != BOOT_CURR_IMG(&boot_data)) {
+                state_scratch.image_num != BOOT_CURR_IMG(state)) {
                 source = BOOT_STATUS_SOURCE_NONE;
             }
 #endif
@@ -232,15 +248,19 @@
  */
 #if !defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_OVERWRITE_ONLY_FAST)
 static int
-boot_read_image_size(int slot, struct image_header *hdr, uint32_t *size)
+boot_read_image_size(struct boot_loader_state *state, int slot,
+                     struct image_header *hdr, uint32_t *size)
 {
     const struct flash_area *fap;
     struct image_tlv_info info;
     int area_id;
     int rc;
 
-    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
-                                                  slot);
+#if (BOOT_IMAGE_NUMBER == 1)
+    (void)state;
+#endif
+
+    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
     rc = flash_area_open(area_id, &fap);
     if (rc != 0) {
         rc = BOOT_EFLASH;
@@ -267,14 +287,18 @@
 #endif /* !MCUBOOT_OVERWRITE_ONLY */
 
 static int
-boot_read_image_header(int slot, struct image_header *out_hdr)
+boot_read_image_header(struct boot_loader_state *state, int slot,
+                       struct image_header *out_hdr)
 {
     const struct flash_area *fap;
     int area_id;
     int rc;
 
-    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
-                                                  slot);
+#if (BOOT_IMAGE_NUMBER == 1)
+    (void)state;
+#endif
+
+    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
     rc = flash_area_open(area_id, &fap);
     if (rc != 0) {
         rc = BOOT_EFLASH;
@@ -295,13 +319,13 @@
 }
 
 static int
-boot_read_image_headers(bool require_all)
+boot_read_image_headers(struct boot_loader_state *state, bool require_all)
 {
     int rc;
     int i;
 
     for (i = 0; i < BOOT_NUM_SLOTS; i++) {
-        rc = boot_read_image_header(i, boot_img_hdr(&boot_data, i));
+        rc = boot_read_image_header(state, i, boot_img_hdr(state, i));
         if (rc != 0) {
             /* If `require_all` is set, fail on any single fail, otherwise
              * if at least the first slot's header was read successfully,
@@ -321,7 +345,7 @@
 }
 
 static uint8_t
-boot_write_sz(void)
+boot_write_sz(struct boot_loader_state *state)
 {
     uint8_t elem_sz;
     uint8_t align;
@@ -330,8 +354,8 @@
      * on what the minimum write size is for scratch area, active image slot.
      * We need to use the bigger of those 2 values.
      */
-    elem_sz = flash_area_align(BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT));
-    align = flash_area_align(BOOT_SCRATCH_AREA(&boot_data));
+    elem_sz = flash_area_align(BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT));
+    align = flash_area_align(BOOT_SCRATCH_AREA(state));
     if (align > elem_sz) {
         elem_sz = align;
     }
@@ -346,7 +370,7 @@
  * presumably!).
  */
 static int
-boot_slots_compatible(void)
+boot_slots_compatible(struct boot_loader_state *state)
 {
     size_t num_sectors_primary;
     size_t num_sectors_secondary;
@@ -356,17 +380,15 @@
     size_t i, j;
     int8_t smaller;
 
-    num_sectors_primary =
-            boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT);
-    num_sectors_secondary =
-            boot_img_num_sectors(&boot_data, BOOT_SECONDARY_SLOT);
+    num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
+    num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
     if ((num_sectors_primary > BOOT_MAX_IMG_SECTORS) ||
         (num_sectors_secondary > BOOT_MAX_IMG_SECTORS)) {
         BOOT_LOG_WRN("Cannot upgrade: more sectors than allowed");
         return 0;
     }
 
-    scratch_sz = boot_scratch_area_size(&boot_data);
+    scratch_sz = boot_scratch_area_size(state);
 
     /*
      * The following loop scans all sectors in a linear fashion, assuring that
@@ -380,12 +402,12 @@
     smaller = 0;
     while (i < num_sectors_primary || j < num_sectors_secondary) {
         if (sz0 == sz1) {
-            sz0 += boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
-            sz1 += boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT, j);
+            sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
+            sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
             i++;
             j++;
         } else if (sz0 < sz1) {
-            sz0 += boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
+            sz0 += boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
             /* Guarantee that multiple sectors of the secondary slot
              * fit into the primary slot.
              */
@@ -396,7 +418,7 @@
             smaller = 1;
             i++;
         } else {
-            sz1 += boot_img_sector_size(&boot_data, BOOT_SECONDARY_SLOT, j);
+            sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
             /* Guarantee that multiple sectors of the primary slot
              * fit into the secondary slot.
              */
@@ -431,37 +453,96 @@
     return 1;
 }
 
+#ifndef MCUBOOT_USE_FLASH_AREA_GET_SECTORS
+static int
+boot_initialize_area(struct boot_loader_state *state, int flash_area)
+{
+    int num_sectors = BOOT_MAX_IMG_SECTORS;
+    int rc;
+
+    if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
+        rc = flash_area_to_sectors(flash_area, &num_sectors,
+                                   BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors);
+        BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors = (size_t)num_sectors;
+
+    } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
+        rc = flash_area_to_sectors(flash_area, &num_sectors,
+                                 BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors);
+        BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors = (size_t)num_sectors;
+
+    } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
+        rc = flash_area_to_sectors(flash_area, &num_sectors,
+                                   state->scratch.sectors);
+        state->scratch.num_sectors = (size_t)num_sectors;
+    } else {
+        return BOOT_EFLASH;
+    }
+
+    return rc;
+}
+#else  /* defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
+static int
+boot_initialize_area(struct boot_loader_state *state, int flash_area)
+{
+    uint32_t num_sectors;
+    struct flash_sector *out_sectors;
+    size_t *out_num_sectors;
+    int rc;
+
+    num_sectors = BOOT_MAX_IMG_SECTORS;
+
+    if (flash_area == FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state))) {
+        out_sectors = BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors;
+        out_num_sectors = &BOOT_IMG(state, BOOT_PRIMARY_SLOT).num_sectors;
+    } else if (flash_area == FLASH_AREA_IMAGE_SECONDARY(BOOT_CURR_IMG(state))) {
+        out_sectors = BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors;
+        out_num_sectors = &BOOT_IMG(state, BOOT_SECONDARY_SLOT).num_sectors;
+    } else if (flash_area == FLASH_AREA_IMAGE_SCRATCH) {
+        out_sectors = state->scratch.sectors;
+        out_num_sectors = &state->scratch.num_sectors;
+    } else {
+        return BOOT_EFLASH;
+    }
+
+    rc = flash_area_get_sectors(flash_area, &num_sectors, out_sectors);
+    if (rc != 0) {
+        return rc;
+    }
+    *out_num_sectors = num_sectors;
+    return 0;
+}
+#endif  /* !defined(MCUBOOT_USE_FLASH_AREA_GET_SECTORS) */
+
 /**
  * Determines the sector layout of both image slots and the scratch area.
  * This information is necessary for calculating the number of bytes to erase
  * and copy during an image swap.  The information collected during this
- * function is used to populate the boot_data global.
+ * function is used to populate the state.
  */
 static int
-boot_read_sectors(void)
+boot_read_sectors(struct boot_loader_state *state)
 {
     uint8_t image_index;
     int rc;
 
-    image_index = BOOT_CURR_IMG(&boot_data);
+    image_index = BOOT_CURR_IMG(state);
 
     rc = boot_initialize_area(state, FLASH_AREA_IMAGE_PRIMARY(image_index));
     if (rc != 0) {
         return BOOT_EFLASH;
     }
 
-    rc = boot_initialize_area(&boot_data,
-            FLASH_AREA_IMAGE_SECONDARY(image_index));
+    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SECONDARY(image_index));
     if (rc != 0) {
         return BOOT_EFLASH;
     }
 
-    rc = boot_initialize_area(&boot_data, FLASH_AREA_IMAGE_SCRATCH);
+    rc = boot_initialize_area(state, FLASH_AREA_IMAGE_SCRATCH);
     if (rc != 0) {
         return BOOT_EFLASH;
     }
 
-    BOOT_WRITE_SZ(&boot_data) = boot_write_sz();
+    BOOT_WRITE_SZ(state) = boot_write_sz(state);
 
     return 0;
 }
@@ -483,7 +564,8 @@
  * operation.
  */
 static int
-boot_read_status_bytes(const struct flash_area *fap, struct boot_status *bs)
+boot_read_status_bytes(const struct flash_area *fap,
+        struct boot_loader_state *state, struct boot_status *bs)
 {
     uint32_t off;
     uint8_t status;
@@ -495,13 +577,13 @@
     int i;
 
     off = boot_status_off(fap);
-    max_entries = boot_status_entries(BOOT_CURR_IMG(&boot_data), fap);
+    max_entries = boot_status_entries(BOOT_CURR_IMG(state), fap);
 
     found = 0;
     found_idx = 0;
     invalid = 0;
     for (i = 0; i < max_entries; i++) {
-        rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(&boot_data),
+        rc = flash_area_read_is_empty(fap, off + i * BOOT_WRITE_SZ(state),
                 &status, 1);
         if (rc < 0) {
             return BOOT_EFLASH;
@@ -552,7 +634,7 @@
  * there is no operation in progress.
  */
 static int
-boot_read_status(struct boot_status *bs)
+boot_read_status(struct boot_loader_state *state, struct boot_status *bs)
 {
     const struct flash_area *fap;
     uint32_t off;
@@ -571,7 +653,7 @@
     return 0;
 #endif
 
-    status_loc = boot_status_source();
+    status_loc = boot_status_source(state);
     switch (status_loc) {
     case BOOT_STATUS_SOURCE_NONE:
         return 0;
@@ -581,7 +663,7 @@
         break;
 
     case BOOT_STATUS_SOURCE_PRIMARY_SLOT:
-        area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(&boot_data));
+        area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
         break;
 
     default:
@@ -594,7 +676,7 @@
         return BOOT_EFLASH;
     }
 
-    rc = boot_read_status_bytes(fap, bs);
+    rc = boot_read_status_bytes(fap, state, bs);
     if (rc == 0) {
         off = boot_swap_info_off(fap);
         rc = flash_area_read_is_empty(fap, off, &swap_info, sizeof swap_info);
@@ -621,7 +703,7 @@
  * @return                      0 on success; nonzero on failure.
  */
 int
-boot_write_status(struct boot_status *bs)
+boot_write_status(struct boot_loader_state *state, struct boot_status *bs)
 {
     const struct flash_area *fap;
     uint32_t off;
@@ -642,7 +724,7 @@
         area_id = FLASH_AREA_IMAGE_SCRATCH;
     } else {
         /* Write to the primary slot. */
-        area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(&boot_data));
+        area_id = FLASH_AREA_IMAGE_PRIMARY(BOOT_CURR_IMG(state));
     }
 
     rc = flash_area_open(area_id, &fap);
@@ -653,7 +735,7 @@
 
     off = boot_status_off(fap) +
           boot_status_internal_off(bs->idx, bs->state,
-                                   BOOT_WRITE_SZ(&boot_data));
+                                   BOOT_WRITE_SZ(state));
     align = flash_area_align(fap);
     erased_val = flash_area_erased_val(fap);
     memset(buf, erased_val, BOOT_MAX_ALIGN);
@@ -676,35 +758,43 @@
  * Validate image hash/signature in a slot.
  */
 static int
-boot_image_check(struct image_header *hdr, const struct flash_area *fap,
-        struct boot_status *bs)
+boot_image_check(struct boot_loader_state *state, struct image_header *hdr,
+                 const struct flash_area *fap, struct boot_status *bs)
 {
-    static uint8_t tmpbuf[BOOT_TMPBUF_SZ];
+    TARGET_STATIC uint8_t tmpbuf[BOOT_TMPBUF_SZ];
     uint8_t image_index;
     int rc;
 
-    image_index = BOOT_CURR_IMG(&boot_data);
+#if (BOOT_IMAGE_NUMBER == 1)
+    (void)state;
+#endif
+
+    image_index = BOOT_CURR_IMG(state);
 
 #ifndef MCUBOOT_ENC_IMAGES
     (void)bs;
     (void)rc;
+    if (bootutil_img_validate(NULL, image_index, hdr, fap, tmpbuf,
+                              BOOT_TMPBUF_SZ, NULL, 0, NULL)) {
+        return BOOT_EBADIMAGE;
+    }
 #else
     if ((fap->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index))
             && IS_ENCRYPTED(hdr)) {
-        rc = boot_enc_load(image_index, hdr, fap, bs->enckey[1]);
+        rc = boot_enc_load(state->enc, image_index, hdr, fap, bs->enckey[1]);
         if (rc < 0) {
             return BOOT_EBADIMAGE;
         }
-        if (rc == 0 && boot_enc_set_key(1, bs->enckey[1])) {
+        if (rc == 0 && boot_enc_set_key(state->enc, 1, bs->enckey[1])) {
             return BOOT_EBADIMAGE;
         }
     }
-#endif
-
-    if (bootutil_img_validate(image_index, hdr, fap, tmpbuf, BOOT_TMPBUF_SZ,
-                NULL, 0, NULL)) {
+    if (bootutil_img_validate(state->enc, image_index, hdr, fap, tmpbuf,
+                              BOOT_TMPBUF_SZ, NULL, 0, NULL)) {
         return BOOT_EBADIMAGE;
     }
+#endif
+
     return 0;
 }
 
@@ -724,13 +814,13 @@
         }
     }
 
-    if (bootutil_img_validate(0, loader_hdr, loader_fap, tmpbuf, BOOT_TMPBUF_SZ,
-                              NULL, 0, loader_hash)) {
+    if (bootutil_img_validate(NULL, 0, loader_hdr, loader_fap, tmpbuf,
+                              BOOT_TMPBUF_SZ, NULL, 0, loader_hash)) {
         return BOOT_EBADIMAGE;
     }
 
-    if (bootutil_img_validate(0, app_hdr, app_fap, tmpbuf, BOOT_TMPBUF_SZ,
-                              loader_hash, 32, NULL)) {
+    if (bootutil_img_validate(NULL, 0, app_hdr, app_fap, tmpbuf,
+                              BOOT_TMPBUF_SZ, loader_hash, 32, NULL)) {
         return BOOT_EBADIMAGE;
     }
 
@@ -754,7 +844,7 @@
 }
 
 static int
-boot_check_header_erased(int slot)
+boot_check_header_erased(struct boot_loader_state *state, int slot)
 {
     const struct flash_area *fap;
     struct image_header *hdr;
@@ -762,8 +852,7 @@
     int area_id;
     int rc;
 
-    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
-                                                  slot);
+    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
     rc = flash_area_open(area_id, &fap);
     if (rc != 0) {
         return -1;
@@ -772,7 +861,7 @@
     erased_val = flash_area_erased_val(fap);
     flash_area_close(fap);
 
-    hdr = boot_img_hdr(&boot_data, slot);
+    hdr = boot_img_hdr(state, slot);
     if (!boot_data_is_set_to(erased_val, &hdr->ih_magic, sizeof(hdr->ih_magic))) {
         return -1;
     }
@@ -781,28 +870,29 @@
 }
 
 static int
-boot_validate_slot(int slot, struct boot_status *bs)
+boot_validate_slot(struct boot_loader_state *state, int slot,
+                   struct boot_status *bs)
 {
     const struct flash_area *fap;
     struct image_header *hdr;
     int area_id;
     int rc;
 
-    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
-                                                  slot);
+    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
     rc = flash_area_open(area_id, &fap);
     if (rc != 0) {
         return BOOT_EFLASH;
     }
 
-    hdr = boot_img_hdr(&boot_data, slot);
-    if (boot_check_header_erased(slot) == 0 || (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
+    hdr = boot_img_hdr(state, slot);
+    if (boot_check_header_erased(state, slot) == 0 ||
+        (hdr->ih_flags & IMAGE_F_NON_BOOTABLE)) {
         /* No bootable image in slot; continue booting from the primary slot. */
         rc = -1;
         goto out;
     }
 
-    if ((hdr->ih_magic != IMAGE_MAGIC || boot_image_check(hdr, fap, bs) != 0)) {
+    if (hdr->ih_magic != IMAGE_MAGIC || boot_image_check(state, hdr, fap, bs)) {
         if (slot != BOOT_PRIMARY_SLOT) {
             flash_area_erase(fap, 0, fap->fa_size);
             /* Image in the secondary slot is invalid. Erase the image and
@@ -832,7 +922,8 @@
  * @return                      The type of swap to perform (BOOT_SWAP_TYPE...)
  */
 static int
-boot_validated_swap_type(struct boot_status *bs)
+boot_validated_swap_type(struct boot_loader_state *state,
+                         struct boot_status *bs)
 {
     int swap_type;
 
@@ -848,7 +939,7 @@
         /* Boot loader wants to switch to the secondary slot.
          * Ensure image is valid.
          */
-        if (boot_validate_slot(BOOT_SECONDARY_SLOT, bs) != 0) {
+        if (boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs) != 0) {
             swap_type = BOOT_SWAP_TYPE_FAIL;
         }
     }
@@ -871,7 +962,8 @@
  */
 #ifndef MCUBOOT_OVERWRITE_ONLY
 static uint32_t
-boot_copy_sz(int last_sector_idx, int *out_first_sector_idx)
+boot_copy_sz(struct boot_loader_state *state, int last_sector_idx,
+             int *out_first_sector_idx)
 {
     size_t scratch_sz;
     uint32_t new_sz;
@@ -880,9 +972,9 @@
 
     sz = 0;
 
-    scratch_sz = boot_scratch_area_size(&boot_data);
+    scratch_sz = boot_scratch_area_size(state);
     for (i = last_sector_idx; i >= 0; i--) {
-        new_sz = sz + boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, i);
+        new_sz = sz + boot_img_sector_size(state, BOOT_PRIMARY_SLOT, i);
         /*
          * The secondary slot is not being checked here, because
          * `boot_slots_compatible` already provides assurance that the copy size
@@ -933,7 +1025,8 @@
  * @return                      0 on success; nonzero on failure.
  */
 static int
-boot_copy_sector(const struct flash_area *fap_src,
+boot_copy_sector(struct boot_loader_state *state,
+                 const struct flash_area *fap_src,
                  const struct flash_area *fap_dst,
                  uint32_t off_src, uint32_t off_dst, uint32_t sz)
 {
@@ -949,7 +1042,11 @@
     uint8_t image_index;
 #endif
 
-    static uint8_t buf[1024];
+    TARGET_STATIC uint8_t buf[1024];
+
+#if !defined(MCUBOOT_ENC_IMAGES)
+    (void)state;
+#endif
 
     bytes_copied = 0;
     while (bytes_copied < sz) {
@@ -965,15 +1062,15 @@
         }
 
 #ifdef MCUBOOT_ENC_IMAGES
-        image_index = BOOT_CURR_IMG(&boot_data);
+        image_index = BOOT_CURR_IMG(state);
         if (fap_src->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index) ||
             fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
             /* assume the secondary slot as src, needs decryption */
-            hdr = boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT);
+            hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
             off = off_src;
             if (fap_dst->fa_id == FLASH_AREA_IMAGE_SECONDARY(image_index)) {
                 /* might need encryption (metadata from the primary slot) */
-                hdr = boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT);
+                hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
                 off = off_dst;
             }
             if (IS_ENCRYPTED(hdr)) {
@@ -995,7 +1092,7 @@
                         blk_sz = (hdr->ih_hdr_size + hdr->ih_img_size) - (off + bytes_copied);
                     }
                 }
-                boot_encrypt(image_index, fap_src,
+                boot_encrypt(state->enc, image_index, fap_src,
                         (off + bytes_copied + idx) - hdr->ih_hdr_size, blk_sz,
                         blk_off, &buf[idx]);
             }
@@ -1017,13 +1114,19 @@
 
 #ifndef MCUBOOT_OVERWRITE_ONLY
 static inline int
-boot_status_init(const struct flash_area *fap, const struct boot_status *bs)
+boot_status_init(const struct boot_loader_state *state,
+                 const struct flash_area *fap,
+                 const struct boot_status *bs)
 {
     struct boot_swap_state swap_state;
     uint8_t image_index;
     int rc;
 
-    image_index = BOOT_CURR_IMG(&boot_data);
+#if (BOOT_IMAGE_NUMBER == 1)
+    (void)state;
+#endif
+
+    image_index = BOOT_CURR_IMG(state);
 
     BOOT_LOG_DBG("initializing status; fa_id=%d", fap->fa_id);
 
@@ -1062,7 +1165,8 @@
 
 #ifndef MCUBOOT_OVERWRITE_ONLY
 static int
-boot_erase_trailer_sectors(const struct flash_area *fap)
+boot_erase_trailer_sectors(const struct boot_loader_state *state,
+                           const struct flash_area *fap)
 {
     uint8_t slot;
     uint32_t sector;
@@ -1077,7 +1181,7 @@
 
     BOOT_LOG_DBG("erasing trailer; fa_id=%d", fap->fa_id);
 
-    image_index = BOOT_CURR_IMG(&boot_data);
+    image_index = BOOT_CURR_IMG(state);
     fa_id_primary = flash_area_id_from_multi_image_slot(image_index,
             BOOT_PRIMARY_SLOT);
     fa_id_secondary = flash_area_id_from_multi_image_slot(image_index,
@@ -1092,12 +1196,12 @@
     }
 
     /* delete starting from last sector and moving to beginning */
-    sector = boot_img_num_sectors(&boot_data, slot) - 1;
-    trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(&boot_data));
+    sector = boot_img_num_sectors(state, slot) - 1;
+    trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
     total_sz = 0;
     do {
-        sz = boot_img_sector_size(&boot_data, slot, sector);
-        off = boot_img_sector_off(&boot_data, slot, sector);
+        sz = boot_img_sector_size(state, slot, sector);
+        off = boot_img_sector_off(state, slot, sector);
         rc = boot_erase_sector(fap, off, sz);
         assert(rc == 0);
 
@@ -1122,7 +1226,8 @@
  */
 #ifndef MCUBOOT_OVERWRITE_ONLY
 static void
-boot_swap_sectors(int idx, uint32_t sz, struct boot_status *bs)
+boot_swap_sectors(int idx, uint32_t sz, struct boot_loader_state *state,
+        struct boot_status *bs)
 {
     const struct flash_area *fap_primary_slot;
     const struct flash_area *fap_secondary_slot;
@@ -1138,10 +1243,10 @@
     int rc;
 
     /* Calculate offset from start of image area. */
-    img_off = boot_img_sector_off(&boot_data, BOOT_PRIMARY_SLOT, idx);
+    img_off = boot_img_sector_off(state, BOOT_PRIMARY_SLOT, idx);
 
     copy_sz = sz;
-    trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(&boot_data));
+    trailer_sz = boot_trailer_sz(BOOT_WRITE_SZ(state));
 
     /* sz in this function is always sized on a multiple of the sector size.
      * The check against the start offset of the last sector
@@ -1152,15 +1257,15 @@
      * NOTE: `use_scratch` is a temporary flag (never written to flash) which
      * controls if special handling is needed (swapping last sector).
      */
-    last_sector = boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT) - 1;
+    last_sector = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT) - 1;
     if ((img_off + sz) >
-        boot_img_sector_off(&boot_data, BOOT_PRIMARY_SLOT, last_sector)) {
+        boot_img_sector_off(state, BOOT_PRIMARY_SLOT, last_sector)) {
         copy_sz -= trailer_sz;
     }
 
     bs->use_scratch = (bs->idx == BOOT_STATUS_IDX_0 && copy_sz != sz);
 
-    image_index = BOOT_CURR_IMG(&boot_data);
+    image_index = BOOT_CURR_IMG(state);
 
     rc = flash_area_open(FLASH_AREA_IMAGE_PRIMARY(image_index),
             &fap_primary_slot);
@@ -1183,7 +1288,7 @@
              * scratch area for status.  We need a temporary place to store the
              * `swap-type` while we erase the primary trailer.
              */ 
-            rc = boot_status_init(fap_scratch, bs);
+            rc = boot_status_init(state, fap_scratch, bs);
             assert(rc == 0);
 
             if (!bs->use_scratch) {
@@ -1191,10 +1296,10 @@
                  * last sector is not being used by the image data so it's safe
                  * to erase.
                  */
-                rc = boot_erase_trailer_sectors(fap_primary_slot);
+                rc = boot_erase_trailer_sectors(state, fap_primary_slot);
                 assert(rc == 0);
 
-                rc = boot_status_init(fap_primary_slot, bs);
+                rc = boot_status_init(state, fap_primary_slot, bs);
                 assert(rc == 0);
 
                 /* Erase the temporary trailer from the scratch area. */
@@ -1203,12 +1308,12 @@
             }
         }
 
-        rc = boot_copy_sector(fap_secondary_slot, fap_scratch,
+        rc = boot_copy_sector(state, fap_secondary_slot, fap_scratch,
                               img_off, 0, copy_sz);
         assert(rc == 0);
 
         bs->state = BOOT_STATUS_STATE_1;
-        rc = boot_write_status(bs);
+        rc = boot_write_status(state, bs);
         BOOT_STATUS_ASSERT(rc == 0);
     }
 
@@ -1216,7 +1321,7 @@
         rc = boot_erase_sector(fap_secondary_slot, img_off, sz);
         assert(rc == 0);
 
-        rc = boot_copy_sector(fap_primary_slot, fap_secondary_slot,
+        rc = boot_copy_sector(state, fap_primary_slot, fap_secondary_slot,
                               img_off, img_off, copy_sz);
         assert(rc == 0);
 
@@ -1224,12 +1329,12 @@
             /* If not all sectors of the slot are being swapped,
              * guarantee here that only the primary slot will have the state.
              */
-            rc = boot_erase_trailer_sectors(fap_secondary_slot);
+            rc = boot_erase_trailer_sectors(state, fap_secondary_slot);
             assert(rc == 0);
         }
 
         bs->state = BOOT_STATUS_STATE_2;
-        rc = boot_write_status(bs);
+        rc = boot_write_status(state, bs);
         BOOT_STATUS_ASSERT(rc == 0);
     }
 
@@ -1240,7 +1345,7 @@
         /* NOTE: If this is the final sector, we exclude the image trailer from
          * this copy (copy_sz was truncated earlier).
          */
-        rc = boot_copy_sector(fap_scratch, fap_primary_slot,
+        rc = boot_copy_sector(state, fap_scratch, fap_primary_slot,
                               0, img_off, copy_sz);
         assert(rc == 0);
 
@@ -1248,9 +1353,9 @@
             scratch_trailer_off = boot_status_off(fap_scratch);
 
             /* copy current status that is being maintained in scratch */
-            rc = boot_copy_sector(fap_scratch, fap_primary_slot,
+            rc = boot_copy_sector(state, fap_scratch, fap_primary_slot,
                         scratch_trailer_off, img_off + copy_sz,
-                        BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(&boot_data));
+                        BOOT_STATUS_STATE_COUNT * BOOT_WRITE_SZ(state));
             BOOT_STATUS_ASSERT(rc == 0);
 
             rc = boot_read_swap_state_by_id(FLASH_AREA_IMAGE_SCRATCH,
@@ -1292,7 +1397,7 @@
 
         bs->idx++;
         bs->state = BOOT_STATUS_STATE_0;
-        rc = boot_write_status(bs);
+        rc = boot_write_status(state, bs);
         BOOT_STATUS_ASSERT(rc == 0);
 
         if (erase_scratch) {
@@ -1322,7 +1427,7 @@
  */
 #if defined(MCUBOOT_OVERWRITE_ONLY) || defined(MCUBOOT_BOOTSTRAP)
 static int
-boot_copy_image(struct boot_status *bs)
+boot_copy_image(struct boot_loader_state *state, struct boot_status *bs)
 {
     size_t sect_count;
     size_t sect;
@@ -1338,8 +1443,8 @@
 
 #if defined(MCUBOOT_OVERWRITE_ONLY_FAST)
     uint32_t src_size = 0;
-    rc = boot_read_image_size(BOOT_SECONDARY_SLOT,
-                              boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT),
+    rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT,
+                              boot_img_hdr(state, BOOT_SECONDARY_SLOT),
                               &src_size);
     assert(rc == 0);
 #endif
@@ -1357,9 +1462,9 @@
             &fap_secondary_slot);
     assert (rc == 0);
 
-    sect_count = boot_img_num_sectors(&boot_data, BOOT_PRIMARY_SLOT);
+    sect_count = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
     for (sect = 0, size = 0; sect < sect_count; sect++) {
-        this_size = boot_img_sector_size(&boot_data, BOOT_PRIMARY_SLOT, sect);
+        this_size = boot_img_sector_size(state, BOOT_PRIMARY_SLOT, sect);
         rc = boot_erase_sector(fap_primary_slot, size, this_size);
         assert(rc == 0);
 
@@ -1373,15 +1478,15 @@
     }
 
 #ifdef MCUBOOT_ENC_IMAGES
-    if (IS_ENCRYPTED(boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT))) {
-        rc = boot_enc_load(image_index,
-                boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT),
+    if (IS_ENCRYPTED(boot_img_hdr(state, BOOT_SECONDARY_SLOT))) {
+        rc = boot_enc_load(state->enc, image_index,
+                boot_img_hdr(state, BOOT_SECONDARY_SLOT),
                 fap_secondary_slot, bs->enckey[1]);
 
         if (rc < 0) {
             return BOOT_EBADIMAGE;
         }
-        if (rc == 0 && boot_enc_set_key(1, bs->enckey[1])) {
+        if (rc == 0 && boot_enc_set_key(state->enc, 1, bs->enckey[1])) {
             return BOOT_EBADIMAGE;
         }
     }
@@ -1389,7 +1494,7 @@
 
     BOOT_LOG_INF("Copying the secondary slot to the primary slot: 0x%zx bytes",
                  size);
-    rc = boot_copy_sector(fap_secondary_slot, fap_primary_slot, 0, 0, size);
+    rc = boot_copy_sector(state, fap_secondary_slot, fap_primary_slot, 0, 0, size);
 
     /*
      * Erases header and trailer. The trailer is erased because when a new
@@ -1398,18 +1503,16 @@
      */
     BOOT_LOG_DBG("erasing secondary header");
     rc = boot_erase_sector(fap_secondary_slot,
-                           boot_img_sector_off(&boot_data,
-                                   BOOT_SECONDARY_SLOT, 0),
-                           boot_img_sector_size(&boot_data,
-                                   BOOT_SECONDARY_SLOT, 0));
+                           boot_img_sector_off(state, BOOT_SECONDARY_SLOT, 0),
+                           boot_img_sector_size(state, BOOT_SECONDARY_SLOT, 0));
     assert(rc == 0);
-    last_sector = boot_img_num_sectors(&boot_data, BOOT_SECONDARY_SLOT) - 1;
+    last_sector = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT) - 1;
     BOOT_LOG_DBG("erasing secondary trailer");
     rc = boot_erase_sector(fap_secondary_slot,
-                           boot_img_sector_off(&boot_data,
-                                   BOOT_SECONDARY_SLOT, last_sector),
-                           boot_img_sector_size(&boot_data,
-                                   BOOT_SECONDARY_SLOT, last_sector));
+                           boot_img_sector_off(state, BOOT_SECONDARY_SLOT,
+                               last_sector),
+                           boot_img_sector_size(state, BOOT_SECONDARY_SLOT,
+                               last_sector));
     assert(rc == 0);
 
     flash_area_close(fap_primary_slot);
@@ -1435,7 +1538,7 @@
  * @return                      0 on success; nonzero on failure.
  */
 static int
-boot_swap_image(struct boot_status *bs)
+boot_swap_image(struct boot_loader_state *state, struct boot_status *bs)
 {
     uint32_t sz;
     int first_sector_idx;
@@ -1458,27 +1561,27 @@
     /* FIXME: just do this if asked by user? */
 
     size = copy_size = 0;
-    image_index = BOOT_CURR_IMG(&boot_data);
+    image_index = BOOT_CURR_IMG(state);
 
     if (bs->idx == BOOT_STATUS_IDX_0 && bs->state == BOOT_STATUS_STATE_0) {
         /*
          * No swap ever happened, so need to find the largest image which
          * will be used to determine the amount of sectors to swap.
          */
-        hdr = boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT);
+        hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
         if (hdr->ih_magic == IMAGE_MAGIC) {
-            rc = boot_read_image_size(BOOT_PRIMARY_SLOT, hdr, &copy_size);
+            rc = boot_read_image_size(state, BOOT_PRIMARY_SLOT, hdr, &copy_size);
             assert(rc == 0);
         }
 
 #ifdef MCUBOOT_ENC_IMAGES
         if (IS_ENCRYPTED(hdr)) {
-            fap = BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT);
-            rc = boot_enc_load(image_index, hdr, fap, bs->enckey[0]);
+            fap = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT);
+            rc = boot_enc_load(state->enc, image_index, hdr, fap, bs->enckey[0]);
             assert(rc >= 0);
 
             if (rc == 0) {
-                rc = boot_enc_set_key(0, bs->enckey[0]);
+                rc = boot_enc_set_key(state->enc, 0, bs->enckey[0]);
                 assert(rc == 0);
             } else {
                 rc = 0;
@@ -1488,21 +1591,21 @@
         }
 #endif
 
-        hdr = boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT);
+        hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
         if (hdr->ih_magic == IMAGE_MAGIC) {
-            rc = boot_read_image_size(BOOT_SECONDARY_SLOT, hdr, &size);
+            rc = boot_read_image_size(state, BOOT_SECONDARY_SLOT, hdr, &size);
             assert(rc == 0);
         }
 
 #ifdef MCUBOOT_ENC_IMAGES
-        hdr = boot_img_hdr(&boot_data, BOOT_SECONDARY_SLOT);
+        hdr = boot_img_hdr(state, BOOT_SECONDARY_SLOT);
         if (IS_ENCRYPTED(hdr)) {
-            fap = BOOT_IMG_AREA(&boot_data, BOOT_SECONDARY_SLOT);
-            rc = boot_enc_load(image_index, hdr, fap, bs->enckey[1]);
+            fap = BOOT_IMG_AREA(state, BOOT_SECONDARY_SLOT);
+            rc = boot_enc_load(state->enc, image_index, hdr, fap, bs->enckey[1]);
             assert(rc >= 0);
 
             if (rc == 0) {
-                rc = boot_enc_set_key(1, bs->enckey[1]);
+                rc = boot_enc_set_key(state->enc, 1, bs->enckey[1]);
                 assert(rc == 0);
             } else {
                 rc = 0;
@@ -1539,7 +1642,7 @@
             }
 
             if (i != BOOT_ENC_KEY_SIZE) {
-                boot_enc_set_key(slot, bs->enckey[slot]);
+                boot_enc_set_key(state->enc, slot, bs->enckey[slot]);
             }
         }
 #endif
@@ -1559,13 +1662,13 @@
     while (1) {
         if ((primary_slot_size < copy_size) ||
             (primary_slot_size < secondary_slot_size)) {
-           primary_slot_size += boot_img_sector_size(&boot_data,
+           primary_slot_size += boot_img_sector_size(state,
                                                      BOOT_PRIMARY_SLOT,
                                                      last_sector_idx);
         }
         if ((secondary_slot_size < copy_size) ||
             (secondary_slot_size < primary_slot_size)) {
-           secondary_slot_size += boot_img_sector_size(&boot_data,
+           secondary_slot_size += boot_img_sector_size(state,
                                                        BOOT_SECONDARY_SLOT,
                                                        last_idx_secondary_slot);
         }
@@ -1580,9 +1683,9 @@
 
     swap_idx = 0;
     while (last_sector_idx >= 0) {
-        sz = boot_copy_sz(last_sector_idx, &first_sector_idx);
+        sz = boot_copy_sz(state, last_sector_idx, &first_sector_idx);
         if (swap_idx >= (bs->idx - BOOT_STATUS_IDX_0)) {
-            boot_swap_sectors(first_sector_idx, sz, bs);
+            boot_swap_sectors(first_sector_idx, sz, state, bs);
         }
 
         last_sector_idx = first_sector_idx - 1;
@@ -1605,7 +1708,7 @@
  */
 #ifndef MCUBOOT_OVERWRITE_ONLY
 static int
-boot_set_copy_done(void)
+boot_set_copy_done(uint8_t image_index)
 {
     const struct flash_area *fap;
     int rc;
@@ -1633,7 +1736,7 @@
  */
 #ifndef MCUBOOT_OVERWRITE_ONLY
 static int
-boot_set_image_ok(void)
+boot_set_image_ok(uint8_t image_index)
 {
     const struct flash_area *fap;
     struct boot_swap_state state;
@@ -1671,7 +1774,8 @@
  * @return                  0 on success; nonzero on failure.
  */
 static int
-boot_verify_single_dependency(struct image_dependency *dep)
+boot_verify_single_dependency(struct boot_loader_state *state,
+                              struct image_dependency *dep)
 {
     struct image_version *dep_version;
     size_t dep_slot;
@@ -1679,9 +1783,9 @@
 
     /* Determine the source of the image which is the subject of
      * the dependency and get it's version. */
-    dep_slot = (boot_data.swap_type[dep->image_id] != BOOT_SWAP_TYPE_NONE) ?
+    dep_slot = (state->swap_type[dep->image_id] != BOOT_SWAP_TYPE_NONE) ?
                 BOOT_SECONDARY_SLOT : BOOT_PRIMARY_SLOT;
-    dep_version = &boot_data.imgs[dep->image_id][dep_slot].hdr.ih_ver;
+    dep_version = &state->imgs[dep->image_id][dep_slot].hdr.ih_ver;
 
     rc = boot_is_version_sufficient(&dep->image_min_version, dep_version);
     if (rc != 0) {
@@ -1691,13 +1795,13 @@
          * consequently the number of unsatisfied dependencies will be
          * decreased or remain the same.
          */
-        switch (BOOT_SWAP_TYPE(&boot_data)) {
+        switch (BOOT_SWAP_TYPE(state)) {
         case BOOT_SWAP_TYPE_TEST:
         case BOOT_SWAP_TYPE_PERM:
-            BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
+            BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
             break;
         case BOOT_SWAP_TYPE_NONE:
-            BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_REVERT;
+            BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
             break;
         default:
             break;
@@ -1716,7 +1820,7 @@
  * @return                  0 on success; nonzero on failure.
  */
 static int
-boot_verify_all_dependency(uint32_t slot)
+boot_verify_all_dependency(struct boot_loader_state *state, uint32_t slot)
 {
     const struct flash_area *fap;
     struct image_header *hdr;
@@ -1729,15 +1833,14 @@
     int area_id;
     int rc;
 
-    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(&boot_data),
-            slot);
+    area_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), slot);
     rc = flash_area_open(area_id, &fap);
     if (rc != 0) {
         rc = BOOT_EFLASH;
         goto done;
     }
 
-    hdr = boot_img_hdr(&boot_data, slot);
+    hdr = boot_img_hdr(state, slot);
     /* The TLVs come after the image. */
     off = hdr->ih_hdr_size + hdr->ih_img_size;
 
@@ -1780,7 +1883,7 @@
             }
 
             /* Verify dependency and modify the swap type if not satisfied. */
-            rc = boot_verify_single_dependency(&dep);
+            rc = boot_verify_single_dependency(state, &dep);
             if (rc != 0) {
                 /* Dependency not satisfied. */
                 goto done;
@@ -1812,7 +1915,7 @@
  *                          nonzero otherwise.
  */
 static int
-boot_verify_single_image_dependency(void)
+boot_verify_single_image_dependency(struct boot_loader_state *state)
 {
     size_t slot;
 
@@ -1820,14 +1923,14 @@
      * be checked which belong to the image that will be located in the primary
      * slot after the firmware update process.
      */
-    if (BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_NONE &&
-        BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_FAIL) {
+    if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE &&
+        BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_FAIL) {
         slot = BOOT_SECONDARY_SLOT;
     } else {
         slot = BOOT_PRIMARY_SLOT;
     }
 
-    return boot_verify_all_dependency(slot);
+    return boot_verify_all_dependency(state, slot);
 }
 
 /**
@@ -1835,19 +1938,19 @@
  * TLV area are all satisfied and update the related swap type if necessary.
  */
 static void
-boot_verify_all_image_dependency(void)
+boot_verify_all_image_dependency(struct boot_loader_state *state)
 {
     int rc;
 
-    BOOT_CURR_IMG(&boot_data) = 0;
-    while (BOOT_CURR_IMG(&boot_data) < BOOT_IMAGE_NUMBER) {
-        rc = boot_verify_single_image_dependency();
+    BOOT_CURR_IMG(state) = 0;
+    while (BOOT_CURR_IMG(state) < BOOT_IMAGE_NUMBER) {
+        rc = boot_verify_single_image_dependency(state);
         if (rc == 0) {
             /* All dependencies've been satisfied, continue with next image. */
-            BOOT_CURR_IMG(&boot_data)++;
+            BOOT_CURR_IMG(state)++;
         } else if (rc == BOOT_EBADVERSION) {
             /* Dependency check needs to be restarted. */
-            BOOT_CURR_IMG(&boot_data) = 0;
+            BOOT_CURR_IMG(state) = 0;
         } else {
             /* Other error happened, images are inconsistent */
             return;
@@ -1864,26 +1967,29 @@
  * @return                      0 on success; nonzero on failure.
  */
 static int
-boot_perform_update(struct boot_status *bs)
+boot_perform_update(struct boot_loader_state *state, struct boot_status *bs)
 {
     int rc;
+#ifndef MCUBOOT_OVERWRITE_ONLY
+    uint8_t swap_type;
+#endif
 
     /* At this point there are no aborted swaps. */
 #if defined(MCUBOOT_OVERWRITE_ONLY)
-    rc = boot_copy_image(bs);
+    rc = boot_copy_image(state, bs);
 #elif defined(MCUBOOT_BOOTSTRAP)
     /* Check if the image update was triggered by a bad image in the
      * primary slot (the validity of the image in the secondary slot had
      * already been checked).
      */
-    if (boot_check_header_erased(BOOT_PRIMARY_SLOT) == 0 ||
-        boot_validate_slot(BOOT_PRIMARY_SLOT, bs) != 0) {
-        rc = boot_copy_image(bs);
+    if (boot_check_header_erased(state, BOOT_PRIMARY_SLOT) == 0 ||
+        boot_validate_slot(state, BOOT_PRIMARY_SLOT, bs) != 0) {
+        rc = boot_copy_image(state, bs);
     } else {
-        rc = boot_swap_image(bs);
+        rc = boot_swap_image(state, bs);
     }
 #else
-        rc = boot_swap_image(bs);
+        rc = boot_swap_image(state, bs);
 #endif
     assert(rc == 0);
 
@@ -1891,20 +1997,21 @@
     /* The following state needs image_ok be explicitly set after the
      * swap was finished to avoid a new revert.
      */
-    if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_REVERT ||
-        BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PERM) {
-        rc = boot_set_image_ok();
+    swap_type = BOOT_SWAP_TYPE(state);
+    if (swap_type == BOOT_SWAP_TYPE_REVERT ||
+            swap_type == BOOT_SWAP_TYPE_PERM) {
+        rc = boot_set_image_ok(BOOT_CURR_IMG(state));
         if (rc != 0) {
-            BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
+            BOOT_SWAP_TYPE(state) = swap_type = BOOT_SWAP_TYPE_PANIC;
         }
     }
 
-    if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_TEST ||
-        BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PERM ||
-        BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_REVERT) {
-        rc = boot_set_copy_done();
+    if (swap_type == BOOT_SWAP_TYPE_TEST ||
+            swap_type == BOOT_SWAP_TYPE_PERM ||
+            swap_type == BOOT_SWAP_TYPE_REVERT) {
+        rc = boot_set_copy_done(BOOT_CURR_IMG(state));
         if (rc != 0) {
-            BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
+            BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
         }
     }
 #endif /* !MCUBOOT_OVERWRITE_ONLY */
@@ -1921,39 +2028,40 @@
  */
 #if !defined(MCUBOOT_OVERWRITE_ONLY)
 static int
-boot_complete_partial_swap(struct boot_status *bs)
+boot_complete_partial_swap(struct boot_loader_state *state,
+        struct boot_status *bs)
 {
     int rc;
 
     /* Determine the type of swap operation being resumed from the
      * `swap-type` trailer field.
      */
-    rc = boot_swap_image(bs);
+    rc = boot_swap_image(state, bs);
     assert(rc == 0);
 
-    BOOT_SWAP_TYPE(&boot_data) = bs->swap_type;
+    BOOT_SWAP_TYPE(state) = bs->swap_type;
 
     /* The following states need image_ok be explicitly set after the
      * swap was finished to avoid a new revert.
      */
     if (bs->swap_type == BOOT_SWAP_TYPE_REVERT ||
         bs->swap_type == BOOT_SWAP_TYPE_PERM) {
-        rc = boot_set_image_ok();
+        rc = boot_set_image_ok(BOOT_CURR_IMG(state));
         if (rc != 0) {
-            BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
+            BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
         }
     }
 
     if (bs->swap_type == BOOT_SWAP_TYPE_TEST ||
         bs->swap_type == BOOT_SWAP_TYPE_PERM ||
         bs->swap_type == BOOT_SWAP_TYPE_REVERT) {
-        rc = boot_set_copy_done();
+        rc = boot_set_copy_done(BOOT_CURR_IMG(state));
         if (rc != 0) {
-            BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
+            BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
         }
     }
 
-    if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PANIC) {
+    if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
         BOOT_LOG_ERR("panic!");
         assert(0);
 
@@ -1973,7 +2081,8 @@
  *                              partial/aborted swap.
  */
 static void
-boot_review_image_swap_types(bool aborted_swap)
+boot_review_image_swap_types(struct boot_loader_state *state,
+                             bool aborted_swap)
 {
     /* In that case if we rebooted in the middle of an image upgrade process, we
      * must review the validity of swap types, that were previously determined
@@ -2000,22 +2109,22 @@
      *      upgrades).
      */
 
-    if (BOOT_CURR_IMG(&boot_data) == 0) {
+    if (BOOT_CURR_IMG(state) == 0) {
         /* Nothing to do */
         return;
     }
 
     if (!aborted_swap) {
-        if ((BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_NONE) ||
-            (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_REVERT)) {
+        if ((BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) ||
+            (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_REVERT)) {
             /* Nothing to do */
             return;
         }
     }
 
-    for (uint8_t i = 0; i < BOOT_CURR_IMG(&boot_data); i++) {
-        if (boot_data.swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
-            boot_data.swap_type[i] = BOOT_SWAP_TYPE_NONE;
+    for (uint8_t i = 0; i < BOOT_CURR_IMG(state); i++) {
+        if (state->swap_type[i] == BOOT_SWAP_TYPE_REVERT) {
+            state->swap_type[i] = BOOT_SWAP_TYPE_NONE;
         }
     }
 }
@@ -2028,47 +2137,48 @@
  * operation if one was aborted and/or determining the type of the
  * swap operation. In case of any error set the swap type to NONE.
  *
+ * @param state                 TODO
  * @param bs                    Pointer where the read and possibly updated
  *                              boot status can be written to.
  */
 static void
-boot_prepare_image_for_update(struct boot_status *bs)
+boot_prepare_image_for_update(struct boot_loader_state *state,
+                              struct boot_status *bs)
 {
     int rc;
 
     /* Determine the sector layout of the image slots and scratch area. */
-    rc = boot_read_sectors();
+    rc = boot_read_sectors(state);
     if (rc != 0) {
         BOOT_LOG_WRN("Failed reading sectors; BOOT_MAX_IMG_SECTORS=%d"
                      " - too small?", BOOT_MAX_IMG_SECTORS);
         /* Unable to determine sector layout, continue with next image
          * if there is one.
          */
-        BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
+        BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
         return;
     }
 
     /* Attempt to read an image header from each slot. */
-    rc = boot_read_image_headers(false);
+    rc = boot_read_image_headers(state, false);
     if (rc != 0) {
         /* Continue with next image if there is one. */
         BOOT_LOG_WRN("Failed reading image headers; Image=%u",
-                BOOT_CURR_IMG(&boot_data));
-        BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
+                BOOT_CURR_IMG(state));
+        BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
         return;
     }
 
     /* If the current image's slots aren't compatible, no swap is possible.
      * Just boot into primary slot.
      */
-    if (boot_slots_compatible()) {
-
-        rc = boot_read_status(bs);
+    if (boot_slots_compatible(state)) {
+        rc = boot_read_status(state, bs);
         if (rc != 0) {
             BOOT_LOG_WRN("Failed reading boot status; Image=%u",
-                    BOOT_CURR_IMG(&boot_data));
+                    BOOT_CURR_IMG(state));
             /* Continue with next image if there is one. */
-            BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
+            BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
             return;
         }
 
@@ -2078,7 +2188,7 @@
         if (bs->idx != BOOT_STATUS_IDX_0 || bs->state != BOOT_STATUS_STATE_0) {
 
 #if (BOOT_IMAGE_NUMBER > 1)
-            boot_review_image_swap_types(true);
+            boot_review_image_swap_types(state, true);
 #endif
 
 #ifdef MCUBOOT_OVERWRITE_ONLY
@@ -2090,51 +2200,51 @@
             /* Determine the type of swap operation being resumed from the
              * `swap-type` trailer field.
              */
-            rc = boot_complete_partial_swap(bs);
+            rc = boot_complete_partial_swap(state, bs);
             assert(rc == 0);
 #endif
             /* Attempt to read an image header from each slot. Ensure that
              * image headers in slots are aligned with headers in boot_data.
              */
-            rc = boot_read_image_headers(false);
+            rc = boot_read_image_headers(state, false);
             assert(rc == 0);
 
             /* Swap has finished set to NONE */
-            BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
+            BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
         } else {
             /* There was no partial swap, determine swap type. */
             if (bs->swap_type == BOOT_SWAP_TYPE_NONE) {
-                BOOT_SWAP_TYPE(&boot_data) = boot_validated_swap_type(bs);
-            } else if (boot_validate_slot(BOOT_SECONDARY_SLOT, bs) != 0) {
-                BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_FAIL;
+                BOOT_SWAP_TYPE(state) = boot_validated_swap_type(state, bs);
+            } else if (boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs) != 0) {
+                BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_FAIL;
             } else {
-                BOOT_SWAP_TYPE(&boot_data) = bs->swap_type;
+                BOOT_SWAP_TYPE(state) = bs->swap_type;
             }
 
 #if (BOOT_IMAGE_NUMBER > 1)
-            boot_review_image_swap_types(false);
+            boot_review_image_swap_types(state, false);
 #endif
 
 #ifdef MCUBOOT_BOOTSTRAP
-            if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_NONE) {
+            if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_NONE) {
                 /* Header checks are done first because they are
                  * inexpensive. Since overwrite-only copies starting from
                  * offset 0, if interrupted, it might leave a valid header
                  * magic, so also run validation on the primary slot to be
                  * sure it's not OK.
                  */
-                 if (boot_check_header_erased(BOOT_PRIMARY_SLOT) == 0 ||
-                     boot_validate_slot(BOOT_PRIMARY_SLOT, bs) != 0) {
-                     if (boot_img_hdr(&boot_data,
+                 if (boot_check_header_erased(state, BOOT_PRIMARY_SLOT) == 0 ||
+                     boot_validate_slot(state, BOOT_PRIMARY_SLOT, bs) != 0) {
+                     if (boot_img_hdr(state,
                           BOOT_SECONDARY_SLOT)->ih_magic == IMAGE_MAGIC &&
-                         boot_validate_slot(BOOT_SECONDARY_SLOT, bs) == 0)
+                         boot_validate_slot(state, BOOT_SECONDARY_SLOT, bs) == 0)
                      {
                         /* Set swap type to REVERT to overwrite the primary
                          * slot with the image contained in secondary slot
                          * and to trigger the explicit setting of the
                          * image_ok flag.
                          */
-                         BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_REVERT;
+                         BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_REVERT;
                     }
                 }
             }
@@ -2142,20 +2252,12 @@
         }
     } else {
         /* In that case if slots are not compatible. */
-        BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_NONE;
+        BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_NONE;
     }
 }
 
-/**
- * Prepares the booting process.  This function moves images around in flash as
- * appropriate, and tells you what address to boot from.
- *
- * @param rsp                   On success, indicates how booting should occur.
- *
- * @return                      0 on success; nonzero on failure.
- */
 int
-boot_go(struct boot_rsp *rsp)
+context_boot_go(struct boot_loader_state *state, struct boot_rsp *rsp)
 {
     size_t slot;
     struct boot_status bs;
@@ -2168,67 +2270,62 @@
      * necessary because the gcc option "-fdata-sections" doesn't seem to have
      * any effect in older gcc versions (e.g., 4.8.4).
      */
-    static boot_sector_t
-        primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
-    static boot_sector_t
-        secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
-    static boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
+    TARGET_STATIC boot_sector_t primary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
+    TARGET_STATIC boot_sector_t secondary_slot_sectors[BOOT_IMAGE_NUMBER][BOOT_MAX_IMG_SECTORS];
+    TARGET_STATIC boot_sector_t scratch_sectors[BOOT_MAX_IMG_SECTORS];
 
-#ifdef MCUBOOT_ENC_IMAGES
-    /* FIXME: remove this after RAM is cleared by sim */
-    boot_enc_zeroize();
-#endif
+    memset(state, 0, sizeof(struct boot_loader_state));
 
     /* Iterate over all the images. By the end of the loop the swap type has
      * to be determined for each image and all aborted swaps have to be
      * completed.
      */
-    IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
+    IMAGES_ITER(BOOT_CURR_IMG(state)) {
 
 #if defined(MCUBOOT_ENC_IMAGES) && (BOOT_IMAGE_NUMBER > 1)
         /* The keys used for encryption may no longer be valid (could belong to
          * another images). Therefore, mark them as invalid to force their reload
          * by boot_enc_load().
          */
-        boot_enc_mark_keys_invalid();
+        boot_enc_mark_keys_invalid(state->enc);
 #endif
 
-        image_index = BOOT_CURR_IMG(&boot_data);
+        image_index = BOOT_CURR_IMG(state);
 
-        BOOT_IMG(&boot_data, BOOT_PRIMARY_SLOT).sectors =
+        BOOT_IMG(state, BOOT_PRIMARY_SLOT).sectors =
             primary_slot_sectors[image_index];
-        BOOT_IMG(&boot_data, BOOT_SECONDARY_SLOT).sectors =
+        BOOT_IMG(state, BOOT_SECONDARY_SLOT).sectors =
             secondary_slot_sectors[image_index];
-        boot_data.scratch.sectors = scratch_sectors;
+        state->scratch.sectors = scratch_sectors;
 
         /* Open primary and secondary image areas for the duration
          * of this call.
          */
         for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
             fa_id = flash_area_id_from_multi_image_slot(image_index, slot);
-            rc = flash_area_open(fa_id, &BOOT_IMG_AREA(&boot_data, slot));
+            rc = flash_area_open(fa_id, &BOOT_IMG_AREA(state, slot));
             assert(rc == 0);
         }
         rc = flash_area_open(FLASH_AREA_IMAGE_SCRATCH,
-                             &BOOT_SCRATCH_AREA(&boot_data));
+                             &BOOT_SCRATCH_AREA(state));
         assert(rc == 0);
 
         /* Determine swap type and complete swap if it has been aborted. */
-        boot_prepare_image_for_update(&bs);
+        boot_prepare_image_for_update(state, &bs);
     }
 
 #if (BOOT_IMAGE_NUMBER > 1)
     /* Iterate over all the images and verify whether the image dependencies
      * are all satisfied and update swap type if necessary.
      */
-    boot_verify_all_image_dependency();
+    boot_verify_all_image_dependency(state);
 #endif
 
     /* Iterate over all the images. At this point there are no aborted swaps
      * and the swap types are determined for each image. By the end of the loop
      * all required update operations will have been finished.
      */
-    IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
+    IMAGES_ITER(BOOT_CURR_IMG(state)) {
 
 #if (BOOT_IMAGE_NUMBER > 1)
 #ifdef MCUBOOT_ENC_IMAGES
@@ -2246,16 +2343,16 @@
 #endif /* (BOOT_IMAGE_NUMBER > 1) */
 
         /* Set the previously determined swap type */
-        bs.swap_type = BOOT_SWAP_TYPE(&boot_data);
+        bs.swap_type = BOOT_SWAP_TYPE(state);
 
-        switch (BOOT_SWAP_TYPE(&boot_data)) {
+        switch (BOOT_SWAP_TYPE(state)) {
         case BOOT_SWAP_TYPE_NONE:
             break;
 
         case BOOT_SWAP_TYPE_TEST:          /* fallthrough */
         case BOOT_SWAP_TYPE_PERM:          /* fallthrough */
         case BOOT_SWAP_TYPE_REVERT:
-            rc = boot_perform_update(&bs);
+            rc = boot_perform_update(state, &bs);
             assert(rc == 0);
             break;
 
@@ -2266,18 +2363,18 @@
              */
 #ifndef MCUBOOT_OVERWRITE_ONLY
             /* image_ok needs to be explicitly set to avoid a new revert. */
-            rc = boot_set_image_ok();
+            rc = boot_set_image_ok(BOOT_CURR_IMG(state));
             if (rc != 0) {
-                BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
+                BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
             }
 #endif /* !MCUBOOT_OVERWRITE_ONLY */
             break;
 
         default:
-            BOOT_SWAP_TYPE(&boot_data) = BOOT_SWAP_TYPE_PANIC;
+            BOOT_SWAP_TYPE(state) = BOOT_SWAP_TYPE_PANIC;
         }
 
-        if (BOOT_SWAP_TYPE(&boot_data) == BOOT_SWAP_TYPE_PANIC) {
+        if (BOOT_SWAP_TYPE(state) == BOOT_SWAP_TYPE_PANIC) {
             BOOT_LOG_ERR("panic!");
             assert(0);
 
@@ -2290,12 +2387,12 @@
      * have finished. By the end of the loop each image in the primary slot will
      * have been re-validated.
      */
-    IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
-        if (BOOT_SWAP_TYPE(&boot_data) != BOOT_SWAP_TYPE_NONE) {
+    IMAGES_ITER(BOOT_CURR_IMG(state)) {
+        if (BOOT_SWAP_TYPE(state) != BOOT_SWAP_TYPE_NONE) {
             /* Attempt to read an image header from each slot. Ensure that image
              * headers in slots are aligned with headers in boot_data.
              */
-            rc = boot_read_image_headers(false);
+            rc = boot_read_image_headers(state, false);
             if (rc != 0) {
                 goto out;
             }
@@ -2307,7 +2404,7 @@
         }
 
 #ifdef MCUBOOT_VALIDATE_PRIMARY_SLOT
-        rc = boot_validate_slot(BOOT_PRIMARY_SLOT, NULL);
+        rc = boot_validate_slot(state, BOOT_PRIMARY_SLOT, NULL);
         if (rc != 0) {
             rc = BOOT_EBADIMAGE;
             goto out;
@@ -2317,11 +2414,10 @@
          * onto an empty flash chip. At least do a basic sanity check that
          * the magic number on the image is OK.
          */
-        if (BOOT_IMG(&boot_data, BOOT_PRIMARY_SLOT).hdr.ih_magic !=
-                IMAGE_MAGIC) {
+        if (BOOT_IMG(state, BOOT_PRIMARY_SLOT).hdr.ih_magic != IMAGE_MAGIC) {
             BOOT_LOG_ERR("bad image magic 0x%lx; Image=%u", (unsigned long)
-                         &boot_img_hdr(&boot_data,BOOT_PRIMARY_SLOT)->ih_magic,
-                         BOOT_CURR_IMG(&boot_data));
+                         &boot_img_hdr(state,BOOT_PRIMARY_SLOT)->ih_magic,
+                         BOOT_CURR_IMG(state));
             rc = BOOT_EBADIMAGE;
             goto out;
         }
@@ -2330,26 +2426,36 @@
 
 #if (BOOT_IMAGE_NUMBER > 1)
     /* Always boot from the primary slot of Image 0. */
-    BOOT_CURR_IMG(&boot_data) = 0;
+    BOOT_CURR_IMG(state) = 0;
 #endif
-    rsp->br_flash_dev_id =
-            BOOT_IMG_AREA(&boot_data, BOOT_PRIMARY_SLOT)->fa_device_id;
-    rsp->br_image_off =
-            boot_img_slot_off(&boot_data, BOOT_PRIMARY_SLOT);
-    rsp->br_hdr =
-            boot_img_hdr(&boot_data, BOOT_PRIMARY_SLOT);
+    rsp->br_flash_dev_id = BOOT_IMG_AREA(state, BOOT_PRIMARY_SLOT)->fa_device_id;
+    rsp->br_image_off = boot_img_slot_off(state, BOOT_PRIMARY_SLOT);
+    rsp->br_hdr = boot_img_hdr(state, BOOT_PRIMARY_SLOT);
 
  out:
-    IMAGES_ITER(BOOT_CURR_IMG(&boot_data)) {
-        flash_area_close(BOOT_SCRATCH_AREA(&boot_data));
+    IMAGES_ITER(BOOT_CURR_IMG(state)) {
+        flash_area_close(BOOT_SCRATCH_AREA(state));
         for (slot = 0; slot < BOOT_NUM_SLOTS; slot++) {
-            flash_area_close(BOOT_IMG_AREA(&boot_data,
-                                           BOOT_NUM_SLOTS - 1 - slot));
+            flash_area_close(BOOT_IMG_AREA(state, BOOT_NUM_SLOTS - 1 - slot));
         }
     }
     return rc;
 }
 
+/**
+ * Prepares the booting process.  This function moves images around in flash as
+ * appropriate, and tells you what address to boot from.
+ *
+ * @param rsp                   On success, indicates how booting should occur.
+ *
+ * @return                      0 on success; nonzero on failure.
+ */
+int
+boot_go(struct boot_rsp *rsp)
+{
+    return context_boot_go(&boot_data, rsp);
+}
+
 int
 split_go(int loader_slot, int split_slot, void **entry)
 {
@@ -2376,13 +2482,13 @@
     assert(rc == 0);
 
     /* Determine the sector layout of the image slots and scratch area. */
-    rc = boot_read_sectors();
+    rc = boot_read_sectors(&boot_data);
     if (rc != 0) {
         rc = SPLIT_GO_ERR;
         goto done;
     }
 
-    rc = boot_read_image_headers(true);
+    rc = boot_read_image_headers(&boot_data, true);
     if (rc != 0) {
         goto done;
     }