blob: 1e9876cef41230442e5e1082ba029128be4f6f2a [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
Fabio Utzig1c9aea52018-11-15 10:36:07 -020036pub struct FlashPtr {
37 pub ptr: *mut Flash,
38}
39unsafe impl Send for FlashPtr {}
40
David Brown7ddec0b2017-07-06 10:47:35 -060041pub trait Flash {
42 fn erase(&mut self, offset: usize, len: usize) -> Result<()>;
43 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()>;
44 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()>;
45
Fabio Utzigf5c895e2017-11-23 19:57:17 -020046 fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()>;
47 fn reset_bad_regions(&mut self);
48
Fabio Utzigfa137fc2017-11-23 20:01:02 -020049 fn set_verify_writes(&mut self, enable: bool);
50
David Brown7ddec0b2017-07-06 10:47:35 -060051 fn sector_iter(&self) -> SectorIter;
52 fn device_size(&self) -> usize;
Fabio Utzigea0290b2018-08-09 14:23:01 -030053
Fabio Utzig269d2862018-10-24 17:45:38 -030054 fn align(&self) -> usize;
Fabio Utzigea0290b2018-08-09 14:23:01 -030055 fn erased_val(&self) -> u8;
David Brown7ddec0b2017-07-06 10:47:35 -060056}
57
David Brownde7729e2017-01-09 10:41:35 -070058fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
59 ErrorKind::OutOfBounds(message.as_ref().to_owned())
60}
61
Fabio Utzig65935d72017-07-17 15:34:36 -030062#[allow(dead_code)]
David Brownde7729e2017-01-09 10:41:35 -070063fn ewrite<T: AsRef<str>>(message: T) -> ErrorKind {
64 ErrorKind::Write(message.as_ref().to_owned())
65}
66
Fabio Utzigf5c895e2017-11-23 19:57:17 -020067#[allow(dead_code)]
68fn esimulatedwrite<T: AsRef<str>>(message: T) -> ErrorKind {
69 ErrorKind::SimulatedFail(message.as_ref().to_owned())
70}
71
David Brownde7729e2017-01-09 10:41:35 -070072/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
73/// mapings.
74#[derive(Clone)]
David Brown7ddec0b2017-07-06 10:47:35 -060075pub struct SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070076 data: Vec<u8>,
Marti Bolivar51d36dd2017-05-17 17:39:46 -040077 write_safe: Vec<bool>,
David Brownde7729e2017-01-09 10:41:35 -070078 sectors: Vec<usize>,
Fabio Utzigf5c895e2017-11-23 19:57:17 -020079 bad_region: Vec<(usize, usize, f32)>,
David Brown562a7a02017-01-23 11:19:03 -070080 // Alignment required for writes.
81 align: usize,
Fabio Utzigfa137fc2017-11-23 20:01:02 -020082 verify_writes: bool,
Fabio Utzigea0290b2018-08-09 14:23:01 -030083 erased_val: u8,
David Brownde7729e2017-01-09 10:41:35 -070084}
85
David Brown7ddec0b2017-07-06 10:47:35 -060086impl SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070087 /// Given a sector size map, construct a flash device for that.
Fabio Utzigea0290b2018-08-09 14:23:01 -030088 pub fn new(sectors: Vec<usize>, align: usize, erased_val: u8) -> SimFlash {
David Brown562a7a02017-01-23 11:19:03 -070089 // Verify that the alignment is a positive power of two.
90 assert!(align > 0);
91 assert!(align & (align - 1) == 0);
92
David Brownde7729e2017-01-09 10:41:35 -070093 let total = sectors.iter().sum();
David Brown7ddec0b2017-07-06 10:47:35 -060094 SimFlash {
Fabio Utzigea0290b2018-08-09 14:23:01 -030095 data: vec![erased_val; total],
Marti Bolivar51d36dd2017-05-17 17:39:46 -040096 write_safe: vec![true; total],
David Brownde7729e2017-01-09 10:41:35 -070097 sectors: sectors,
Fabio Utzigf5c895e2017-11-23 19:57:17 -020098 bad_region: Vec::new(),
David Brown562a7a02017-01-23 11:19:03 -070099 align: align,
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200100 verify_writes: true,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300101 erased_val: erased_val,
David Brownde7729e2017-01-09 10:41:35 -0700102 }
103 }
104
David Brown7ddec0b2017-07-06 10:47:35 -0600105 #[allow(dead_code)]
106 pub fn dump(&self) {
107 self.data.dump();
108 }
109
110 /// Dump this image to the given file.
111 #[allow(dead_code)]
112 pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
113 let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
114 fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
115 Ok(())
116 }
117
118 // Scan the sector map, and return the base and offset within a sector for this given byte.
119 // Returns None if the value is outside of the device.
120 fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
121 let mut offset = offset;
122 for (sector, &size) in self.sectors.iter().enumerate() {
123 if offset < size {
124 return Some((sector, offset));
125 }
126 offset -= size;
127 }
128 return None;
129 }
130
131}
132
133impl Flash for SimFlash {
David Brownde7729e2017-01-09 10:41:35 -0700134 /// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
135 /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
136 /// return an error.
David Brown7ddec0b2017-07-06 10:47:35 -0600137 fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700138 let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
139 let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
140
141 if slen != 0 {
142 bail!(ebounds("offset not at start of sector"));
143 }
144 if elen != self.sectors[end] - 1 {
145 bail!(ebounds("end not at start of sector"));
146 }
147
148 for x in &mut self.data[offset .. offset + len] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300149 *x = self.erased_val;
David Brownde7729e2017-01-09 10:41:35 -0700150 }
151
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400152 for x in &mut self.write_safe[offset .. offset + len] {
153 *x = true;
154 }
155
David Brownde7729e2017-01-09 10:41:35 -0700156 Ok(())
157 }
158
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400159 /// We restrict to only allowing writes of values that are:
160 ///
161 /// 1. being written to for the first time
162 /// 2. being written to after being erased
163 ///
164 /// This emulates a flash device which starts out erased, with the
165 /// added restriction that repeated writes to the same location
166 /// are disallowed, even if they would be safe to do.
David Brown7ddec0b2017-07-06 10:47:35 -0600167 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200168 for &(off, len, rate) in &self.bad_region {
169 if offset >= off && (offset + payload.len()) <= (off + len) {
170 let mut rng = rand::thread_rng();
171 let between = Range::new(0., 1.);
172 if between.ind_sample(&mut rng) < rate {
173 bail!(esimulatedwrite(
174 format!("Ignoring write to {:#x}-{:#x}", off, off + len)));
175 }
176 }
177 }
178
David Brownde7729e2017-01-09 10:41:35 -0700179 if offset + payload.len() > self.data.len() {
David Brownf253fa82017-01-23 15:43:47 -0700180 panic!("Write outside of device");
David Brownde7729e2017-01-09 10:41:35 -0700181 }
182
David Brown562a7a02017-01-23 11:19:03 -0700183 // Verify the alignment (which must be a power of two).
184 if offset & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700185 panic!("Misaligned write address");
David Brown562a7a02017-01-23 11:19:03 -0700186 }
187
188 if payload.len() & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700189 panic!("Write length not multiple of alignment");
David Brown562a7a02017-01-23 11:19:03 -0700190 }
191
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400192 for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200193 if self.verify_writes && !(*x) {
Fabio Utzig65935d72017-07-17 15:34:36 -0300194 panic!("Write to unerased location at 0x{:x}", offset + i);
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300195 }
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400196 *x = false;
David Brownde7729e2017-01-09 10:41:35 -0700197 }
198
David Brown59ae5222017-12-06 11:45:15 -0700199 let sub = &mut self.data[offset .. offset + payload.len()];
David Brownde7729e2017-01-09 10:41:35 -0700200 sub.copy_from_slice(payload);
201 Ok(())
202 }
203
204 /// Read is simple.
David Brown7ddec0b2017-07-06 10:47:35 -0600205 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700206 if offset + data.len() > self.data.len() {
207 bail!(ebounds("Read outside of device"));
208 }
209
210 let sub = &self.data[offset .. offset + data.len()];
211 data.copy_from_slice(sub);
212 Ok(())
213 }
214
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200215 /// Adds a new flash bad region. Writes to this area fail with a chance
216 /// given by `rate`.
217 fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()> {
218 if rate < 0.0 || rate > 1.0 {
219 bail!(ebounds("Invalid rate"));
220 }
221
222 info!("Adding new bad region {:#x}-{:#x}", offset, offset + len);
223 self.bad_region.push((offset, len, rate));
224
225 Ok(())
226 }
227
228 fn reset_bad_regions(&mut self) {
229 self.bad_region.clear();
230 }
231
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200232 fn set_verify_writes(&mut self, enable: bool) {
233 self.verify_writes = enable;
234 }
235
David Brownde7729e2017-01-09 10:41:35 -0700236 /// An iterator over each sector in the device.
David Brown7ddec0b2017-07-06 10:47:35 -0600237 fn sector_iter(&self) -> SectorIter {
David Brownde7729e2017-01-09 10:41:35 -0700238 SectorIter {
239 iter: self.sectors.iter().enumerate(),
240 base: 0,
241 }
242 }
243
David Brown7ddec0b2017-07-06 10:47:35 -0600244 fn device_size(&self) -> usize {
David Brownde7729e2017-01-09 10:41:35 -0700245 self.data.len()
246 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300247
Fabio Utzig269d2862018-10-24 17:45:38 -0300248 fn align(&self) -> usize {
249 self.align
250 }
251
Fabio Utzigea0290b2018-08-09 14:23:01 -0300252 fn erased_val(&self) -> u8 {
253 self.erased_val
254 }
David Brownde7729e2017-01-09 10:41:35 -0700255}
256
257/// It is possible to iterate over the sectors in the device, each element returning this.
David Brown3f687dc2017-11-06 13:41:18 -0700258#[derive(Debug, Clone)]
David Brownde7729e2017-01-09 10:41:35 -0700259pub struct Sector {
260 /// Which sector is this, starting from 0.
261 pub num: usize,
262 /// The offset, in bytes, of the start of this sector.
263 pub base: usize,
264 /// The length, in bytes, of this sector.
265 pub size: usize,
266}
267
268pub struct SectorIter<'a> {
269 iter: Enumerate<slice::Iter<'a, usize>>,
270 base: usize,
271}
272
273impl<'a> Iterator for SectorIter<'a> {
274 type Item = Sector;
275
276 fn next(&mut self) -> Option<Sector> {
277 match self.iter.next() {
278 None => None,
279 Some((num, &size)) => {
280 let base = self.base;
281 self.base += size;
282 Some(Sector {
283 num: num,
284 base: base,
285 size: size,
286 })
287 }
288 }
289 }
290}
291
292#[cfg(test)]
293mod test {
David Brown7ddec0b2017-07-06 10:47:35 -0600294 use super::{Flash, SimFlash, Error, ErrorKind, Result, Sector};
David Brownde7729e2017-01-09 10:41:35 -0700295
296 #[test]
297 fn test_flash() {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300298 for &erased_val in &[0, 0xff] {
299 // NXP-style, uniform sectors.
300 let mut f1 = SimFlash::new(vec![4096usize; 256], 1, erased_val);
301 test_device(&mut f1, erased_val);
David Brownde7729e2017-01-09 10:41:35 -0700302
Fabio Utzigea0290b2018-08-09 14:23:01 -0300303 // STM style, non-uniform sectors.
304 let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
305 128 * 1024, 128 * 1024, 128 * 1024], 1, erased_val);
306 test_device(&mut f2, erased_val);
307 }
David Brownde7729e2017-01-09 10:41:35 -0700308 }
309
Fabio Utzigea0290b2018-08-09 14:23:01 -0300310 fn test_device(flash: &mut Flash, erased_val: u8) {
David Brownde7729e2017-01-09 10:41:35 -0700311 let sectors: Vec<Sector> = flash.sector_iter().collect();
312
313 flash.erase(0, sectors[0].size).unwrap();
314 let flash_size = flash.device_size();
315 flash.erase(0, flash_size).unwrap();
316 assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
317
318 // Verify that write and erase do something.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300319 flash.write(0, &[0x55]).unwrap();
320 let mut buf = [0xAA; 4];
David Brownde7729e2017-01-09 10:41:35 -0700321 flash.read(0, &mut buf).unwrap();
Fabio Utzigea0290b2018-08-09 14:23:01 -0300322 assert_eq!(buf, [0x55, erased_val, erased_val, erased_val]);
David Brownde7729e2017-01-09 10:41:35 -0700323
324 flash.erase(0, sectors[0].size).unwrap();
325 flash.read(0, &mut buf).unwrap();
Fabio Utzigea0290b2018-08-09 14:23:01 -0300326 assert_eq!(buf, [erased_val; 4]);
David Brownde7729e2017-01-09 10:41:35 -0700327
328 // Program the first and last byte of each sector, verify that has been done, and then
329 // erase to verify the erase boundaries.
330 for sector in &sectors {
331 let byte = [(sector.num & 127) as u8];
332 flash.write(sector.base, &byte).unwrap();
333 flash.write(sector.base + sector.size - 1, &byte).unwrap();
334 }
335
336 // Verify the above
337 let mut buf = Vec::new();
338 for sector in &sectors {
339 let byte = (sector.num & 127) as u8;
340 buf.resize(sector.size, 0);
341 flash.read(sector.base, &mut buf).unwrap();
342 assert_eq!(buf.first(), Some(&byte));
343 assert_eq!(buf.last(), Some(&byte));
Fabio Utzigea0290b2018-08-09 14:23:01 -0300344 assert!(buf[1..buf.len()-1].iter().all(|&x| x == erased_val));
David Brownde7729e2017-01-09 10:41:35 -0700345 }
346 }
347
348 // Helper checks for the result type.
349 trait EChecker {
350 fn is_bounds(&self) -> bool;
351 }
352
353 impl<T> EChecker for Result<T> {
354
355 fn is_bounds(&self) -> bool {
356 match *self {
357 Err(Error(ErrorKind::OutOfBounds(_), _)) => true,
358 _ => false,
359 }
360 }
361 }
362}