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/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 ©[16..] != v {
+ if v == 1 && ©[16..] != MAGIC.unwrap() {
warn!("\"magic\" mismatch at {:#x}", offset);
true
+ } else if v == 3 {
+ let expected = [erased_val; 16];
+ if ©[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();
}