blob: 6219a85053cf5de9dd9f1e17e5b84771c6197389 [file] [log] [blame]
David Brownde7729e2017-01-09 10:41:35 -07001//! A flash simulator
2//!
3//! This module is capable of simulating the type of NOR flash commonly used in microcontrollers.
4//! These generally can be written as individual bytes, but must be erased in larger units.
5
Fabio Utzigf5c895e2017-11-23 19:57:17 -02006#[macro_use] extern crate log;
David Brown2cbc4702017-07-06 14:18:58 -06007#[macro_use] extern crate error_chain;
Fabio Utzigf5c895e2017-11-23 19:57:17 -02008extern crate rand;
David Brown2cbc4702017-07-06 14:18:58 -06009mod pdump;
10
Fabio Utzigf5c895e2017-11-23 19:57:17 -020011use rand::distributions::{IndependentSample, Range};
David Brown163ab232017-01-23 15:48:35 -070012use std::fs::File;
13use std::io::Write;
David Brownde7729e2017-01-09 10:41:35 -070014use std::iter::Enumerate;
David Brown163ab232017-01-23 15:48:35 -070015use std::path::Path;
David Brownde7729e2017-01-09 10:41:35 -070016use std::slice;
17use pdump::HexDump;
18
19error_chain! {
20 errors {
21 OutOfBounds(t: String) {
22 description("Offset is out of bounds")
23 display("Offset out of bounds: {}", t)
24 }
25 Write(t: String) {
26 description("Invalid write")
27 display("Invalid write: {}", t)
28 }
Fabio Utzigf5c895e2017-11-23 19:57:17 -020029 SimulatedFail(t: String) {
30 description("Write failed by chance")
31 display("Failed write: {}", t)
32 }
David Brownde7729e2017-01-09 10:41:35 -070033 }
34}
35
David Brown7ddec0b2017-07-06 10:47:35 -060036pub trait Flash {
37 fn erase(&mut self, offset: usize, len: usize) -> Result<()>;
38 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()>;
39 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()>;
40
Fabio Utzigf5c895e2017-11-23 19:57:17 -020041 fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()>;
42 fn reset_bad_regions(&mut self);
43
Fabio Utzigfa137fc2017-11-23 20:01:02 -020044 fn set_verify_writes(&mut self, enable: bool);
45
David Brown7ddec0b2017-07-06 10:47:35 -060046 fn sector_iter(&self) -> SectorIter;
47 fn device_size(&self) -> usize;
48}
49
David Brownde7729e2017-01-09 10:41:35 -070050fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
51 ErrorKind::OutOfBounds(message.as_ref().to_owned())
52}
53
Fabio Utzig65935d72017-07-17 15:34:36 -030054#[allow(dead_code)]
David Brownde7729e2017-01-09 10:41:35 -070055fn ewrite<T: AsRef<str>>(message: T) -> ErrorKind {
56 ErrorKind::Write(message.as_ref().to_owned())
57}
58
Fabio Utzigf5c895e2017-11-23 19:57:17 -020059#[allow(dead_code)]
60fn esimulatedwrite<T: AsRef<str>>(message: T) -> ErrorKind {
61 ErrorKind::SimulatedFail(message.as_ref().to_owned())
62}
63
David Brownde7729e2017-01-09 10:41:35 -070064/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
65/// mapings.
66#[derive(Clone)]
David Brown7ddec0b2017-07-06 10:47:35 -060067pub struct SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070068 data: Vec<u8>,
Marti Bolivar51d36dd2017-05-17 17:39:46 -040069 write_safe: Vec<bool>,
David Brownde7729e2017-01-09 10:41:35 -070070 sectors: Vec<usize>,
Fabio Utzigf5c895e2017-11-23 19:57:17 -020071 bad_region: Vec<(usize, usize, f32)>,
David Brown562a7a02017-01-23 11:19:03 -070072 // Alignment required for writes.
73 align: usize,
Fabio Utzigfa137fc2017-11-23 20:01:02 -020074 verify_writes: bool,
David Brownde7729e2017-01-09 10:41:35 -070075}
76
David Brown7ddec0b2017-07-06 10:47:35 -060077impl SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070078 /// Given a sector size map, construct a flash device for that.
David Brown7ddec0b2017-07-06 10:47:35 -060079 pub fn new(sectors: Vec<usize>, align: usize) -> SimFlash {
David Brown562a7a02017-01-23 11:19:03 -070080 // Verify that the alignment is a positive power of two.
81 assert!(align > 0);
82 assert!(align & (align - 1) == 0);
83
David Brownde7729e2017-01-09 10:41:35 -070084 let total = sectors.iter().sum();
David Brown7ddec0b2017-07-06 10:47:35 -060085 SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070086 data: vec![0xffu8; total],
Marti Bolivar51d36dd2017-05-17 17:39:46 -040087 write_safe: vec![true; total],
David Brownde7729e2017-01-09 10:41:35 -070088 sectors: sectors,
Fabio Utzigf5c895e2017-11-23 19:57:17 -020089 bad_region: Vec::new(),
David Brown562a7a02017-01-23 11:19:03 -070090 align: align,
Fabio Utzigfa137fc2017-11-23 20:01:02 -020091 verify_writes: true,
David Brownde7729e2017-01-09 10:41:35 -070092 }
93 }
94
David Brown7ddec0b2017-07-06 10:47:35 -060095 #[allow(dead_code)]
96 pub fn dump(&self) {
97 self.data.dump();
98 }
99
100 /// Dump this image to the given file.
101 #[allow(dead_code)]
102 pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
103 let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
104 fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
105 Ok(())
106 }
107
108 // Scan the sector map, and return the base and offset within a sector for this given byte.
109 // Returns None if the value is outside of the device.
110 fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
111 let mut offset = offset;
112 for (sector, &size) in self.sectors.iter().enumerate() {
113 if offset < size {
114 return Some((sector, offset));
115 }
116 offset -= size;
117 }
118 return None;
119 }
120
121}
122
123impl Flash for SimFlash {
David Brownde7729e2017-01-09 10:41:35 -0700124 /// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
125 /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
126 /// return an error.
David Brown7ddec0b2017-07-06 10:47:35 -0600127 fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700128 let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
129 let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
130
131 if slen != 0 {
132 bail!(ebounds("offset not at start of sector"));
133 }
134 if elen != self.sectors[end] - 1 {
135 bail!(ebounds("end not at start of sector"));
136 }
137
138 for x in &mut self.data[offset .. offset + len] {
139 *x = 0xff;
140 }
141
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400142 for x in &mut self.write_safe[offset .. offset + len] {
143 *x = true;
144 }
145
David Brownde7729e2017-01-09 10:41:35 -0700146 Ok(())
147 }
148
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400149 /// We restrict to only allowing writes of values that are:
150 ///
151 /// 1. being written to for the first time
152 /// 2. being written to after being erased
153 ///
154 /// This emulates a flash device which starts out erased, with the
155 /// added restriction that repeated writes to the same location
156 /// are disallowed, even if they would be safe to do.
David Brown7ddec0b2017-07-06 10:47:35 -0600157 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200158 for &(off, len, rate) in &self.bad_region {
159 if offset >= off && (offset + payload.len()) <= (off + len) {
160 let mut rng = rand::thread_rng();
161 let between = Range::new(0., 1.);
162 if between.ind_sample(&mut rng) < rate {
163 bail!(esimulatedwrite(
164 format!("Ignoring write to {:#x}-{:#x}", off, off + len)));
165 }
166 }
167 }
168
David Brownde7729e2017-01-09 10:41:35 -0700169 if offset + payload.len() > self.data.len() {
David Brownf253fa82017-01-23 15:43:47 -0700170 panic!("Write outside of device");
David Brownde7729e2017-01-09 10:41:35 -0700171 }
172
David Brown562a7a02017-01-23 11:19:03 -0700173 // Verify the alignment (which must be a power of two).
174 if offset & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700175 panic!("Misaligned write address");
David Brown562a7a02017-01-23 11:19:03 -0700176 }
177
178 if payload.len() & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700179 panic!("Write length not multiple of alignment");
David Brown562a7a02017-01-23 11:19:03 -0700180 }
181
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400182 for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200183 if self.verify_writes && !(*x) {
Fabio Utzig65935d72017-07-17 15:34:36 -0300184 panic!("Write to unerased location at 0x{:x}", offset + i);
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300185 }
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400186 *x = false;
David Brownde7729e2017-01-09 10:41:35 -0700187 }
188
David Brown59ae5222017-12-06 11:45:15 -0700189 let sub = &mut self.data[offset .. offset + payload.len()];
David Brownde7729e2017-01-09 10:41:35 -0700190 sub.copy_from_slice(payload);
191 Ok(())
192 }
193
194 /// Read is simple.
David Brown7ddec0b2017-07-06 10:47:35 -0600195 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700196 if offset + data.len() > self.data.len() {
197 bail!(ebounds("Read outside of device"));
198 }
199
200 let sub = &self.data[offset .. offset + data.len()];
201 data.copy_from_slice(sub);
202 Ok(())
203 }
204
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200205 /// Adds a new flash bad region. Writes to this area fail with a chance
206 /// given by `rate`.
207 fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()> {
208 if rate < 0.0 || rate > 1.0 {
209 bail!(ebounds("Invalid rate"));
210 }
211
212 info!("Adding new bad region {:#x}-{:#x}", offset, offset + len);
213 self.bad_region.push((offset, len, rate));
214
215 Ok(())
216 }
217
218 fn reset_bad_regions(&mut self) {
219 self.bad_region.clear();
220 }
221
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200222 fn set_verify_writes(&mut self, enable: bool) {
223 self.verify_writes = enable;
224 }
225
David Brownde7729e2017-01-09 10:41:35 -0700226 /// An iterator over each sector in the device.
David Brown7ddec0b2017-07-06 10:47:35 -0600227 fn sector_iter(&self) -> SectorIter {
David Brownde7729e2017-01-09 10:41:35 -0700228 SectorIter {
229 iter: self.sectors.iter().enumerate(),
230 base: 0,
231 }
232 }
233
David Brown7ddec0b2017-07-06 10:47:35 -0600234 fn device_size(&self) -> usize {
David Brownde7729e2017-01-09 10:41:35 -0700235 self.data.len()
236 }
David Brownde7729e2017-01-09 10:41:35 -0700237}
238
239/// It is possible to iterate over the sectors in the device, each element returning this.
David Brown3f687dc2017-11-06 13:41:18 -0700240#[derive(Debug, Clone)]
David Brownde7729e2017-01-09 10:41:35 -0700241pub struct Sector {
242 /// Which sector is this, starting from 0.
243 pub num: usize,
244 /// The offset, in bytes, of the start of this sector.
245 pub base: usize,
246 /// The length, in bytes, of this sector.
247 pub size: usize,
248}
249
250pub struct SectorIter<'a> {
251 iter: Enumerate<slice::Iter<'a, usize>>,
252 base: usize,
253}
254
255impl<'a> Iterator for SectorIter<'a> {
256 type Item = Sector;
257
258 fn next(&mut self) -> Option<Sector> {
259 match self.iter.next() {
260 None => None,
261 Some((num, &size)) => {
262 let base = self.base;
263 self.base += size;
264 Some(Sector {
265 num: num,
266 base: base,
267 size: size,
268 })
269 }
270 }
271 }
272}
273
274#[cfg(test)]
275mod test {
David Brown7ddec0b2017-07-06 10:47:35 -0600276 use super::{Flash, SimFlash, Error, ErrorKind, Result, Sector};
David Brownde7729e2017-01-09 10:41:35 -0700277
278 #[test]
279 fn test_flash() {
280 // NXP-style, uniform sectors.
David Brown7ddec0b2017-07-06 10:47:35 -0600281 let mut f1 = SimFlash::new(vec![4096usize; 256], 1);
David Brownde7729e2017-01-09 10:41:35 -0700282 test_device(&mut f1);
283
284 // STM style, non-uniform sectors
David Brown7ddec0b2017-07-06 10:47:35 -0600285 let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
286 128 * 1024, 128 * 1024, 128 * 1024], 1);
David Brownde7729e2017-01-09 10:41:35 -0700287 test_device(&mut f2);
288 }
289
290 fn test_device(flash: &mut Flash) {
291 let sectors: Vec<Sector> = flash.sector_iter().collect();
292
293 flash.erase(0, sectors[0].size).unwrap();
294 let flash_size = flash.device_size();
295 flash.erase(0, flash_size).unwrap();
296 assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
297
298 // Verify that write and erase do something.
299 flash.write(0, &[0]).unwrap();
300 let mut buf = [0; 4];
301 flash.read(0, &mut buf).unwrap();
302 assert_eq!(buf, [0, 0xff, 0xff, 0xff]);
303
304 flash.erase(0, sectors[0].size).unwrap();
305 flash.read(0, &mut buf).unwrap();
306 assert_eq!(buf, [0xff; 4]);
307
308 // Program the first and last byte of each sector, verify that has been done, and then
309 // erase to verify the erase boundaries.
310 for sector in &sectors {
311 let byte = [(sector.num & 127) as u8];
312 flash.write(sector.base, &byte).unwrap();
313 flash.write(sector.base + sector.size - 1, &byte).unwrap();
314 }
315
316 // Verify the above
317 let mut buf = Vec::new();
318 for sector in &sectors {
319 let byte = (sector.num & 127) as u8;
320 buf.resize(sector.size, 0);
321 flash.read(sector.base, &mut buf).unwrap();
322 assert_eq!(buf.first(), Some(&byte));
323 assert_eq!(buf.last(), Some(&byte));
324 assert!(buf[1..buf.len()-1].iter().all(|&x| x == 0xff));
325 }
326 }
327
328 // Helper checks for the result type.
329 trait EChecker {
330 fn is_bounds(&self) -> bool;
331 }
332
333 impl<T> EChecker for Result<T> {
334
335 fn is_bounds(&self) -> bool {
336 match *self {
337 Err(Error(ErrorKind::OutOfBounds(_), _)) => true,
338 _ => false,
339 }
340 }
341 }
342}