1 // Copyright (c) 2017-2021 Linaro LTD
2 // Copyright (c) 2017-2018 JUUL Labs
3 //
4 // SPDX-License-Identifier: Apache-2.0
5 
6 //! A flash simulator
7 //!
8 //! This module is capable of simulating the type of NOR flash commonly used in microcontrollers.
9 //! These generally can be written as individual bytes, but must be erased in larger units.
10 
11 mod pdump;
12 
13 use crate::pdump::HexDump;
14 use log::info;
15 use rand::{
16     self,
17     distributions::Standard,
18     Rng,
19 };
20 use std::{
21     collections::HashMap,
22     fs::File,
23     io::{self, Write},
24     iter::Enumerate,
25     path::Path,
26     slice,
27 };
28 use thiserror::Error;
29 
30 pub type Result<T> = std::result::Result<T, FlashError>;
31 
32 #[derive(Error, Debug)]
33 pub enum FlashError {
34     #[error("Offset out of bounds: {0}")]
35     OutOfBounds(String),
36     #[error("Invalid write: {0}")]
37     Write(String),
38     #[error("Write failed by chance: {0}")]
39     SimulatedFail(String),
40     #[error("{0}")]
41     Io(#[from] io::Error),
42 }
43 
44 // Transition from error-chain.
45 macro_rules! bail {
46     ($item:expr) => (return Err($item.into());)
47 }
48 
49 pub struct FlashPtr {
50    pub ptr: *mut dyn Flash,
51 }
52 unsafe impl Send for FlashPtr {}
53 
54 pub trait Flash {
erase(&mut self, offset: usize, len: usize) -> Result<()>55     fn erase(&mut self, offset: usize, len: usize) -> Result<()>;
write(&mut self, offset: usize, payload: &[u8]) -> Result<()>56     fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()>;
read(&self, offset: usize, data: &mut [u8]) -> Result<()>57     fn read(&self, offset: usize, data: &mut [u8]) -> Result<()>;
58 
add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()>59     fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()>;
reset_bad_regions(&mut self)60     fn reset_bad_regions(&mut self);
61 
set_verify_writes(&mut self, enable: bool)62     fn set_verify_writes(&mut self, enable: bool);
63 
sector_iter(&self) -> SectorIter<'_>64     fn sector_iter(&self) -> SectorIter<'_>;
device_size(&self) -> usize65     fn device_size(&self) -> usize;
66 
align(&self) -> usize67     fn align(&self) -> usize;
erased_val(&self) -> u868     fn erased_val(&self) -> u8;
69 }
70 
ebounds<T: AsRef<str>>(message: T) -> FlashError71 fn ebounds<T: AsRef<str>>(message: T) -> FlashError {
72     FlashError::OutOfBounds(message.as_ref().to_owned())
73 }
74 
75 #[allow(dead_code)]
ewrite<T: AsRef<str>>(message: T) -> FlashError76 fn ewrite<T: AsRef<str>>(message: T) -> FlashError {
77     FlashError::Write(message.as_ref().to_owned())
78 }
79 
80 #[allow(dead_code)]
esimulatedwrite<T: AsRef<str>>(message: T) -> FlashError81 fn esimulatedwrite<T: AsRef<str>>(message: T) -> FlashError {
82     FlashError::SimulatedFail(message.as_ref().to_owned())
83 }
84 
85 /// An emulated flash device.  It is represented as a block of bytes, and a list of the sector
86 /// mappings.
87 #[derive(Clone)]
88 pub struct SimFlash {
89     data: Vec<u8>,
90     write_safe: Vec<bool>,
91     sectors: Vec<usize>,
92     bad_region: Vec<(usize, usize, f32)>,
93     // Alignment required for writes.
94     align: usize,
95     verify_writes: bool,
96     erased_val: u8,
97 }
98 
99 impl SimFlash {
100     /// Given a sector size map, construct a flash device for that.
new(sectors: Vec<usize>, align: usize, erased_val: u8) -> SimFlash101     pub fn new(sectors: Vec<usize>, align: usize, erased_val: u8) -> SimFlash {
102         // Verify that the alignment is a positive power of two.
103         assert!(align > 0);
104         assert!(align & (align - 1) == 0);
105 
106         let total = sectors.iter().sum();
107         SimFlash {
108             data: vec![erased_val; total],
109             write_safe: vec![true; total],
110             sectors,
111             bad_region: Vec::new(),
112             align,
113             verify_writes: true,
114             erased_val,
115         }
116     }
117 
118     #[allow(dead_code)]
dump(&self)119     pub fn dump(&self) {
120         self.data.dump();
121     }
122 
123     /// Dump this image to the given file.
124     #[allow(dead_code)]
write_file<P: AsRef<Path>>(&self, path: P) -> Result<()>125     pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
126         let mut fd = File::create(path)?;
127         fd.write_all(&self.data)?;
128         Ok(())
129     }
130 
131     // Scan the sector map, and return the base and offset within a sector for this given byte.
132     // Returns None if the value is outside of the device.
get_sector(&self, offset: usize) -> Option<(usize, usize)>133     fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
134         let mut offset = offset;
135         for (sector, &size) in self.sectors.iter().enumerate() {
136             if offset < size {
137                 return Some((sector, offset));
138             }
139             offset -= size;
140         }
141         None
142     }
143 
144 }
145 
146 pub type SimMultiFlash = HashMap<u8, SimFlash>;
147 
148 impl Flash for SimFlash {
149     /// The flash drivers tend to erase beyond the bounds of the given range.  Instead, we'll be
150     /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
151     /// return an error.
erase(&mut self, offset: usize, len: usize) -> Result<()>152     fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
153         let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
154         let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
155 
156         if slen != 0 {
157             bail!(ebounds("offset not at start of sector"));
158         }
159         if elen != self.sectors[end] - 1 {
160             bail!(ebounds("end not at start of sector"));
161         }
162 
163         for x in &mut self.data[offset .. offset + len] {
164             *x = self.erased_val;
165         }
166 
167         for x in &mut self.write_safe[offset .. offset + len] {
168             *x = true;
169         }
170 
171         Ok(())
172     }
173 
174     /// We restrict to only allowing writes of values that are:
175     ///
176     /// 1. being written to for the first time
177     /// 2. being written to after being erased
178     ///
179     /// This emulates a flash device which starts out erased, with the
180     /// added restriction that repeated writes to the same location
181     /// are disallowed, even if they would be safe to do.
write(&mut self, offset: usize, payload: &[u8]) -> Result<()>182     fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
183         for &(off, len, rate) in &self.bad_region {
184             if offset >= off && (offset + payload.len()) <= (off + len) {
185                 let mut rng = rand::thread_rng();
186                 let samp: f32 = rng.sample(Standard);
187                 if samp < rate {
188                     bail!(esimulatedwrite(
189                         format!("Ignoring write to {:#x}-{:#x}", off, off + len)));
190                 }
191             }
192         }
193 
194         if offset + payload.len() > self.data.len() {
195             panic!("Write outside of device");
196         }
197 
198         // Verify the alignment (which must be a power of two).
199         if offset & (self.align - 1) != 0 {
200             panic!("Misaligned write address");
201         }
202 
203         if payload.len() & (self.align - 1) != 0 {
204             panic!("Write length not multiple of alignment");
205         }
206 
207         for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
208             if self.verify_writes && !(*x) {
209                 panic!("Write to unerased location at 0x{:x}", offset + i);
210             }
211             *x = false;
212         }
213 
214         let sub = &mut self.data[offset .. offset + payload.len()];
215         sub.copy_from_slice(payload);
216         Ok(())
217     }
218 
219     /// Read is simple.
read(&self, offset: usize, data: &mut [u8]) -> Result<()>220     fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
221         if offset + data.len() > self.data.len() {
222             bail!(ebounds("Read outside of device"));
223         }
224 
225         let sub = &self.data[offset .. offset + data.len()];
226         data.copy_from_slice(sub);
227         Ok(())
228     }
229 
230     /// Adds a new flash bad region. Writes to this area fail with a chance
231     /// given by `rate`.
add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()>232     fn add_bad_region(&mut self, offset: usize, len: usize, rate: f32) -> Result<()> {
233         if !(0.0..=1.0).contains(&rate) {
234             bail!(ebounds("Invalid rate"));
235         }
236 
237         info!("Adding new bad region {:#x}-{:#x}", offset, offset + len);
238         self.bad_region.push((offset, len, rate));
239 
240         Ok(())
241     }
242 
reset_bad_regions(&mut self)243     fn reset_bad_regions(&mut self) {
244         self.bad_region.clear();
245     }
246 
set_verify_writes(&mut self, enable: bool)247     fn set_verify_writes(&mut self, enable: bool) {
248         self.verify_writes = enable;
249     }
250 
251     /// An iterator over each sector in the device.
sector_iter(&self) -> SectorIter<'_>252     fn sector_iter(&self) -> SectorIter<'_> {
253         SectorIter {
254             iter: self.sectors.iter().enumerate(),
255             base: 0,
256         }
257     }
258 
device_size(&self) -> usize259     fn device_size(&self) -> usize {
260         self.data.len()
261     }
262 
align(&self) -> usize263     fn align(&self) -> usize {
264         self.align
265     }
266 
erased_val(&self) -> u8267     fn erased_val(&self) -> u8 {
268         self.erased_val
269     }
270 }
271 
272 /// It is possible to iterate over the sectors in the device, each element returning this.
273 #[derive(Debug, Clone)]
274 pub struct Sector {
275     /// Which sector is this, starting from 0.
276     pub num: usize,
277     /// The offset, in bytes, of the start of this sector.
278     pub base: usize,
279     /// The length, in bytes, of this sector.
280     pub size: usize,
281 }
282 
283 pub struct SectorIter<'a> {
284     iter: Enumerate<slice::Iter<'a, usize>>,
285     base: usize,
286 }
287 
288 impl<'a> Iterator for SectorIter<'a> {
289     type Item = Sector;
290 
next(&mut self) -> Option<Sector>291     fn next(&mut self) -> Option<Sector> {
292         match self.iter.next() {
293             None => None,
294             Some((num, &size)) => {
295                 let base = self.base;
296                 self.base += size;
297                 Some(Sector {
298                     num,
299                     base,
300                     size,
301                 })
302             }
303         }
304     }
305 }
306 
307 #[cfg(test)]
308 mod test {
309     use super::{Flash, FlashError, SimFlash, Result, Sector};
310 
311     #[test]
test_flash()312     fn test_flash() {
313         for &erased_val in &[0, 0xff] {
314             // NXP-style, uniform sectors.
315             let mut f1 = SimFlash::new(vec![4096usize; 256], 1, erased_val);
316             test_device(&mut f1, erased_val);
317 
318             // STM style, non-uniform sectors.
319             let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
320                                     128 * 1024, 128 * 1024, 128 * 1024], 1, erased_val);
321             test_device(&mut f2, erased_val);
322         }
323     }
324 
test_device(flash: &mut dyn Flash, erased_val: u8)325     fn test_device(flash: &mut dyn Flash, erased_val: u8) {
326         let sectors: Vec<Sector> = flash.sector_iter().collect();
327 
328         flash.erase(0, sectors[0].size).unwrap();
329         let flash_size = flash.device_size();
330         flash.erase(0, flash_size).unwrap();
331         assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
332 
333         // Verify that write and erase do something.
334         flash.write(0, &[0x55]).unwrap();
335         let mut buf = [0xAA; 4];
336         flash.read(0, &mut buf).unwrap();
337         assert_eq!(buf, [0x55, erased_val, erased_val, erased_val]);
338 
339         flash.erase(0, sectors[0].size).unwrap();
340         flash.read(0, &mut buf).unwrap();
341         assert_eq!(buf, [erased_val; 4]);
342 
343         // Program the first and last byte of each sector, verify that has been done, and then
344         // erase to verify the erase boundaries.
345         for sector in &sectors {
346             let byte = [(sector.num & 127) as u8];
347             flash.write(sector.base, &byte).unwrap();
348             flash.write(sector.base + sector.size - 1, &byte).unwrap();
349         }
350 
351         // Verify the above
352         let mut buf = Vec::new();
353         for sector in &sectors {
354             let byte = (sector.num & 127) as u8;
355             buf.resize(sector.size, 0);
356             flash.read(sector.base, &mut buf).unwrap();
357             assert_eq!(buf.first(), Some(&byte));
358             assert_eq!(buf.last(), Some(&byte));
359             assert!(buf[1..buf.len()-1].iter().all(|&x| x == erased_val));
360         }
361     }
362 
363     // Helper checks for the result type.
364     trait EChecker {
is_bounds(&self) -> bool365         fn is_bounds(&self) -> bool;
366     }
367 
368     impl<T> EChecker for Result<T> {
369 
is_bounds(&self) -> bool370         fn is_bounds(&self) -> bool {
371             match *self {
372                 Err(FlashError::OutOfBounds(_)) => true,
373                 _ => false,
374             }
375         }
376     }
377 }
378