Implement new swap scheme for devices with large erase size using scratch with status area
diff --git a/sim/Cargo.toml b/sim/Cargo.toml
index ddf3b88..02f0f73 100644
--- a/sim/Cargo.toml
+++ b/sim/Cargo.toml
@@ -14,6 +14,7 @@
 sig-ed25519 = ["mcuboot-sys/sig-ed25519"]
 overwrite-only = ["mcuboot-sys/overwrite-only"]
 swap-move = ["mcuboot-sys/swap-move"]
+swap-status = ["mcuboot-sys/swap-status"]
 validate-primary-slot = ["mcuboot-sys/validate-primary-slot"]
 enc-rsa = ["mcuboot-sys/enc-rsa"]
 enc-kw = ["mcuboot-sys/enc-kw"]
diff --git a/sim/mcuboot-sys/Cargo.toml b/sim/mcuboot-sys/Cargo.toml
index 19114f9..ef09755 100644
--- a/sim/mcuboot-sys/Cargo.toml
+++ b/sim/mcuboot-sys/Cargo.toml
@@ -30,6 +30,8 @@
 # Overwrite only upgrade
 overwrite-only = []
 
+swap-status = []
+
 swap-move = []
 
 # Disable validation of the primary slot
diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs
index 74b19f0..a2206c9 100644
--- a/sim/mcuboot-sys/build.rs
+++ b/sim/mcuboot-sys/build.rs
@@ -16,6 +16,7 @@
     let sig_ed25519 = env::var("CARGO_FEATURE_SIG_ED25519").is_ok();
     let overwrite_only = env::var("CARGO_FEATURE_OVERWRITE_ONLY").is_ok();
     let swap_move = env::var("CARGO_FEATURE_SWAP_MOVE").is_ok();
+    let swap_status = env::var("CARGO_FEATURE_SWAP_STATUS").is_ok();
     let validate_primary_slot =
                   env::var("CARGO_FEATURE_VALIDATE_PRIMARY_SLOT").is_ok();
     let enc_rsa = env::var("CARGO_FEATURE_ENC_RSA").is_ok();
@@ -31,7 +32,9 @@
     conf.define("MCUBOOT_HAVE_LOGGING", None);
     conf.define("MCUBOOT_USE_FLASH_AREA_GET_SECTORS", None);
     conf.define("MCUBOOT_HAVE_ASSERT_H", None);
-    conf.define("MCUBOOT_MAX_IMG_SECTORS", Some("128"));
+    if !swap_status {
+        conf.define("MCUBOOT_MAX_IMG_SECTORS", Some("128"));
+    }
     conf.define("MCUBOOT_IMAGE_NUMBER", Some(if multiimage { "2" } else { "1" }));
 
     if downgrade_prevention && !overwrite_only {
@@ -40,7 +43,6 @@
 
     if bootstrap {
         conf.define("MCUBOOT_BOOTSTRAP", None);
-        conf.define("MCUBOOT_OVERWRITE_ONLY_FAST", None);
     }
 
     if validate_primary_slot {
@@ -138,10 +140,25 @@
 
     if overwrite_only {
         conf.define("MCUBOOT_OVERWRITE_ONLY", None);
+        conf.define("MCUBOOT_OVERWRITE_ONLY_FAST", None);
     }
 
     if swap_move {
         conf.define("MCUBOOT_SWAP_USING_MOVE", None);
+        conf.file("../../boot/bootutil/src/swap_move.c");
+    }
+
+    if swap_status {
+        conf.define("MCUBOOT_SWAP_USING_STATUS", None);
+        conf.define("MCUBOOT_LOG_LEVEL", "MCUBOOT_LOG_LEVEL_DEBUG");
+        conf.define("MCUBOOT_MAX_IMG_SECTORS", Some("2000"));
+        conf.define("CY_FLASH_ALIGN", "512");
+        conf.file("../../boot/bootutil/src/swap_status.c");
+        conf.file("../../boot/bootutil/src/swap_status_part.c");
+        conf.file("../../boot/bootutil/src/swap_status_misc.c");
+        conf.file("../../boot/bootutil/src/crc32c.c");
+//        conf.file("../../boot/cypress/cy_flash_pal/cy_my_support.c");
+        conf.include("../../boot/cypress/cy_flash_pal");
     }
 
     if enc_rsa {
@@ -284,7 +301,6 @@
     conf.file("../../boot/bootutil/src/loader.c");
     conf.file("../../boot/bootutil/src/swap_misc.c");
     conf.file("../../boot/bootutil/src/swap_scratch.c");
-    conf.file("../../boot/bootutil/src/swap_move.c");
     conf.file("../../boot/bootutil/src/caps.c");
     conf.file("../../boot/bootutil/src/bootutil_misc.c");
     conf.file("../../boot/bootutil/src/bootutil_public.c");
diff --git a/sim/mcuboot-sys/csupport/devicetree.h b/sim/mcuboot-sys/csupport/devicetree.h
index 434e4ee..73c7c83 100644
--- a/sim/mcuboot-sys/csupport/devicetree.h
+++ b/sim/mcuboot-sys/csupport/devicetree.h
@@ -17,4 +17,11 @@
 #define FLASH_AREA_ID_image_2 4
 #define FLASH_AREA_ID_image_3 5
 
+#define FLASH_AREA_IMAGE_0     FLASH_AREA_ID(image_0)
+#define FLASH_AREA_IMAGE_1     FLASH_AREA_ID(image_1)
+#define FLASH_AREA_IMAGE_2     FLASH_AREA_ID(image_2)
+#define FLASH_AREA_IMAGE_3     FLASH_AREA_ID(image_3)
+
+#define FLASH_AREA_IMAGE_SWAP_STATUS FLASH_AREA_ID(image_scratch)
+
 #endif /*__DEVICETREE_H__*/
diff --git a/sim/mcuboot-sys/csupport/run.c b/sim/mcuboot-sys/csupport/run.c
index 0133262..fd21bfd 100644
--- a/sim/mcuboot-sys/csupport/run.c
+++ b/sim/mcuboot-sys/csupport/run.c
@@ -22,7 +22,6 @@
 #include "mbedtls/nist_kw.h"
 #endif
 
-#define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_ERROR
 #include <bootutil/bootutil_log.h>
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@@ -262,30 +261,53 @@
     return malloc(size);
 }
 
+void os_free(void *mem)
+{
+    free(mem);
+}
+
+void *os_realloc(void *ptr, size_t size)
+{
+    return realloc(ptr, size);
+}
+
 int flash_area_id_from_multi_image_slot(int image_index, int slot)
 {
     switch (slot) {
     case 0: return FLASH_AREA_IMAGE_PRIMARY(image_index);
     case 1: return FLASH_AREA_IMAGE_SECONDARY(image_index);
     case 2: return FLASH_AREA_IMAGE_SCRATCH;
+
+    // case 7: return FLASH_AREA_IMAGE_SWAP_STATUS;
     }
 
-    printf("Image flash area ID not found\n");
+    printf("Image flash area ID not found, image=%d, slot=%d\n", image_index, slot);
     return -1; /* flash_area_open will fail on that */
 }
 
+int flash_area_id_from_image_slot(int slot)
+{
+    return flash_area_id_from_multi_image_slot(0, slot);
+}
+
 int flash_area_open(uint8_t id, const struct flash_area **area)
 {
     uint32_t i;
     struct area_desc *flash_areas;
 
+    // BOOT_LOG_SIM("%s: area id=%d, num_slots=%d", __func__, id, sim_get_flash_areas()->num_slots);
+
     flash_areas = sim_get_flash_areas();
     for (i = 0; i < flash_areas->num_slots; i++) {
+        // BOOT_LOG_SIM(" * flash_areas->slots[%d].id=%d", i, flash_areas->slots[i].id);
         if (flash_areas->slots[i].id == id)
+        {
+            // BOOT_LOG_SIM(" * found, i=%d, id=%d", i, id);
             break;
+        }
     }
     if (i == flash_areas->num_slots) {
-        printf("Unsupported area\n");
+        printf("Unsupported area id=%d\n", id);
         abort();
     }
 
@@ -341,20 +363,22 @@
     struct area *slot;
     struct area_desc *flash_areas;
 
+    // BOOT_LOG_SIM("%s: idx=%d", __func__, idx);
+
     flash_areas = sim_get_flash_areas();
     for (i = 0; i < flash_areas->num_slots; i++) {
         if (flash_areas->slots[i].id == idx)
             break;
     }
     if (i == flash_areas->num_slots) {
-        printf("Unsupported area\n");
+        printf("flash_area_to_sectors: Unsupported area = %d\n", idx);
         abort();
     }
 
     slot = &flash_areas->slots[i];
 
     if (slot->num_areas > (uint32_t)*cnt) {
-        printf("Too many areas in slot\n");
+        printf("Too many areas in slot: %d > %d\n", slot->num_areas, *cnt);
         abort();
     }
 
@@ -371,20 +395,22 @@
     struct area *slot;
     struct area_desc *flash_areas;
 
+    // BOOT_LOG_SIM("%s: area id=%d", __func__, fa_id);
+
     flash_areas = sim_get_flash_areas();
     for (i = 0; i < flash_areas->num_slots; i++) {
         if (flash_areas->slots[i].id == fa_id)
             break;
     }
     if (i == flash_areas->num_slots) {
-        printf("Unsupported area\n");
+        printf("flash_area_get_sectors: Unsupported area = %d\n", fa_id);
         abort();
     }
 
     slot = &flash_areas->slots[i];
 
     if (slot->num_areas > *count) {
-        printf("Too many areas in slot\n");
+        printf("Too many areas in slot: %d > %d\n", slot->num_areas, *count);
         abort();
     }
 
@@ -407,7 +433,7 @@
         return 1;
     }
 
-    printf("Unsupported image area ID\n");
+    printf("Unsupported image area ID=%d\n", area_id);
     abort();
 }
 
@@ -437,3 +463,28 @@
 {
     return BOOT_MAGIC_SZ;
 }
+
+void mbedtls_platform_zeroize( void *buf, size_t len )
+{
+    memset( buf, 0, len );
+}
+
+int flash_area_read_is_empty(const struct flash_area *fa, uint32_t off,
+        void *dst, uint32_t len)
+{
+    uint8_t *mem_dest;
+    int rc;
+
+    mem_dest = (uint8_t *)dst;
+    rc = flash_area_read(fa, off, dst, len);
+    if (rc) {
+        return -1;
+    }
+
+    for (uint8_t i = 0; i < len; i++) {
+        if (mem_dest[i] != flash_area_erased_val(fa)) {
+            return 0;
+        }
+    }
+    return 1;
+}
diff --git a/sim/mcuboot-sys/src/area.rs b/sim/mcuboot-sys/src/area.rs
index 9d65078..f151fe4 100644
--- a/sim/mcuboot-sys/src/area.rs
+++ b/sim/mcuboot-sys/src/area.rs
@@ -189,6 +189,8 @@
     ImageScratch = 3,
     Image2 = 4,
     Image3 = 5,
+    //ImageSwapStatus = 7,
+    //ImageSwapStatus = 3,
 }
 
 impl Default for FlashId {
diff --git a/sim/simflash/src/lib.rs b/sim/simflash/src/lib.rs
index 532fb0e..c52f53e 100644
--- a/sim/simflash/src/lib.rs
+++ b/sim/simflash/src/lib.rs
@@ -66,6 +66,8 @@
 
     fn align(&self) -> usize;
     fn erased_val(&self) -> u8;
+
+    fn set_erase_by_sector(&mut self, enable: bool);
 }
 
 fn ebounds<T: AsRef<str>>(message: T) -> FlashError {
@@ -94,6 +96,7 @@
     align: usize,
     verify_writes: bool,
     erased_val: u8,
+    erase_by_sector: bool,
 }
 
 impl SimFlash {
@@ -130,11 +133,11 @@
 
     // Scan the sector map, and return the base and offset within a sector for this given byte.
     // Returns None if the value is outside of the device.
-    fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
+    fn get_sector(&self, offset: usize) -> Option<(usize, usize, usize)> {
         let mut offset = offset;
         for (sector, &size) in self.sectors.iter().enumerate() {
             if offset < size {
-                return Some((sector, offset));
+                return Some((sector, offset, size));
             }
             offset -= size;
         }
@@ -150,8 +153,21 @@
     /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
     /// return an error.
     fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
-        let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
-        let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
+        let (_start, mut slen, ssize) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
+        let (end, mut elen, _) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
+
+        let mut offset = offset;
+        let mut len = len;
+
+        if self.erase_by_sector {
+            // info!("erase_by_sector: {:#X}/{:#X} -> {:#X}/{:#X}", offset, len, offset - slen, ssize);
+
+            offset = offset - slen;
+            len = ssize;
+
+            slen = 0;
+            elen = self.sectors[end] - 1;
+        }
 
         if slen != 0 {
             bail!(ebounds("offset not at start of sector"));
@@ -267,6 +283,10 @@
     fn erased_val(&self) -> u8 {
         self.erased_val
     }
+
+    fn set_erase_by_sector(&mut self, enable: bool) {
+        self.erase_by_sector = enable;
+    }
 }
 
 /// It is possible to iterate over the sectors in the device, each element returning this.
diff --git a/sim/src/caps.rs b/sim/src/caps.rs
index 1d9a612..c626ee6 100644
--- a/sim/src/caps.rs
+++ b/sim/src/caps.rs
@@ -25,6 +25,7 @@
     DowngradePrevention  = (1 << 12),
     EncX25519            = (1 << 13),
     Bootstrap            = (1 << 14),
+    SwapUsingStatus      = (1 << 15),
 }
 
 impl Caps {
diff --git a/sim/src/image.rs b/sim/src/image.rs
index 1fdb1f0..6bd14c5 100644
--- a/sim/src/image.rs
+++ b/sim/src/image.rs
@@ -279,8 +279,10 @@
 
     /// Build the Flash and area descriptor for a given device.
     pub fn make_device(device: DeviceName, align: usize, erased_val: u8) -> (SimMultiFlash, AreaDesc, &'static [Caps]) {
+        info!(" +++ Make new device...");
         match device {
             DeviceName::Stm32f4 => {
+                info!("DeviceName::Stm32f4");
                 // STM style flash.  Large sectors, with a large scratch area.
                 let dev = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
                                         64 * 1024,
@@ -295,9 +297,10 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc, &[Caps::SwapUsingMove])
+                (flash, areadesc, &[Caps::SwapUsingMove, Caps::SwapUsingStatus])
             }
             DeviceName::K64f => {
+                info!("DeviceName::K64f");
                 // NXP style flash.  Small sectors, one small sector for scratch.
                 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
 
@@ -310,9 +313,10 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc, &[])
+                (flash, areadesc, &[Caps::SwapUsingStatus])
             }
             DeviceName::K64fBig => {
+                info!("DeviceName::K64fBig");
                 // Simulating an STM style flash on top of an NXP style flash.  Underlying flash device
                 // uses small sectors, but we tell the bootloader they are large.
                 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
@@ -326,9 +330,10 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc, &[Caps::SwapUsingMove])
+                (flash, areadesc, &[Caps::SwapUsingMove, Caps::SwapUsingStatus])
             }
             DeviceName::Nrf52840 => {
+                info!("DeviceName::Nrf52840");
                 // Simulating the flash on the nrf52840 with partitions set up so that the scratch size
                 // does not divide into the image size.
                 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
@@ -342,9 +347,10 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc, &[])
+                (flash, areadesc, &[Caps::SwapUsingStatus])
             }
             DeviceName::Nrf52840UnequalSlots => {
+                info!("DeviceName::Nrf52840UnequalSlots");
                 let dev = SimFlash::new(vec![4096; 128], align as usize, erased_val);
 
                 let dev_id = 0;
@@ -355,9 +361,10 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc, &[Caps::SwapUsingScratch, Caps::OverwriteUpgrade])
+                (flash, areadesc, &[Caps::SwapUsingScratch, Caps::OverwriteUpgrade, Caps::SwapUsingStatus])
             }
             DeviceName::Nrf52840SpiFlash => {
+                info!("DeviceName::Nrf52840SpiFlash");
                 // Simulate nrf52840 with external SPI flash. The external SPI flash
                 // has a larger sector size so for now store scratch on that flash.
                 let dev0 = SimFlash::new(vec![4096; 128], align as usize, erased_val);
@@ -374,9 +381,10 @@
                 let mut flash = SimMultiFlash::new();
                 flash.insert(0, dev0);
                 flash.insert(1, dev1);
-                (flash, areadesc, &[Caps::SwapUsingMove])
+                (flash, areadesc, &[Caps::SwapUsingMove, Caps::SwapUsingStatus])
             }
             DeviceName::K64fMulti => {
+                info!("DeviceName::K64fMulti");
                 // NXP style flash, but larger, to support multiple images.
                 let dev = SimFlash::new(vec![4096; 256], align as usize, erased_val);
 
@@ -391,7 +399,34 @@
 
                 let mut flash = SimMultiFlash::new();
                 flash.insert(dev_id, dev);
-                (flash, areadesc, &[])
+                (flash, areadesc, &[Caps::SwapUsingStatus])
+            }
+            DeviceName::PSoC6Multi => {
+                info!("DeviceName::PSoC6Multi");
+                // NXP style flash, but larger, to support multiple images.
+
+                let mut areadesc = AreaDesc::new();
+                let mut flash = SimMultiFlash::new();
+
+                // let dev0 = SimFlash::new(vec![4096; 256], align as usize, 0);
+                let mut dev0 = SimFlash::new(vec![512; 1024], align as usize, 0);
+                dev0.set_verify_writes(false);
+                dev0.set_erase_by_sector(true);
+
+                areadesc.add_flash_sectors(0, &dev0);
+                areadesc.add_image(0x020000, 0x020000, FlashId::Image0, 0);
+                areadesc.add_image(0x040000, 0x020000, FlashId::Image1, 0);
+                areadesc.add_image(0x060000, 0x008000, FlashId::ImageScratch, 0);
+                flash.insert(0, dev0);
+
+                // let dev1 = SimFlash::new(vec![4096; 256], align as usize, erased_val);
+                // areadesc.add_flash_sectors(1, &dev1);
+                // areadesc.add_image(0x080000, 0x020000, FlashId::Image2, 0);
+                // areadesc.add_image(0x0a0000, 0x020000, FlashId::Image3, 1);
+                // flash.insert(1, dev1);
+
+                // (flash, areadesc, &[])
+                (flash, areadesc, &[Caps::SwapUsingScratch, Caps::SwapUsingMove])
             }
         }
     }
@@ -461,7 +496,7 @@
     }
 
     fn is_swap_upgrade(&self) -> bool {
-        Caps::SwapUsingScratch.present() || Caps::SwapUsingMove.present()
+        Caps::SwapUsingScratch.present() || Caps::SwapUsingMove.present() || Caps::SwapUsingStatus.present()
     }
 
     pub fn run_basic_revert(&self) -> bool {
diff --git a/sim/src/lib.rs b/sim/src/lib.rs
index c5aa04f..4203c0e 100644
--- a/sim/src/lib.rs
+++ b/sim/src/lib.rs
@@ -64,7 +64,7 @@
 #[derive(Copy, Clone, Debug, Deserialize)]
 pub enum DeviceName {
     Stm32f4, K64f, K64fBig, K64fMulti, Nrf52840, Nrf52840SpiFlash,
-    Nrf52840UnequalSlots,
+    Nrf52840UnequalSlots, PSoC6Multi,
 }
 
 pub static ALL_DEVICES: &[DeviceName] = &[
@@ -75,6 +75,7 @@
     DeviceName::Nrf52840,
     DeviceName::Nrf52840SpiFlash,
     DeviceName::Nrf52840UnequalSlots,
+    DeviceName::PSoC6Multi,
 ];
 
 impl fmt::Display for DeviceName {
@@ -87,6 +88,7 @@
             DeviceName::Nrf52840 => "nrf52840",
             DeviceName::Nrf52840SpiFlash => "Nrf52840SpiFlash",
             DeviceName::Nrf52840UnequalSlots => "Nrf52840UnequalSlots",
+            DeviceName::PSoC6Multi => "psoc6multi",
         };
         f.write_str(name)
     }