blob: d4817c1619bc16e1e85ed41dee168ca69aeba9eb [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
David Brown7ddec0b2017-07-06 10:47:35 -060044 fn sector_iter(&self) -> SectorIter;
45 fn device_size(&self) -> usize;
46}
47
David Brownde7729e2017-01-09 10:41:35 -070048fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
49 ErrorKind::OutOfBounds(message.as_ref().to_owned())
50}
51
Fabio Utzig65935d72017-07-17 15:34:36 -030052#[allow(dead_code)]
David Brownde7729e2017-01-09 10:41:35 -070053fn ewrite<T: AsRef<str>>(message: T) -> ErrorKind {
54 ErrorKind::Write(message.as_ref().to_owned())
55}
56
Fabio Utzigf5c895e2017-11-23 19:57:17 -020057#[allow(dead_code)]
58fn esimulatedwrite<T: AsRef<str>>(message: T) -> ErrorKind {
59 ErrorKind::SimulatedFail(message.as_ref().to_owned())
60}
61
David Brownde7729e2017-01-09 10:41:35 -070062/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
63/// mapings.
64#[derive(Clone)]
David Brown7ddec0b2017-07-06 10:47:35 -060065pub struct SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070066 data: Vec<u8>,
Marti Bolivar51d36dd2017-05-17 17:39:46 -040067 write_safe: Vec<bool>,
David Brownde7729e2017-01-09 10:41:35 -070068 sectors: Vec<usize>,
Fabio Utzigf5c895e2017-11-23 19:57:17 -020069 bad_region: Vec<(usize, usize, f32)>,
David Brown562a7a02017-01-23 11:19:03 -070070 // Alignment required for writes.
71 align: usize,
David Brownde7729e2017-01-09 10:41:35 -070072}
73
David Brown7ddec0b2017-07-06 10:47:35 -060074impl SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070075 /// Given a sector size map, construct a flash device for that.
David Brown7ddec0b2017-07-06 10:47:35 -060076 pub fn new(sectors: Vec<usize>, align: usize) -> SimFlash {
David Brown562a7a02017-01-23 11:19:03 -070077 // Verify that the alignment is a positive power of two.
78 assert!(align > 0);
79 assert!(align & (align - 1) == 0);
80
David Brownde7729e2017-01-09 10:41:35 -070081 let total = sectors.iter().sum();
David Brown7ddec0b2017-07-06 10:47:35 -060082 SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070083 data: vec![0xffu8; total],
Marti Bolivar51d36dd2017-05-17 17:39:46 -040084 write_safe: vec![true; total],
David Brownde7729e2017-01-09 10:41:35 -070085 sectors: sectors,
Fabio Utzigf5c895e2017-11-23 19:57:17 -020086 bad_region: Vec::new(),
David Brown562a7a02017-01-23 11:19:03 -070087 align: align,
David Brownde7729e2017-01-09 10:41:35 -070088 }
89 }
90
David Brown7ddec0b2017-07-06 10:47:35 -060091 #[allow(dead_code)]
92 pub fn dump(&self) {
93 self.data.dump();
94 }
95
96 /// Dump this image to the given file.
97 #[allow(dead_code)]
98 pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
99 let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
100 fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
101 Ok(())
102 }
103
104 // Scan the sector map, and return the base and offset within a sector for this given byte.
105 // Returns None if the value is outside of the device.
106 fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
107 let mut offset = offset;
108 for (sector, &size) in self.sectors.iter().enumerate() {
109 if offset < size {
110 return Some((sector, offset));
111 }
112 offset -= size;
113 }
114 return None;
115 }
116
117}
118
119impl Flash for SimFlash {
David Brownde7729e2017-01-09 10:41:35 -0700120 /// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
121 /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
122 /// return an error.
David Brown7ddec0b2017-07-06 10:47:35 -0600123 fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700124 let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
125 let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
126
127 if slen != 0 {
128 bail!(ebounds("offset not at start of sector"));
129 }
130 if elen != self.sectors[end] - 1 {
131 bail!(ebounds("end not at start of sector"));
132 }
133
134 for x in &mut self.data[offset .. offset + len] {
135 *x = 0xff;
136 }
137
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400138 for x in &mut self.write_safe[offset .. offset + len] {
139 *x = true;
140 }
141
David Brownde7729e2017-01-09 10:41:35 -0700142 Ok(())
143 }
144
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400145 /// We restrict to only allowing writes of values that are:
146 ///
147 /// 1. being written to for the first time
148 /// 2. being written to after being erased
149 ///
150 /// This emulates a flash device which starts out erased, with the
151 /// added restriction that repeated writes to the same location
152 /// are disallowed, even if they would be safe to do.
David Brown7ddec0b2017-07-06 10:47:35 -0600153 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200154 for &(off, len, rate) in &self.bad_region {
155 if offset >= off && (offset + payload.len()) <= (off + len) {
156 let mut rng = rand::thread_rng();
157 let between = Range::new(0., 1.);
158 if between.ind_sample(&mut rng) < rate {
159 bail!(esimulatedwrite(
160 format!("Ignoring write to {:#x}-{:#x}", off, off + len)));
161 }
162 }
163 }
164
David Brownde7729e2017-01-09 10:41:35 -0700165 if offset + payload.len() > self.data.len() {
David Brownf253fa82017-01-23 15:43:47 -0700166 panic!("Write outside of device");
David Brownde7729e2017-01-09 10:41:35 -0700167 }
168
David Brown562a7a02017-01-23 11:19:03 -0700169 // Verify the alignment (which must be a power of two).
170 if offset & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700171 panic!("Misaligned write address");
David Brown562a7a02017-01-23 11:19:03 -0700172 }
173
174 if payload.len() & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700175 panic!("Write length not multiple of alignment");
David Brown562a7a02017-01-23 11:19:03 -0700176 }
177
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400178 for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
179 if !(*x) {
Fabio Utzig65935d72017-07-17 15:34:36 -0300180 panic!("Write to unerased location at 0x{:x}", offset + i);
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300181 }
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400182 *x = false;
David Brownde7729e2017-01-09 10:41:35 -0700183 }
184
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400185 let mut sub = &mut self.data[offset .. offset + payload.len()];
David Brownde7729e2017-01-09 10:41:35 -0700186 sub.copy_from_slice(payload);
187 Ok(())
188 }
189
190 /// Read is simple.
David Brown7ddec0b2017-07-06 10:47:35 -0600191 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700192 if offset + data.len() > self.data.len() {
193 bail!(ebounds("Read outside of device"));
194 }
195
196 let sub = &self.data[offset .. offset + data.len()];
197 data.copy_from_slice(sub);
198 Ok(())
199 }
200
Fabio Utzigf5c895e2017-11-23 19:57:17 -0200201 /// Adds a new flash bad region. Writes to this area fail with a chance
202 /// given by `rate`.
203 fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()> {
204 if rate < 0.0 || rate > 1.0 {
205 bail!(ebounds("Invalid rate"));
206 }
207
208 info!("Adding new bad region {:#x}-{:#x}", offset, offset + len);
209 self.bad_region.push((offset, len, rate));
210
211 Ok(())
212 }
213
214 fn reset_bad_regions(&mut self) {
215 self.bad_region.clear();
216 }
217
David Brownde7729e2017-01-09 10:41:35 -0700218 /// An iterator over each sector in the device.
David Brown7ddec0b2017-07-06 10:47:35 -0600219 fn sector_iter(&self) -> SectorIter {
David Brownde7729e2017-01-09 10:41:35 -0700220 SectorIter {
221 iter: self.sectors.iter().enumerate(),
222 base: 0,
223 }
224 }
225
David Brown7ddec0b2017-07-06 10:47:35 -0600226 fn device_size(&self) -> usize {
David Brownde7729e2017-01-09 10:41:35 -0700227 self.data.len()
228 }
David Brownde7729e2017-01-09 10:41:35 -0700229}
230
231/// It is possible to iterate over the sectors in the device, each element returning this.
David Brown3f687dc2017-11-06 13:41:18 -0700232#[derive(Debug, Clone)]
David Brownde7729e2017-01-09 10:41:35 -0700233pub struct Sector {
234 /// Which sector is this, starting from 0.
235 pub num: usize,
236 /// The offset, in bytes, of the start of this sector.
237 pub base: usize,
238 /// The length, in bytes, of this sector.
239 pub size: usize,
240}
241
242pub struct SectorIter<'a> {
243 iter: Enumerate<slice::Iter<'a, usize>>,
244 base: usize,
245}
246
247impl<'a> Iterator for SectorIter<'a> {
248 type Item = Sector;
249
250 fn next(&mut self) -> Option<Sector> {
251 match self.iter.next() {
252 None => None,
253 Some((num, &size)) => {
254 let base = self.base;
255 self.base += size;
256 Some(Sector {
257 num: num,
258 base: base,
259 size: size,
260 })
261 }
262 }
263 }
264}
265
266#[cfg(test)]
267mod test {
David Brown7ddec0b2017-07-06 10:47:35 -0600268 use super::{Flash, SimFlash, Error, ErrorKind, Result, Sector};
David Brownde7729e2017-01-09 10:41:35 -0700269
270 #[test]
271 fn test_flash() {
272 // NXP-style, uniform sectors.
David Brown7ddec0b2017-07-06 10:47:35 -0600273 let mut f1 = SimFlash::new(vec![4096usize; 256], 1);
David Brownde7729e2017-01-09 10:41:35 -0700274 test_device(&mut f1);
275
276 // STM style, non-uniform sectors
David Brown7ddec0b2017-07-06 10:47:35 -0600277 let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
278 128 * 1024, 128 * 1024, 128 * 1024], 1);
David Brownde7729e2017-01-09 10:41:35 -0700279 test_device(&mut f2);
280 }
281
282 fn test_device(flash: &mut Flash) {
283 let sectors: Vec<Sector> = flash.sector_iter().collect();
284
285 flash.erase(0, sectors[0].size).unwrap();
286 let flash_size = flash.device_size();
287 flash.erase(0, flash_size).unwrap();
288 assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
289
290 // Verify that write and erase do something.
291 flash.write(0, &[0]).unwrap();
292 let mut buf = [0; 4];
293 flash.read(0, &mut buf).unwrap();
294 assert_eq!(buf, [0, 0xff, 0xff, 0xff]);
295
296 flash.erase(0, sectors[0].size).unwrap();
297 flash.read(0, &mut buf).unwrap();
298 assert_eq!(buf, [0xff; 4]);
299
300 // Program the first and last byte of each sector, verify that has been done, and then
301 // erase to verify the erase boundaries.
302 for sector in &sectors {
303 let byte = [(sector.num & 127) as u8];
304 flash.write(sector.base, &byte).unwrap();
305 flash.write(sector.base + sector.size - 1, &byte).unwrap();
306 }
307
308 // Verify the above
309 let mut buf = Vec::new();
310 for sector in &sectors {
311 let byte = (sector.num & 127) as u8;
312 buf.resize(sector.size, 0);
313 flash.read(sector.base, &mut buf).unwrap();
314 assert_eq!(buf.first(), Some(&byte));
315 assert_eq!(buf.last(), Some(&byte));
316 assert!(buf[1..buf.len()-1].iter().all(|&x| x == 0xff));
317 }
318 }
319
320 // Helper checks for the result type.
321 trait EChecker {
322 fn is_bounds(&self) -> bool;
323 }
324
325 impl<T> EChecker for Result<T> {
326
327 fn is_bounds(&self) -> bool {
328 match *self {
329 Err(Error(ErrorKind::OutOfBounds(_), _)) => true,
330 _ => false,
331 }
332 }
333 }
334}