Add sim support for flash erased at 0

This extends the simulator to be able to test the bootloader in devices
which use flash technologies that erase flash at 0 instead of 0xff.
Two MCU devices that have this "property" are the STM32L0x and STM32L1x
lines from ST.

Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/sim/mcuboot-sys/csupport/flash_map.h b/sim/mcuboot-sys/csupport/flash_map.h
index 506f266..7622dd0 100644
--- a/sim/mcuboot-sys/csupport/flash_map.h
+++ b/sim/mcuboot-sys/csupport/flash_map.h
@@ -126,6 +126,11 @@
 uint8_t flash_area_align(const struct flash_area *);
 
 /*
+ * What is value is read from erased flash bytes.
+ */
+uint8_t flash_area_erased_val(const struct flash_area *);
+
+/*
  * Given flash area ID, return info about sectors within the area.
  */
 int flash_area_get_sectors(int fa_id, uint32_t *count,
diff --git a/sim/mcuboot-sys/csupport/run.c b/sim/mcuboot-sys/csupport/run.c
index ece8555..8238b39 100644
--- a/sim/mcuboot-sys/csupport/run.c
+++ b/sim/mcuboot-sys/csupport/run.c
@@ -52,6 +52,13 @@
     return sim_flash_align;
 }
 
+uint8_t sim_flash_erased_val = 0xff;
+uint8_t flash_area_erased_val(const struct flash_area *area)
+{
+    (void)area;
+    return sim_flash_erased_val;
+}
+
 struct area {
     struct flash_area whole;
     struct flash_area *areas;
diff --git a/sim/mcuboot-sys/src/c.rs b/sim/mcuboot-sys/src/c.rs
index 3400bc0..3b944c6 100644
--- a/sim/mcuboot-sys/src/c.rs
+++ b/sim/mcuboot-sys/src/c.rs
@@ -22,6 +22,7 @@
         raw::c_catch_asserts = if catch_asserts { 1 } else { 0 };
         raw::c_asserts = 0u8;
         raw::sim_flash_align = align;
+        raw::sim_flash_erased_val = flash.erased_val();
         raw::flash_counter = match counter {
             None => 0,
             Some(ref c) => **c as libc::c_int
@@ -73,6 +74,7 @@
         pub static mut c_catch_asserts: u8;
 
         pub static mut sim_flash_align: u8;
+        pub static mut sim_flash_erased_val: u8;
         pub fn boot_slots_trailer_sz(min_write_sz: u8) -> u32;
 
         pub static BOOT_MAGIC_SZ: u32;
diff --git a/sim/simflash/src/lib.rs b/sim/simflash/src/lib.rs
index 6219a85..9523a4f 100644
--- a/sim/simflash/src/lib.rs
+++ b/sim/simflash/src/lib.rs
@@ -45,6 +45,8 @@
 
     fn sector_iter(&self) -> SectorIter;
     fn device_size(&self) -> usize;
+
+    fn erased_val(&self) -> u8;
 }
 
 fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
@@ -72,23 +74,25 @@
     // Alignment required for writes.
     align: usize,
     verify_writes: bool,
+    erased_val: u8,
 }
 
 impl SimFlash {
     /// Given a sector size map, construct a flash device for that.
-    pub fn new(sectors: Vec<usize>, align: usize) -> SimFlash {
+    pub fn new(sectors: Vec<usize>, align: usize, erased_val: u8) -> SimFlash {
         // Verify that the alignment is a positive power of two.
         assert!(align > 0);
         assert!(align & (align - 1) == 0);
 
         let total = sectors.iter().sum();
         SimFlash {
-            data: vec![0xffu8; total],
+            data: vec![erased_val; total],
             write_safe: vec![true; total],
             sectors: sectors,
             bad_region: Vec::new(),
             align: align,
             verify_writes: true,
+            erased_val: erased_val,
         }
     }
 
@@ -136,7 +140,7 @@
         }
 
         for x in &mut self.data[offset .. offset + len] {
-            *x = 0xff;
+            *x = self.erased_val;
         }
 
         for x in &mut self.write_safe[offset .. offset + len] {
@@ -234,6 +238,10 @@
     fn device_size(&self) -> usize {
         self.data.len()
     }
+
+    fn erased_val(&self) -> u8 {
+        self.erased_val
+    }
 }
 
 /// It is possible to iterate over the sectors in the device, each element returning this.
@@ -277,17 +285,19 @@
 
     #[test]
     fn test_flash() {
-        // NXP-style, uniform sectors.
-        let mut f1 = SimFlash::new(vec![4096usize; 256], 1);
-        test_device(&mut f1);
+        for &erased_val in &[0, 0xff] {
+            // NXP-style, uniform sectors.
+            let mut f1 = SimFlash::new(vec![4096usize; 256], 1, erased_val);
+            test_device(&mut f1, erased_val);
 
-        // STM style, non-uniform sectors
-        let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
-                                128 * 1024, 128 * 1024, 128 * 1024], 1);
-        test_device(&mut f2);
+            // STM style, non-uniform sectors.
+            let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
+                                    128 * 1024, 128 * 1024, 128 * 1024], 1, erased_val);
+            test_device(&mut f2, erased_val);
+        }
     }
 
-    fn test_device(flash: &mut Flash) {
+    fn test_device(flash: &mut Flash, erased_val: u8) {
         let sectors: Vec<Sector> = flash.sector_iter().collect();
 
         flash.erase(0, sectors[0].size).unwrap();
@@ -296,14 +306,14 @@
         assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
 
         // Verify that write and erase do something.
-        flash.write(0, &[0]).unwrap();
-        let mut buf = [0; 4];
+        flash.write(0, &[0x55]).unwrap();
+        let mut buf = [0xAA; 4];
         flash.read(0, &mut buf).unwrap();
-        assert_eq!(buf, [0, 0xff, 0xff, 0xff]);
+        assert_eq!(buf, [0x55, erased_val, erased_val, erased_val]);
 
         flash.erase(0, sectors[0].size).unwrap();
         flash.read(0, &mut buf).unwrap();
-        assert_eq!(buf, [0xff; 4]);
+        assert_eq!(buf, [erased_val; 4]);
 
         // Program the first and last byte of each sector, verify that has been done, and then
         // erase to verify the erase boundaries.
@@ -321,7 +331,7 @@
             flash.read(sector.base, &mut buf).unwrap();
             assert_eq!(buf.first(), Some(&byte));
             assert_eq!(buf.last(), Some(&byte));
-            assert!(buf[1..buf.len()-1].iter().all(|&x| x == 0xff));
+            assert!(buf[1..buf.len()-1].iter().all(|&x| x == erased_val));
         }
     }
 
diff --git a/sim/src/lib.rs b/sim/src/lib.rs
index 2b240db..1e8ba8a 100644
--- a/sim/src/lib.rs
+++ b/sim/src/lib.rs
@@ -133,13 +133,15 @@
             Some(dev) => dev,
         };
 
-        status.run_single(device, align);
+        status.run_single(device, align, 0xff);
     }
 
     if args.cmd_runall {
         for &dev in ALL_DEVICES {
             for &align in &[1, 2, 4, 8] {
-                status.run_single(dev, align);
+                for &erased_val in &[0, 0xff] {
+                    status.run_single(dev, align, erased_val);
+                }
             }
         }
     }
@@ -159,11 +161,12 @@
     areadesc: AreaDesc,
     slots: [SlotInfo; 2],
     align: u8,
+    erased_val: u8,
 }
 
 impl Run {
-    pub fn new(device: DeviceName, align: u8) -> Run {
-        let (flash, areadesc) = make_device(device, align);
+    pub fn new(device: DeviceName, align: u8, erased_val: u8) -> Run {
+        let (flash, areadesc) = make_device(device, align, erased_val);
 
         let (slot0_base, slot0_len) = areadesc.find(FlashId::Image0);
         let (slot1_base, slot1_len) = areadesc.find(FlashId::Image1);
@@ -193,6 +196,7 @@
             areadesc: areadesc,
             slots: [slot0, slot1],
             align: align,
+            erased_val: erased_val,
         }
     }
 
@@ -201,8 +205,10 @@
     {
         for &dev in ALL_DEVICES {
             for &align in &[1, 2, 4, 8] {
-                let mut run = Run::new(dev, align);
-                f(&mut run);
+                for &erased_val in &[0, 0xff] {
+                    let mut run = Run::new(dev, align, erased_val);
+                    f(&mut run);
+                }
             }
         }
     }
@@ -221,6 +227,7 @@
             upgrade: upgrade,
             total_count: None,
             align: self.align,
+            erased_val: self.erased_val,
         }
     }
 
@@ -254,6 +261,7 @@
             upgrade: upgrade,
             total_count: None,
             align: self.align,
+            erased_val: self.erased_val,
         }
     }
 
@@ -272,10 +280,10 @@
         }
     }
 
-    pub fn run_single(&mut self, device: DeviceName, align: u8) {
+    pub fn run_single(&mut self, device: DeviceName, align: u8, erased_val: u8) {
         warn!("Running on device {} with alignment {}", device, align);
 
-        let run = Run::new(device, align);
+        let run = Run::new(device, align, erased_val);
 
         let mut failed = false;
 
@@ -314,14 +322,14 @@
 }
 
 /// Build the Flash and area descriptor for a given device.
-pub fn make_device(device: DeviceName, align: u8) -> (SimFlash, AreaDesc) {
+pub fn make_device(device: DeviceName, align: u8, erased_val: u8) -> (SimFlash, AreaDesc) {
     match device {
         DeviceName::Stm32f4 => {
             // STM style flash.  Large sectors, with a large scratch area.
             let flash = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
                                       64 * 1024,
                                       128 * 1024, 128 * 1024, 128 * 1024],
-                                      align as usize);
+                                      align as usize, erased_val);
             let mut areadesc = AreaDesc::new(&flash);
             areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
             areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
@@ -330,7 +338,7 @@
         }
         DeviceName::K64f => {
             // NXP style flash.  Small sectors, one small sector for scratch.
-            let flash = SimFlash::new(vec![4096; 128], align as usize);
+            let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
 
             let mut areadesc = AreaDesc::new(&flash);
             areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
@@ -341,7 +349,7 @@
         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 flash = SimFlash::new(vec![4096; 128], align as usize);
+            let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
 
             let mut areadesc = AreaDesc::new(&flash);
             areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0);
@@ -352,7 +360,7 @@
         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 flash = SimFlash::new(vec![4096; 128], align as usize);
+            let flash = SimFlash::new(vec![4096; 128], align as usize, erased_val);
 
             let mut areadesc = AreaDesc::new(&flash);
             areadesc.add_image(0x008000, 0x034000, FlashId::Image0);
@@ -418,14 +426,14 @@
                 fails += 1;
             }
 
-            if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
-                               COPY_DONE) {
+            if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                               BOOT_FLAG_SET, BOOT_FLAG_SET) {
                 warn!("Mismatched trailer for Slot 0");
                 fails += 1;
             }
 
-            if !verify_trailer(&fl, self.slot1.trailer_off, MAGIC_UNSET, UNSET,
-                               UNSET) {
+            if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
+                               BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
                 warn!("Mismatched trailer for Slot 1");
                 fails += 1;
             }
@@ -469,13 +477,13 @@
                    if slot1_ok { "ok" } else { "fail" });
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
-                           COPY_DONE) {
+        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                           BOOT_FLAG_SET, BOOT_FLAG_SET) {
             error!("Mismatched trailer for Slot 0");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot1.trailer_off, MAGIC_UNSET, UNSET,
-                           UNSET) {
+        if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
+                           BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             error!("Mismatched trailer for Slot 1");
             fails += 1;
         }
@@ -535,22 +543,22 @@
             warn!("Slot 0 image verification FAIL");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, UNSET,
-                           COPY_DONE) {
+        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                           BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot1.trailer_off, MAGIC_UNSET, UNSET,
-                           UNSET) {
+        if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
+                           BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 1");
             fails += 1;
         }
 
         // Marks image in slot0 as permanent, no revert should happen...
-        mark_permanent_upgrade(&mut fl, &self.slot0, self.align);
+        mark_permanent_upgrade(&mut fl, &self.slot0, self.align, self.erased_val);
 
-        if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
-                           COPY_DONE) {
+        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                           BOOT_FLAG_SET, BOOT_FLAG_SET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
@@ -561,8 +569,8 @@
             fails += 1;
         }
 
-        if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
-                           COPY_DONE) {
+        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                           BOOT_FLAG_SET, BOOT_FLAG_SET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
@@ -589,7 +597,8 @@
         mark_upgrade(&mut fl, &self.slot0);
 
         // This simulates writing an image created by imgtool to Slot 0
-        if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, UNSET, UNSET) {
+        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                           BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
@@ -606,13 +615,13 @@
             warn!("Failed image verification");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, UNSET,
-                           UNSET) {
+        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                           BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot1.trailer_off, MAGIC_UNSET, UNSET,
-                           UNSET) {
+        if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
+                           BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 1");
             fails += 1;
         }
@@ -633,11 +642,11 @@
         info!("Try upgrade image with bad signature");
 
         mark_upgrade(&mut fl, &self.slot0);
-        mark_permanent_upgrade(&mut fl, &self.slot0, self.align);
+        mark_permanent_upgrade(&mut fl, &self.slot0, self.align, self.erased_val);
         mark_upgrade(&mut fl, &self.slot1);
 
-        if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
-                           UNSET) {
+        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                           BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
@@ -654,8 +663,8 @@
             warn!("Failed image verification");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
-                           UNSET) {
+        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                           BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
@@ -691,7 +700,7 @@
 
         info!("Try swap with status fails");
 
-        mark_permanent_upgrade(&mut fl, &self.slot1, self.align);
+        mark_permanent_upgrade(&mut fl, &self.slot1, self.align, self.erased_val);
 
         let status_off = self.slot1.base_off - self.trailer_sz();
 
@@ -711,8 +720,8 @@
             fails += 1;
         }
 
-        if !verify_trailer(&fl, self.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
-                           COPY_DONE) {
+        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                           BOOT_FLAG_SET, BOOT_FLAG_SET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
@@ -749,7 +758,7 @@
 
         info!("Try interrupted swap with status fails");
 
-        mark_permanent_upgrade(&mut fl, &self.slot1, self.align);
+        mark_permanent_upgrade(&mut fl, &self.slot1, self.align, self.erased_val);
 
         let status_off = self.slot1.base_off - self.trailer_sz();
 
@@ -796,7 +805,7 @@
 
         info!("Try interrupted swap with status fails");
 
-        mark_permanent_upgrade(&mut fl, &self.slot1, self.align);
+        mark_permanent_upgrade(&mut fl, &self.slot1, self.align, self.erased_val);
 
         let status_off = self.slot1.base_off - self.trailer_sz();
 
@@ -826,7 +835,7 @@
     // Clone the flash to have a new copy.
     let mut fl = flash.clone();
 
-    mark_permanent_upgrade(&mut fl, &images.slot1, images.align);
+    mark_permanent_upgrade(&mut fl, &images.slot1, images.align, images.erased_val);
 
     let mut counter = stop.unwrap_or(0);
 
@@ -874,7 +883,7 @@
         fails += 1;
     }
 
-    if !verify_trailer(&fl, images.slot0.trailer_off, None, None, UNSET) {
+    if !verify_trailer(&fl, images.slot0.trailer_off, None, None, BOOT_FLAG_UNSET) {
         warn!("copy_done should be unset");
         fails += 1;
     }
@@ -893,13 +902,13 @@
         warn!("Image in slot 1 before revert is invalid at stop={}", stop);
         fails += 1;
     }
-    if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, UNSET,
-                       COPY_DONE) {
+    if !verify_trailer(&fl, images.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                       BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
         warn!("Mismatched trailer for Slot 0 before revert");
         fails += 1;
     }
-    if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
-                       UNSET) {
+    if !verify_trailer(&fl, images.slot1.trailer_off, BOOT_MAGIC_UNSET,
+                       BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
         warn!("Mismatched trailer for Slot 1 before revert");
         fails += 1;
     }
@@ -919,13 +928,13 @@
         warn!("Image in slot 1 after revert is invalid at stop={}", stop);
         fails += 1;
     }
-    if !verify_trailer(&fl, images.slot0.trailer_off, MAGIC_VALID, IMAGE_OK,
-                       COPY_DONE) {
+    if !verify_trailer(&fl, images.slot0.trailer_off, BOOT_MAGIC_GOOD,
+                       BOOT_FLAG_SET, BOOT_FLAG_SET) {
         warn!("Mismatched trailer for Slot 1 after revert");
         fails += 1;
     }
-    if !verify_trailer(&fl, images.slot1.trailer_off, MAGIC_UNSET, UNSET,
-                       UNSET) {
+    if !verify_trailer(&fl, images.slot1.trailer_off, BOOT_MAGIC_UNSET,
+                       BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
         warn!("Mismatched trailer for Slot 1 after revert");
         fails += 1;
     }
@@ -937,7 +946,7 @@
                     total_ops: i32,  count: usize) -> (SimFlash, Vec<i32>) {
     let mut fl = flash.clone();
 
-    mark_permanent_upgrade(&mut fl, &images.slot1, images.align);
+    mark_permanent_upgrade(&mut fl, &images.slot1, images.align, images.erased_val);
 
     let mut rng = rand::thread_rng();
     let mut resets = vec![0i32; count];
@@ -1078,25 +1087,34 @@
 #[allow(unused_variables)]
 // overwrite-only doesn't employ trailer management
 fn verify_trailer(flash: &Flash, offset: usize,
-                  magic: Option<&[u8]>, image_ok: Option<u8>,
+                  magic: Option<u8>, image_ok: Option<u8>,
                   copy_done: Option<u8>) -> bool {
     true
 }
 
 #[cfg(not(feature = "overwrite-only"))]
 fn verify_trailer(flash: &Flash, offset: usize,
-                  magic: Option<&[u8]>, image_ok: Option<u8>,
+                  magic: Option<u8>, image_ok: Option<u8>,
                   copy_done: Option<u8>) -> bool {
     let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
     let mut failed = false;
+    let erased_val = flash.erased_val();
 
     flash.read(offset, &mut copy).unwrap();
 
     failed |= match magic {
         Some(v) => {
-            if &copy[16..] != v  {
+            if v == 1 && &copy[16..] != MAGIC.unwrap() {
                 warn!("\"magic\" mismatch at {:#x}", offset);
                 true
+            } else if v == 3 {
+                let expected = [erased_val; 16];
+                if &copy[16..] != expected {
+                    warn!("\"magic\" mismatch at {:#x}", offset);
+                    true
+                } else {
+                    false
+                }
             } else {
                 false
             }
@@ -1106,8 +1124,8 @@
 
     failed |= match image_ok {
         Some(v) => {
-            if copy[8] != v {
-                warn!("\"image_ok\" mismatch at {:#x}", offset);
+            if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
+                warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
                 true
             } else {
                 false
@@ -1118,8 +1136,8 @@
 
     failed |= match copy_done {
         Some(v) => {
-            if copy[0] != v {
-                warn!("\"copy_done\" mismatch at {:#x}", offset);
+            if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
+                warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
                 true
             } else {
                 false
@@ -1171,28 +1189,32 @@
     upgrade: Vec<u8>,
     total_count: Option<i32>,
     align: u8,
+    erased_val: u8,
 }
 
-const MAGIC_VALID: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
-                                          0x60, 0xd2, 0xef, 0x7f,
-                                          0x35, 0x52, 0x50, 0x0f,
-                                          0x2c, 0xb6, 0x79, 0x80]);
-const MAGIC_UNSET: Option<&[u8]> = Some(&[0xff; 16]);
+const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
+                                    0x60, 0xd2, 0xef, 0x7f,
+                                    0x35, 0x52, 0x50, 0x0f,
+                                    0x2c, 0xb6, 0x79, 0x80]);
 
-const COPY_DONE: Option<u8> = Some(1);
-const IMAGE_OK: Option<u8> = Some(1);
-const UNSET: Option<u8> = Some(0xff);
+// Replicates defines found in bootutil.h
+const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
+const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
+
+const BOOT_FLAG_SET: Option<u8> = Some(1);
+const BOOT_FLAG_UNSET: Option<u8> = Some(3);
 
 /// Write out the magic so that the loader tries doing an upgrade.
 fn mark_upgrade(flash: &mut Flash, slot: &SlotInfo) {
     let offset = slot.trailer_off + c::boot_max_align() * 2;
-    flash.write(offset, MAGIC_VALID.unwrap()).unwrap();
+    flash.write(offset, MAGIC.unwrap()).unwrap();
 }
 
 /// Writes the image_ok flag which, guess what, tells the bootloader
 /// the this image is ok (not a test, and no revert is to be performed).
-fn mark_permanent_upgrade(flash: &mut Flash, slot: &SlotInfo, align: u8) {
-    let ok = [1u8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
+fn mark_permanent_upgrade(flash: &mut Flash, slot: &SlotInfo, align: u8, erased_val: u8) {
+    let mut ok = [erased_val; 8];
+    ok[0] = 1u8;
     let off = slot.trailer_off + c::boot_max_align();
     flash.write(off, &ok[..align as usize]).unwrap();
 }