blob: cd074c9b4ea00971d6099b54b7f8cbacd20d15e5 [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
David Brown2cbc4702017-07-06 14:18:58 -06006#[macro_use] extern crate error_chain;
7mod pdump;
8
David Brownafabfcf2019-01-02 11:30:27 -07009use crate::pdump::HexDump;
David Brownea25c412019-01-02 11:33:55 -070010use log::info;
11use rand::{
12 self,
13 distributions::{IndependentSample, Range},
14};
15use std::{
16 collections::HashMap,
17 fs::File,
18 io::Write,
19 iter::Enumerate,
20 path::Path,
21 slice,
22};
David Brownde7729e2017-01-09 10:41:35 -070023
24error_chain! {
25 errors {
26 OutOfBounds(t: String) {
27 description("Offset is out of bounds")
28 display("Offset out of bounds: {}", t)
29 }
30 Write(t: String) {
31 description("Invalid write")
32 display("Invalid write: {}", t)
33 }
Fabio Utzigf5c895e2017-11-23 19:57:17 -020034 SimulatedFail(t: String) {
35 description("Write failed by chance")
36 display("Failed write: {}", t)
37 }
David Brownde7729e2017-01-09 10:41:35 -070038 }
39}
40
Fabio Utzig1c9aea52018-11-15 10:36:07 -020041pub struct FlashPtr {
David Brownea25c412019-01-02 11:33:55 -070042 pub ptr: *mut dyn Flash,
Fabio Utzig1c9aea52018-11-15 10:36:07 -020043}
44unsafe impl Send for FlashPtr {}
45
David Brown7ddec0b2017-07-06 10:47:35 -060046pub trait Flash {
47 fn erase(&mut self, offset: usize, len: usize) -> Result<()>;
48 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()>;
49 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()>;
50
Fabio Utzigf5c895e2017-11-23 19:57:17 -020051 fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()>;
52 fn reset_bad_regions(&mut self);
53
Fabio Utzigfa137fc2017-11-23 20:01:02 -020054 fn set_verify_writes(&mut self, enable: bool);
55
David Brownea25c412019-01-02 11:33:55 -070056 fn sector_iter(&self) -> SectorIter<'_>;
David Brown7ddec0b2017-07-06 10:47:35 -060057 fn device_size(&self) -> usize;
Fabio Utzigea0290b2018-08-09 14:23:01 -030058
Fabio Utzig269d2862018-10-24 17:45:38 -030059 fn align(&self) -> usize;
Fabio Utzigea0290b2018-08-09 14:23:01 -030060 fn erased_val(&self) -> u8;
David Brown7ddec0b2017-07-06 10:47:35 -060061}
62
David Brownde7729e2017-01-09 10:41:35 -070063fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
64 ErrorKind::OutOfBounds(message.as_ref().to_owned())
65}
66
Fabio Utzig65935d72017-07-17 15:34:36 -030067#[allow(dead_code)]
David Brownde7729e2017-01-09 10:41:35 -070068fn ewrite<T: AsRef<str>>(message: T) -> ErrorKind {
69 ErrorKind::Write(message.as_ref().to_owned())
70}
71
Fabio Utzigf5c895e2017-11-23 19:57:17 -020072#[allow(dead_code)]
73fn esimulatedwrite<T: AsRef<str>>(message: T) -> ErrorKind {
74 ErrorKind::SimulatedFail(message.as_ref().to_owned())
75}
76
David Brownde7729e2017-01-09 10:41:35 -070077/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
78/// mapings.
79#[derive(Clone)]
David Brown7ddec0b2017-07-06 10:47:35 -060080pub struct SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070081 data: Vec<u8>,
Marti Bolivar51d36dd2017-05-17 17:39:46 -040082 write_safe: Vec<bool>,
David Brownde7729e2017-01-09 10:41:35 -070083 sectors: Vec<usize>,
Fabio Utzigf5c895e2017-11-23 19:57:17 -020084 bad_region: Vec<(usize, usize, f32)>,
David Brown562a7a02017-01-23 11:19:03 -070085 // Alignment required for writes.
86 align: usize,
Fabio Utzigfa137fc2017-11-23 20:01:02 -020087 verify_writes: bool,
Fabio Utzigea0290b2018-08-09 14:23:01 -030088 erased_val: u8,
David Brownde7729e2017-01-09 10:41:35 -070089}
90
David Brown7ddec0b2017-07-06 10:47:35 -060091impl SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070092 /// Given a sector size map, construct a flash device for that.
Fabio Utzigea0290b2018-08-09 14:23:01 -030093 pub fn new(sectors: Vec<usize>, align: usize, erased_val: u8) -> SimFlash {
David Brown562a7a02017-01-23 11:19:03 -070094 // Verify that the alignment is a positive power of two.
95 assert!(align > 0);
96 assert!(align & (align - 1) == 0);
97
David Brownde7729e2017-01-09 10:41:35 -070098 let total = sectors.iter().sum();
David Brown7ddec0b2017-07-06 10:47:35 -060099 SimFlash {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300100 data: vec![erased_val; total],
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400101 write_safe: vec![true; total],
David Brownde7729e2017-01-09 10:41:35 -0700102 sectors: sectors,
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200103 bad_region: Vec::new(),
David Brown562a7a02017-01-23 11:19:03 -0700104 align: align,
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200105 verify_writes: true,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300106 erased_val: erased_val,
David Brownde7729e2017-01-09 10:41:35 -0700107 }
108 }
109
David Brown7ddec0b2017-07-06 10:47:35 -0600110 #[allow(dead_code)]
111 pub fn dump(&self) {
112 self.data.dump();
113 }
114
115 /// Dump this image to the given file.
116 #[allow(dead_code)]
117 pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
118 let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
119 fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
120 Ok(())
121 }
122
123 // Scan the sector map, and return the base and offset within a sector for this given byte.
124 // Returns None if the value is outside of the device.
125 fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
126 let mut offset = offset;
127 for (sector, &size) in self.sectors.iter().enumerate() {
128 if offset < size {
129 return Some((sector, offset));
130 }
131 offset -= size;
132 }
133 return None;
134 }
135
136}
137
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200138pub type SimFlashMap = HashMap<u8, SimFlash>;
139
David Brown7ddec0b2017-07-06 10:47:35 -0600140impl Flash for SimFlash {
David Brownde7729e2017-01-09 10:41:35 -0700141 /// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
142 /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
143 /// return an error.
David Brown7ddec0b2017-07-06 10:47:35 -0600144 fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700145 let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
146 let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
147
148 if slen != 0 {
149 bail!(ebounds("offset not at start of sector"));
150 }
151 if elen != self.sectors[end] - 1 {
152 bail!(ebounds("end not at start of sector"));
153 }
154
155 for x in &mut self.data[offset .. offset + len] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300156 *x = self.erased_val;
David Brownde7729e2017-01-09 10:41:35 -0700157 }
158
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400159 for x in &mut self.write_safe[offset .. offset + len] {
160 *x = true;
161 }
162
David Brownde7729e2017-01-09 10:41:35 -0700163 Ok(())
164 }
165
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400166 /// We restrict to only allowing writes of values that are:
167 ///
168 /// 1. being written to for the first time
169 /// 2. being written to after being erased
170 ///
171 /// This emulates a flash device which starts out erased, with the
172 /// added restriction that repeated writes to the same location
173 /// are disallowed, even if they would be safe to do.
David Brown7ddec0b2017-07-06 10:47:35 -0600174 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200175 for &(off, len, rate) in &self.bad_region {
176 if offset >= off && (offset + payload.len()) <= (off + len) {
177 let mut rng = rand::thread_rng();
178 let between = Range::new(0., 1.);
179 if between.ind_sample(&mut rng) < rate {
180 bail!(esimulatedwrite(
181 format!("Ignoring write to {:#x}-{:#x}", off, off + len)));
182 }
183 }
184 }
185
David Brownde7729e2017-01-09 10:41:35 -0700186 if offset + payload.len() > self.data.len() {
David Brownf253fa82017-01-23 15:43:47 -0700187 panic!("Write outside of device");
David Brownde7729e2017-01-09 10:41:35 -0700188 }
189
David Brown562a7a02017-01-23 11:19:03 -0700190 // Verify the alignment (which must be a power of two).
191 if offset & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700192 panic!("Misaligned write address");
David Brown562a7a02017-01-23 11:19:03 -0700193 }
194
195 if payload.len() & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700196 panic!("Write length not multiple of alignment");
David Brown562a7a02017-01-23 11:19:03 -0700197 }
198
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400199 for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200200 if self.verify_writes && !(*x) {
Fabio Utzig65935d72017-07-17 15:34:36 -0300201 panic!("Write to unerased location at 0x{:x}", offset + i);
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300202 }
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400203 *x = false;
David Brownde7729e2017-01-09 10:41:35 -0700204 }
205
David Brown59ae5222017-12-06 11:45:15 -0700206 let sub = &mut self.data[offset .. offset + payload.len()];
David Brownde7729e2017-01-09 10:41:35 -0700207 sub.copy_from_slice(payload);
208 Ok(())
209 }
210
211 /// Read is simple.
David Brown7ddec0b2017-07-06 10:47:35 -0600212 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700213 if offset + data.len() > self.data.len() {
214 bail!(ebounds("Read outside of device"));
215 }
216
217 let sub = &self.data[offset .. offset + data.len()];
218 data.copy_from_slice(sub);
219 Ok(())
220 }
221
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200222 /// Adds a new flash bad region. Writes to this area fail with a chance
223 /// given by `rate`.
224 fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()> {
225 if rate < 0.0 || rate > 1.0 {
226 bail!(ebounds("Invalid rate"));
227 }
228
229 info!("Adding new bad region {:#x}-{:#x}", offset, offset + len);
230 self.bad_region.push((offset, len, rate));
231
232 Ok(())
233 }
234
235 fn reset_bad_regions(&mut self) {
236 self.bad_region.clear();
237 }
238
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200239 fn set_verify_writes(&mut self, enable: bool) {
240 self.verify_writes = enable;
241 }
242
David Brownde7729e2017-01-09 10:41:35 -0700243 /// An iterator over each sector in the device.
David Brownea25c412019-01-02 11:33:55 -0700244 fn sector_iter(&self) -> SectorIter<'_> {
David Brownde7729e2017-01-09 10:41:35 -0700245 SectorIter {
246 iter: self.sectors.iter().enumerate(),
247 base: 0,
248 }
249 }
250
David Brown7ddec0b2017-07-06 10:47:35 -0600251 fn device_size(&self) -> usize {
David Brownde7729e2017-01-09 10:41:35 -0700252 self.data.len()
253 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300254
Fabio Utzig269d2862018-10-24 17:45:38 -0300255 fn align(&self) -> usize {
256 self.align
257 }
258
Fabio Utzigea0290b2018-08-09 14:23:01 -0300259 fn erased_val(&self) -> u8 {
260 self.erased_val
261 }
David Brownde7729e2017-01-09 10:41:35 -0700262}
263
264/// It is possible to iterate over the sectors in the device, each element returning this.
David Brown3f687dc2017-11-06 13:41:18 -0700265#[derive(Debug, Clone)]
David Brownde7729e2017-01-09 10:41:35 -0700266pub struct Sector {
267 /// Which sector is this, starting from 0.
268 pub num: usize,
269 /// The offset, in bytes, of the start of this sector.
270 pub base: usize,
271 /// The length, in bytes, of this sector.
272 pub size: usize,
273}
274
275pub struct SectorIter<'a> {
276 iter: Enumerate<slice::Iter<'a, usize>>,
277 base: usize,
278}
279
280impl<'a> Iterator for SectorIter<'a> {
281 type Item = Sector;
282
283 fn next(&mut self) -> Option<Sector> {
284 match self.iter.next() {
285 None => None,
286 Some((num, &size)) => {
287 let base = self.base;
288 self.base += size;
289 Some(Sector {
290 num: num,
291 base: base,
292 size: size,
293 })
294 }
295 }
296 }
297}
298
299#[cfg(test)]
300mod test {
David Brown7ddec0b2017-07-06 10:47:35 -0600301 use super::{Flash, SimFlash, Error, ErrorKind, Result, Sector};
David Brownde7729e2017-01-09 10:41:35 -0700302
303 #[test]
304 fn test_flash() {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300305 for &erased_val in &[0, 0xff] {
306 // NXP-style, uniform sectors.
307 let mut f1 = SimFlash::new(vec![4096usize; 256], 1, erased_val);
308 test_device(&mut f1, erased_val);
David Brownde7729e2017-01-09 10:41:35 -0700309
Fabio Utzigea0290b2018-08-09 14:23:01 -0300310 // STM style, non-uniform sectors.
311 let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
312 128 * 1024, 128 * 1024, 128 * 1024], 1, erased_val);
313 test_device(&mut f2, erased_val);
314 }
David Brownde7729e2017-01-09 10:41:35 -0700315 }
316
David Brownea25c412019-01-02 11:33:55 -0700317 fn test_device(flash: &mut dyn Flash, erased_val: u8) {
David Brownde7729e2017-01-09 10:41:35 -0700318 let sectors: Vec<Sector> = flash.sector_iter().collect();
319
320 flash.erase(0, sectors[0].size).unwrap();
321 let flash_size = flash.device_size();
322 flash.erase(0, flash_size).unwrap();
323 assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
324
325 // Verify that write and erase do something.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300326 flash.write(0, &[0x55]).unwrap();
327 let mut buf = [0xAA; 4];
David Brownde7729e2017-01-09 10:41:35 -0700328 flash.read(0, &mut buf).unwrap();
Fabio Utzigea0290b2018-08-09 14:23:01 -0300329 assert_eq!(buf, [0x55, erased_val, erased_val, erased_val]);
David Brownde7729e2017-01-09 10:41:35 -0700330
331 flash.erase(0, sectors[0].size).unwrap();
332 flash.read(0, &mut buf).unwrap();
Fabio Utzigea0290b2018-08-09 14:23:01 -0300333 assert_eq!(buf, [erased_val; 4]);
David Brownde7729e2017-01-09 10:41:35 -0700334
335 // Program the first and last byte of each sector, verify that has been done, and then
336 // erase to verify the erase boundaries.
337 for sector in &sectors {
338 let byte = [(sector.num & 127) as u8];
339 flash.write(sector.base, &byte).unwrap();
340 flash.write(sector.base + sector.size - 1, &byte).unwrap();
341 }
342
343 // Verify the above
344 let mut buf = Vec::new();
345 for sector in &sectors {
346 let byte = (sector.num & 127) as u8;
347 buf.resize(sector.size, 0);
348 flash.read(sector.base, &mut buf).unwrap();
349 assert_eq!(buf.first(), Some(&byte));
350 assert_eq!(buf.last(), Some(&byte));
Fabio Utzigea0290b2018-08-09 14:23:01 -0300351 assert!(buf[1..buf.len()-1].iter().all(|&x| x == erased_val));
David Brownde7729e2017-01-09 10:41:35 -0700352 }
353 }
354
355 // Helper checks for the result type.
356 trait EChecker {
357 fn is_bounds(&self) -> bool;
358 }
359
360 impl<T> EChecker for Result<T> {
361
362 fn is_bounds(&self) -> bool {
363 match *self {
364 Err(Error(ErrorKind::OutOfBounds(_), _)) => true,
365 _ => false,
366 }
367 }
368 }
369}