bootutil: Add active slot number and max app size to shared data

This allows the currently executing slot number to be checked by
the external function, which can be used by XIP images to know
which slot is currently being executed from to allow for correct
uploading/positioning of firmware files, and also provides the
maximum size of an upgrade that can be loaded so that applications
can reject images that are too large.

Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
diff --git a/boot/bootutil/src/swap_scratch.c b/boot/bootutil/src/swap_scratch.c
index bb0d12d..66cbdce 100644
--- a/boot/bootutil/src/swap_scratch.c
+++ b/boot/bootutil/src/swap_scratch.c
@@ -743,6 +743,118 @@
 }
 #endif /* !MCUBOOT_OVERWRITE_ONLY */
 
+int app_max_size(struct boot_loader_state *state)
+{
+    size_t num_sectors_primary;
+    size_t num_sectors_secondary;
+    size_t sz0, sz1;
+    size_t primary_slot_sz, secondary_slot_sz;
+#ifndef MCUBOOT_OVERWRITE_ONLY
+    size_t scratch_sz;
+#endif
+    size_t i, j;
+    int8_t smaller;
+
+    num_sectors_primary = boot_img_num_sectors(state, BOOT_PRIMARY_SLOT);
+    num_sectors_secondary = boot_img_num_sectors(state, BOOT_SECONDARY_SLOT);
+
+#ifndef MCUBOOT_OVERWRITE_ONLY
+    scratch_sz = boot_scratch_area_size(state);
+#endif
+
+    /*
+     * The following loop scans all sectors in a linear fashion, assuring that
+     * for each possible sector in each slot, it is able to fit in the other
+     * slot's sector or sectors. Slot's should be compatible as long as any
+     * number of a slot's sectors are able to fit into another, which only
+     * excludes cases where sector sizes are not a multiple of each other.
+     */
+    i = sz0 = primary_slot_sz = 0;
+    j = sz1 = secondary_slot_sz = 0;
+    smaller = 0;
+    while (i < num_sectors_primary || j < num_sectors_secondary) {
+        if (sz0 == sz1) {
+            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(state, BOOT_PRIMARY_SLOT, i);
+            /* Guarantee that multiple sectors of the secondary slot
+             * fit into the primary slot.
+             */
+            if (smaller == 2) {
+                BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
+                return 0;
+            }
+            smaller = 1;
+            i++;
+        } else {
+            sz1 += boot_img_sector_size(state, BOOT_SECONDARY_SLOT, j);
+            /* Guarantee that multiple sectors of the primary slot
+             * fit into the secondary slot.
+             */
+            if (smaller == 1) {
+                BOOT_LOG_WRN("Cannot upgrade: slots have non-compatible sectors");
+                return 0;
+            }
+            smaller = 2;
+            j++;
+        }
+#ifndef MCUBOOT_OVERWRITE_ONLY
+        if (sz0 == sz1) {
+            primary_slot_sz += sz0;
+            secondary_slot_sz += sz1;
+            /* Scratch has to fit each swap operation to the size of the larger
+             * sector among the primary slot and the secondary slot.
+             */
+            if (sz0 > scratch_sz || sz1 > scratch_sz) {
+                BOOT_LOG_WRN("Cannot upgrade: not all sectors fit inside scratch");
+                return 0;
+            }
+            smaller = sz0 = sz1 = 0;
+        }
+#endif
+    }
+
+#ifdef MCUBOOT_OVERWRITE_ONLY
+    return (sz1 < sz0 ? sz1 : sz0);
+#else
+    return (secondary_slot_sz < primary_slot_sz ? secondary_slot_sz : primary_slot_sz);
+#endif
+}
+#else
+int app_max_size(struct boot_loader_state *state)
+{
+    const struct flash_area *fap;
+    int fa_id;
+    int rc;
+    uint32_t active_slot;
+    int primary_sz, secondary_sz;
+
+    active_slot = state->slot_usage[BOOT_CURR_IMG(state)].active_slot;
+
+    fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
+    rc = flash_area_open(fa_id, &fap);
+    assert(rc == 0);
+    primary_sz = flash_area_get_size(fap);
+    flash_area_close(fap);
+
+    if (active_slot == BOOT_PRIMARY_SLOT) {
+        active_slot = BOOT_SECONDARY_SLOT;
+    } else {
+        active_slot = BOOT_PRIMARY_SLOT;
+    }
+
+    fa_id = flash_area_id_from_multi_image_slot(BOOT_CURR_IMG(state), active_slot);
+    rc = flash_area_open(fa_id, &fap);
+    assert(rc == 0);
+    secondary_sz = flash_area_get_size(fap);
+    flash_area_close(fap);
+
+    return (secondary_sz < primary_sz ? secondary_sz : primary_sz);
+}
+
 #endif /* !MCUBOOT_DIRECT_XIP && !MCUBOOT_RAM_LOAD */
 
 #endif /* !MCUBOOT_SWAP_USING_MOVE */