sim: Move 'Flash' into a trait
Make 'Flash' a trait, and move the current functionality into a type
called 'SimFlash'. The code that runs the simulation only uses the
trait.
Signed-off-by: David Brown <david.brown@linaro.org>
diff --git a/sim/src/api.rs b/sim/src/api.rs
index 7b81627..2fa6b31 100644
--- a/sim/src/api.rs
+++ b/sim/src/api.rs
@@ -3,6 +3,7 @@
use flash::{Result, Flash};
use libc;
use log::LogLevel;
+use mem;
use std::slice;
// The current active flash device. The 'static is a lie, and we manage the lifetime ourselves.
@@ -10,7 +11,8 @@
// Set the flash device to be used by the simulation. The pointer is unsafely stashed away.
pub unsafe fn set_flash(dev: &mut Flash) {
- FLASH = Some(dev);
+ let dev: &'static mut Flash = mem::transmute(dev);
+ FLASH = Some(dev as *mut Flash);
}
pub unsafe fn clear_flash() {
diff --git a/sim/src/area.rs b/sim/src/area.rs
index 4b85912..eb42292 100644
--- a/sim/src/area.rs
+++ b/sim/src/area.rs
@@ -1,6 +1,6 @@
//! Describe flash areas.
-use flash::{Flash, Sector};
+use flash::{Flash, SimFlash, Sector};
use std::ptr;
/// Structure to build up the boot area table.
@@ -12,7 +12,7 @@
}
impl AreaDesc {
- pub fn new(flash: &Flash) -> AreaDesc {
+ pub fn new(flash: &SimFlash) -> AreaDesc {
AreaDesc {
areas: vec![],
whole: vec![],
diff --git a/sim/src/flash.rs b/sim/src/flash.rs
index 5e08f8d..98b6a27 100644
--- a/sim/src/flash.rs
+++ b/sim/src/flash.rs
@@ -23,6 +23,15 @@
}
}
+pub trait Flash {
+ fn erase(&mut self, offset: usize, len: usize) -> Result<()>;
+ fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()>;
+ fn read(&self, offset: usize, data: &mut [u8]) -> Result<()>;
+
+ fn sector_iter(&self) -> SectorIter;
+ fn device_size(&self) -> usize;
+}
+
fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
ErrorKind::OutOfBounds(message.as_ref().to_owned())
}
@@ -34,7 +43,7 @@
/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
/// mapings.
#[derive(Clone)]
-pub struct Flash {
+pub struct SimFlash {
data: Vec<u8>,
write_safe: Vec<bool>,
sectors: Vec<usize>,
@@ -42,15 +51,15 @@
align: usize,
}
-impl Flash {
+impl SimFlash {
/// Given a sector size map, construct a flash device for that.
- pub fn new(sectors: Vec<usize>, align: usize) -> Flash {
+ pub fn new(sectors: Vec<usize>, align: usize) -> SimFlash {
// Verify that the alignment is a positive power of two.
assert!(align > 0);
assert!(align & (align - 1) == 0);
let total = sectors.iter().sum();
- Flash {
+ SimFlash {
data: vec![0xffu8; total],
write_safe: vec![true; total],
sectors: sectors,
@@ -58,10 +67,39 @@
}
}
+ #[allow(dead_code)]
+ pub fn dump(&self) {
+ self.data.dump();
+ }
+
+ /// Dump this image to the given file.
+ #[allow(dead_code)]
+ pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
+ let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
+ fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
+ Ok(())
+ }
+
+ // 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)> {
+ let mut offset = offset;
+ for (sector, &size) in self.sectors.iter().enumerate() {
+ if offset < size {
+ return Some((sector, offset));
+ }
+ offset -= size;
+ }
+ return None;
+ }
+
+}
+
+impl Flash for SimFlash {
/// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
/// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
/// return an error.
- pub fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
+ 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"))?;
@@ -91,7 +129,7 @@
/// This emulates a flash device which starts out erased, with the
/// added restriction that repeated writes to the same location
/// are disallowed, even if they would be safe to do.
- pub fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
+ fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
if offset + payload.len() > self.data.len() {
panic!("Write outside of device");
}
@@ -119,7 +157,7 @@
}
/// Read is simple.
- pub fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
+ fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
if offset + data.len() > self.data.len() {
bail!(ebounds("Read outside of device"));
}
@@ -129,41 +167,17 @@
Ok(())
}
- // 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)> {
- let mut offset = offset;
- for (sector, &size) in self.sectors.iter().enumerate() {
- if offset < size {
- return Some((sector, offset));
- }
- offset -= size;
- }
- return None;
- }
-
/// An iterator over each sector in the device.
- pub fn sector_iter(&self) -> SectorIter {
+ fn sector_iter(&self) -> SectorIter {
SectorIter {
iter: self.sectors.iter().enumerate(),
base: 0,
}
}
- pub fn device_size(&self) -> usize {
+ fn device_size(&self) -> usize {
self.data.len()
}
-
- pub fn dump(&self) {
- self.data.dump();
- }
-
- /// Dump this image to the given file.
- pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
- let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
- fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
- Ok(())
- }
}
/// It is possible to iterate over the sectors in the device, each element returning this.
@@ -203,17 +217,17 @@
#[cfg(test)]
mod test {
- use super::{Flash, Error, ErrorKind, Result, Sector};
+ use super::{Flash, SimFlash, Error, ErrorKind, Result, Sector};
#[test]
fn test_flash() {
// NXP-style, uniform sectors.
- let mut f1 = Flash::new(vec![4096usize; 256]);
+ let mut f1 = SimFlash::new(vec![4096usize; 256], 1);
test_device(&mut f1);
// STM style, non-uniform sectors
- let mut f2 = Flash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
- 128 * 1024, 128 * 1024, 128 * 1024]);
+ 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);
}
diff --git a/sim/src/main.rs b/sim/src/main.rs
index 16400a3..af3a2d6 100644
--- a/sim/src/main.rs
+++ b/sim/src/main.rs
@@ -24,7 +24,7 @@
mod pdump;
mod caps;
-use flash::Flash;
+use flash::{Flash, SimFlash};
use area::{AreaDesc, FlashId};
use caps::Caps;
@@ -155,10 +155,10 @@
let (mut flash, areadesc) = match device {
DeviceName::Stm32f4 => {
// STM style flash. Large sectors, with a large scratch area.
- let flash = Flash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
- 64 * 1024,
- 128 * 1024, 128 * 1024, 128 * 1024],
- align as usize);
+ let flash = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 16 * 1024,
+ 64 * 1024,
+ 128 * 1024, 128 * 1024, 128 * 1024],
+ align as usize);
let mut areadesc = AreaDesc::new(&flash);
areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
areadesc.add_image(0x040000, 0x020000, FlashId::Image1);
@@ -167,7 +167,7 @@
}
DeviceName::K64f => {
// NXP style flash. Small sectors, one small sector for scratch.
- let flash = Flash::new(vec![4096; 128], align as usize);
+ let flash = SimFlash::new(vec![4096; 128], align as usize);
let mut areadesc = AreaDesc::new(&flash);
areadesc.add_image(0x020000, 0x020000, FlashId::Image0);
@@ -178,7 +178,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 = Flash::new(vec![4096; 128], align as usize);
+ let flash = SimFlash::new(vec![4096; 128], align as usize);
let mut areadesc = AreaDesc::new(&flash);
areadesc.add_simple_image(0x020000, 0x020000, FlashId::Image0);
@@ -189,7 +189,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 = Flash::new(vec![4096; 128], align as usize);
+ let flash = SimFlash::new(vec![4096; 128], align as usize);
let mut areadesc = AreaDesc::new(&flash);
areadesc.add_image(0x008000, 0x034000, FlashId::Image0);
@@ -270,7 +270,7 @@
///
/// Returns the number of flash operations which can later be used to
/// inject failures at chosen steps.
-fn run_basic_upgrade(flash: &Flash, areadesc: &AreaDesc, images: &Images)
+fn run_basic_upgrade(flash: &SimFlash, areadesc: &AreaDesc, images: &Images)
-> Result<i32, ()> {
let (fl, total_count) = try_upgrade(&flash, &areadesc, &images, None);
info!("Total flash operation count={}", total_count);
@@ -283,7 +283,7 @@
}
}
-fn run_basic_revert(flash: &Flash, areadesc: &AreaDesc, images: &Images) -> bool {
+fn run_basic_revert(flash: &SimFlash, areadesc: &AreaDesc, images: &Images) -> bool {
let mut fails = 0;
if Caps::SwapUpgrade.present() {
@@ -300,7 +300,7 @@
fails > 0
}
-fn run_perm_with_fails(flash: &Flash, areadesc: &AreaDesc, images: &Images,
+fn run_perm_with_fails(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
total_flash_ops: i32) -> bool {
let mut fails = 0;
@@ -340,7 +340,7 @@
fails > 0
}
-fn run_perm_with_random_fails(flash: &Flash, areadesc: &AreaDesc,
+fn run_perm_with_random_fails(flash: &SimFlash, areadesc: &AreaDesc,
images: &Images, total_flash_ops: i32,
total_fails: usize) -> bool {
let mut fails = 0;
@@ -374,7 +374,7 @@
fails > 0
}
-fn run_revert_with_fails(flash: &Flash, areadesc: &AreaDesc, images: &Images,
+fn run_revert_with_fails(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
total_count: i32) -> bool {
let mut fails = 0;
@@ -390,7 +390,7 @@
fails > 0
}
-fn run_norevert(flash: &Flash, areadesc: &AreaDesc, images: &Images) -> bool {
+fn run_norevert(flash: &SimFlash, areadesc: &AreaDesc, images: &Images) -> bool {
let mut fl = flash.clone();
let mut fails = 0;
@@ -441,8 +441,8 @@
/// Test a boot, optionally stopping after 'n' flash options. Returns a count
/// of the number of flash operations done total.
-fn try_upgrade(flash: &Flash, areadesc: &AreaDesc, images: &Images,
- stop: Option<i32>) -> (Flash, i32) {
+fn try_upgrade(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
+ stop: Option<i32>) -> (SimFlash, i32) {
// Clone the flash to have a new copy.
let mut fl = flash.clone();
@@ -468,7 +468,7 @@
(fl, count - c::get_flash_counter())
}
-fn try_revert(flash: &Flash, areadesc: &AreaDesc, count: usize) -> Flash {
+fn try_revert(flash: &SimFlash, areadesc: &AreaDesc, count: usize) -> SimFlash {
let mut fl = flash.clone();
c::set_flash_counter(0);
@@ -480,7 +480,7 @@
fl
}
-fn try_revert_with_fail_at(flash: &Flash, areadesc: &AreaDesc, images: &Images,
+fn try_revert_with_fail_at(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
stop: i32) -> bool {
let mut fl = flash.clone();
let mut x: i32;
@@ -554,8 +554,8 @@
fails > 0
}
-fn try_random_fails(flash: &Flash, areadesc: &AreaDesc, images: &Images,
- total_ops: i32, count: usize) -> (Flash, Vec<i32>) {
+fn try_random_fails(flash: &SimFlash, areadesc: &AreaDesc, images: &Images,
+ total_ops: i32, count: usize) -> (SimFlash, Vec<i32>) {
let mut fl = flash.clone();
mark_permanent_upgrade(&mut fl, &images.slot1);