blob: 26f81875e17eba2bf92ea327407f52b34d9bc0a3 [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;
Fabio Utzigafb2bc92018-11-19 16:11:52 -020017use std::collections::HashMap;
David Brownafabfcf2019-01-02 11:30:27 -070018use crate::pdump::HexDump;
David Brownde7729e2017-01-09 10:41:35 -070019
20error_chain! {
21 errors {
22 OutOfBounds(t: String) {
23 description("Offset is out of bounds")
24 display("Offset out of bounds: {}", t)
25 }
26 Write(t: String) {
27 description("Invalid write")
28 display("Invalid write: {}", t)
29 }
Fabio Utzigf5c895e2017-11-23 19:57:17 -020030 SimulatedFail(t: String) {
31 description("Write failed by chance")
32 display("Failed write: {}", t)
33 }
David Brownde7729e2017-01-09 10:41:35 -070034 }
35}
36
Fabio Utzig1c9aea52018-11-15 10:36:07 -020037pub struct FlashPtr {
38 pub ptr: *mut Flash,
39}
40unsafe impl Send for FlashPtr {}
41
David Brown7ddec0b2017-07-06 10:47:35 -060042pub trait Flash {
43 fn erase(&mut self, offset: usize, len: usize) -> Result<()>;
44 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()>;
45 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()>;
46
Fabio Utzigf5c895e2017-11-23 19:57:17 -020047 fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()>;
48 fn reset_bad_regions(&mut self);
49
Fabio Utzigfa137fc2017-11-23 20:01:02 -020050 fn set_verify_writes(&mut self, enable: bool);
51
David Brown7ddec0b2017-07-06 10:47:35 -060052 fn sector_iter(&self) -> SectorIter;
53 fn device_size(&self) -> usize;
Fabio Utzigea0290b2018-08-09 14:23:01 -030054
Fabio Utzig269d2862018-10-24 17:45:38 -030055 fn align(&self) -> usize;
Fabio Utzigea0290b2018-08-09 14:23:01 -030056 fn erased_val(&self) -> u8;
David Brown7ddec0b2017-07-06 10:47:35 -060057}
58
David Brownde7729e2017-01-09 10:41:35 -070059fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
60 ErrorKind::OutOfBounds(message.as_ref().to_owned())
61}
62
Fabio Utzig65935d72017-07-17 15:34:36 -030063#[allow(dead_code)]
David Brownde7729e2017-01-09 10:41:35 -070064fn ewrite<T: AsRef<str>>(message: T) -> ErrorKind {
65 ErrorKind::Write(message.as_ref().to_owned())
66}
67
Fabio Utzigf5c895e2017-11-23 19:57:17 -020068#[allow(dead_code)]
69fn esimulatedwrite<T: AsRef<str>>(message: T) -> ErrorKind {
70 ErrorKind::SimulatedFail(message.as_ref().to_owned())
71}
72
David Brownde7729e2017-01-09 10:41:35 -070073/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
74/// mapings.
75#[derive(Clone)]
David Brown7ddec0b2017-07-06 10:47:35 -060076pub struct SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070077 data: Vec<u8>,
Marti Bolivar51d36dd2017-05-17 17:39:46 -040078 write_safe: Vec<bool>,
David Brownde7729e2017-01-09 10:41:35 -070079 sectors: Vec<usize>,
Fabio Utzigf5c895e2017-11-23 19:57:17 -020080 bad_region: Vec<(usize, usize, f32)>,
David Brown562a7a02017-01-23 11:19:03 -070081 // Alignment required for writes.
82 align: usize,
Fabio Utzigfa137fc2017-11-23 20:01:02 -020083 verify_writes: bool,
Fabio Utzigea0290b2018-08-09 14:23:01 -030084 erased_val: u8,
David Brownde7729e2017-01-09 10:41:35 -070085}
86
David Brown7ddec0b2017-07-06 10:47:35 -060087impl SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070088 /// Given a sector size map, construct a flash device for that.
Fabio Utzigea0290b2018-08-09 14:23:01 -030089 pub fn new(sectors: Vec<usize>, align: usize, erased_val: u8) -> SimFlash {
David Brown562a7a02017-01-23 11:19:03 -070090 // Verify that the alignment is a positive power of two.
91 assert!(align > 0);
92 assert!(align & (align - 1) == 0);
93
David Brownde7729e2017-01-09 10:41:35 -070094 let total = sectors.iter().sum();
David Brown7ddec0b2017-07-06 10:47:35 -060095 SimFlash {
Fabio Utzigea0290b2018-08-09 14:23:01 -030096 data: vec![erased_val; total],
Marti Bolivar51d36dd2017-05-17 17:39:46 -040097 write_safe: vec![true; total],
David Brownde7729e2017-01-09 10:41:35 -070098 sectors: sectors,
Fabio Utzigf5c895e2017-11-23 19:57:17 -020099 bad_region: Vec::new(),
David Brown562a7a02017-01-23 11:19:03 -0700100 align: align,
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200101 verify_writes: true,
Fabio Utzigea0290b2018-08-09 14:23:01 -0300102 erased_val: erased_val,
David Brownde7729e2017-01-09 10:41:35 -0700103 }
104 }
105
David Brown7ddec0b2017-07-06 10:47:35 -0600106 #[allow(dead_code)]
107 pub fn dump(&self) {
108 self.data.dump();
109 }
110
111 /// Dump this image to the given file.
112 #[allow(dead_code)]
113 pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
114 let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
115 fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
116 Ok(())
117 }
118
119 // Scan the sector map, and return the base and offset within a sector for this given byte.
120 // Returns None if the value is outside of the device.
121 fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
122 let mut offset = offset;
123 for (sector, &size) in self.sectors.iter().enumerate() {
124 if offset < size {
125 return Some((sector, offset));
126 }
127 offset -= size;
128 }
129 return None;
130 }
131
132}
133
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200134pub type SimFlashMap = HashMap<u8, SimFlash>;
135
David Brown7ddec0b2017-07-06 10:47:35 -0600136impl Flash for SimFlash {
David Brownde7729e2017-01-09 10:41:35 -0700137 /// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
138 /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
139 /// return an error.
David Brown7ddec0b2017-07-06 10:47:35 -0600140 fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700141 let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
142 let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
143
144 if slen != 0 {
145 bail!(ebounds("offset not at start of sector"));
146 }
147 if elen != self.sectors[end] - 1 {
148 bail!(ebounds("end not at start of sector"));
149 }
150
151 for x in &mut self.data[offset .. offset + len] {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300152 *x = self.erased_val;
David Brownde7729e2017-01-09 10:41:35 -0700153 }
154
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400155 for x in &mut self.write_safe[offset .. offset + len] {
156 *x = true;
157 }
158
David Brownde7729e2017-01-09 10:41:35 -0700159 Ok(())
160 }
161
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400162 /// We restrict to only allowing writes of values that are:
163 ///
164 /// 1. being written to for the first time
165 /// 2. being written to after being erased
166 ///
167 /// This emulates a flash device which starts out erased, with the
168 /// added restriction that repeated writes to the same location
169 /// are disallowed, even if they would be safe to do.
David Brown7ddec0b2017-07-06 10:47:35 -0600170 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200171 for &(off, len, rate) in &self.bad_region {
172 if offset >= off && (offset + payload.len()) <= (off + len) {
173 let mut rng = rand::thread_rng();
174 let between = Range::new(0., 1.);
175 if between.ind_sample(&mut rng) < rate {
176 bail!(esimulatedwrite(
177 format!("Ignoring write to {:#x}-{:#x}", off, off + len)));
178 }
179 }
180 }
181
David Brownde7729e2017-01-09 10:41:35 -0700182 if offset + payload.len() > self.data.len() {
David Brownf253fa82017-01-23 15:43:47 -0700183 panic!("Write outside of device");
David Brownde7729e2017-01-09 10:41:35 -0700184 }
185
David Brown562a7a02017-01-23 11:19:03 -0700186 // Verify the alignment (which must be a power of two).
187 if offset & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700188 panic!("Misaligned write address");
David Brown562a7a02017-01-23 11:19:03 -0700189 }
190
191 if payload.len() & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700192 panic!("Write length not multiple of alignment");
David Brown562a7a02017-01-23 11:19:03 -0700193 }
194
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400195 for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200196 if self.verify_writes && !(*x) {
Fabio Utzig65935d72017-07-17 15:34:36 -0300197 panic!("Write to unerased location at 0x{:x}", offset + i);
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300198 }
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400199 *x = false;
David Brownde7729e2017-01-09 10:41:35 -0700200 }
201
David Brown59ae5222017-12-06 11:45:15 -0700202 let sub = &mut self.data[offset .. offset + payload.len()];
David Brownde7729e2017-01-09 10:41:35 -0700203 sub.copy_from_slice(payload);
204 Ok(())
205 }
206
207 /// Read is simple.
David Brown7ddec0b2017-07-06 10:47:35 -0600208 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700209 if offset + data.len() > self.data.len() {
210 bail!(ebounds("Read outside of device"));
211 }
212
213 let sub = &self.data[offset .. offset + data.len()];
214 data.copy_from_slice(sub);
215 Ok(())
216 }
217
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200218 /// Adds a new flash bad region. Writes to this area fail with a chance
219 /// given by `rate`.
220 fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()> {
221 if rate < 0.0 || rate > 1.0 {
222 bail!(ebounds("Invalid rate"));
223 }
224
225 info!("Adding new bad region {:#x}-{:#x}", offset, offset + len);
226 self.bad_region.push((offset, len, rate));
227
228 Ok(())
229 }
230
231 fn reset_bad_regions(&mut self) {
232 self.bad_region.clear();
233 }
234
Fabio Utzigfa137fc2017-11-23 20:01:02 -0200235 fn set_verify_writes(&mut self, enable: bool) {
236 self.verify_writes = enable;
237 }
238
David Brownde7729e2017-01-09 10:41:35 -0700239 /// An iterator over each sector in the device.
David Brown7ddec0b2017-07-06 10:47:35 -0600240 fn sector_iter(&self) -> SectorIter {
David Brownde7729e2017-01-09 10:41:35 -0700241 SectorIter {
242 iter: self.sectors.iter().enumerate(),
243 base: 0,
244 }
245 }
246
David Brown7ddec0b2017-07-06 10:47:35 -0600247 fn device_size(&self) -> usize {
David Brownde7729e2017-01-09 10:41:35 -0700248 self.data.len()
249 }
Fabio Utzigea0290b2018-08-09 14:23:01 -0300250
Fabio Utzig269d2862018-10-24 17:45:38 -0300251 fn align(&self) -> usize {
252 self.align
253 }
254
Fabio Utzigea0290b2018-08-09 14:23:01 -0300255 fn erased_val(&self) -> u8 {
256 self.erased_val
257 }
David Brownde7729e2017-01-09 10:41:35 -0700258}
259
260/// It is possible to iterate over the sectors in the device, each element returning this.
David Brown3f687dc2017-11-06 13:41:18 -0700261#[derive(Debug, Clone)]
David Brownde7729e2017-01-09 10:41:35 -0700262pub struct Sector {
263 /// Which sector is this, starting from 0.
264 pub num: usize,
265 /// The offset, in bytes, of the start of this sector.
266 pub base: usize,
267 /// The length, in bytes, of this sector.
268 pub size: usize,
269}
270
271pub struct SectorIter<'a> {
272 iter: Enumerate<slice::Iter<'a, usize>>,
273 base: usize,
274}
275
276impl<'a> Iterator for SectorIter<'a> {
277 type Item = Sector;
278
279 fn next(&mut self) -> Option<Sector> {
280 match self.iter.next() {
281 None => None,
282 Some((num, &size)) => {
283 let base = self.base;
284 self.base += size;
285 Some(Sector {
286 num: num,
287 base: base,
288 size: size,
289 })
290 }
291 }
292 }
293}
294
295#[cfg(test)]
296mod test {
David Brown7ddec0b2017-07-06 10:47:35 -0600297 use super::{Flash, SimFlash, Error, ErrorKind, Result, Sector};
David Brownde7729e2017-01-09 10:41:35 -0700298
299 #[test]
300 fn test_flash() {
Fabio Utzigea0290b2018-08-09 14:23:01 -0300301 for &erased_val in &[0, 0xff] {
302 // NXP-style, uniform sectors.
303 let mut f1 = SimFlash::new(vec![4096usize; 256], 1, erased_val);
304 test_device(&mut f1, erased_val);
David Brownde7729e2017-01-09 10:41:35 -0700305
Fabio Utzigea0290b2018-08-09 14:23:01 -0300306 // STM style, non-uniform sectors.
307 let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
308 128 * 1024, 128 * 1024, 128 * 1024], 1, erased_val);
309 test_device(&mut f2, erased_val);
310 }
David Brownde7729e2017-01-09 10:41:35 -0700311 }
312
Fabio Utzigea0290b2018-08-09 14:23:01 -0300313 fn test_device(flash: &mut Flash, erased_val: u8) {
David Brownde7729e2017-01-09 10:41:35 -0700314 let sectors: Vec<Sector> = flash.sector_iter().collect();
315
316 flash.erase(0, sectors[0].size).unwrap();
317 let flash_size = flash.device_size();
318 flash.erase(0, flash_size).unwrap();
319 assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
320
321 // Verify that write and erase do something.
Fabio Utzigea0290b2018-08-09 14:23:01 -0300322 flash.write(0, &[0x55]).unwrap();
323 let mut buf = [0xAA; 4];
David Brownde7729e2017-01-09 10:41:35 -0700324 flash.read(0, &mut buf).unwrap();
Fabio Utzigea0290b2018-08-09 14:23:01 -0300325 assert_eq!(buf, [0x55, erased_val, erased_val, erased_val]);
David Brownde7729e2017-01-09 10:41:35 -0700326
327 flash.erase(0, sectors[0].size).unwrap();
328 flash.read(0, &mut buf).unwrap();
Fabio Utzigea0290b2018-08-09 14:23:01 -0300329 assert_eq!(buf, [erased_val; 4]);
David Brownde7729e2017-01-09 10:41:35 -0700330
331 // Program the first and last byte of each sector, verify that has been done, and then
332 // erase to verify the erase boundaries.
333 for sector in &sectors {
334 let byte = [(sector.num & 127) as u8];
335 flash.write(sector.base, &byte).unwrap();
336 flash.write(sector.base + sector.size - 1, &byte).unwrap();
337 }
338
339 // Verify the above
340 let mut buf = Vec::new();
341 for sector in &sectors {
342 let byte = (sector.num & 127) as u8;
343 buf.resize(sector.size, 0);
344 flash.read(sector.base, &mut buf).unwrap();
345 assert_eq!(buf.first(), Some(&byte));
346 assert_eq!(buf.last(), Some(&byte));
Fabio Utzigea0290b2018-08-09 14:23:01 -0300347 assert!(buf[1..buf.len()-1].iter().all(|&x| x == erased_val));
David Brownde7729e2017-01-09 10:41:35 -0700348 }
349 }
350
351 // Helper checks for the result type.
352 trait EChecker {
353 fn is_bounds(&self) -> bool;
354 }
355
356 impl<T> EChecker for Result<T> {
357
358 fn is_bounds(&self) -> bool {
359 match *self {
360 Err(Error(ErrorKind::OutOfBounds(_), _)) => true,
361 _ => false,
362 }
363 }
364 }
365}