blob: 98b6a27b556a9e3b7668c22e413e68c8478c5de5 [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 Brown163ab232017-01-23 15:48:35 -07006use std::fs::File;
7use std::io::Write;
David Brownde7729e2017-01-09 10:41:35 -07008use std::iter::Enumerate;
David Brown163ab232017-01-23 15:48:35 -07009use std::path::Path;
David Brownde7729e2017-01-09 10:41:35 -070010use std::slice;
11use pdump::HexDump;
12
13error_chain! {
14 errors {
15 OutOfBounds(t: String) {
16 description("Offset is out of bounds")
17 display("Offset out of bounds: {}", t)
18 }
19 Write(t: String) {
20 description("Invalid write")
21 display("Invalid write: {}", t)
22 }
23 }
24}
25
David Brown7ddec0b2017-07-06 10:47:35 -060026pub trait Flash {
27 fn erase(&mut self, offset: usize, len: usize) -> Result<()>;
28 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()>;
29 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()>;
30
31 fn sector_iter(&self) -> SectorIter;
32 fn device_size(&self) -> usize;
33}
34
David Brownde7729e2017-01-09 10:41:35 -070035fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
36 ErrorKind::OutOfBounds(message.as_ref().to_owned())
37}
38
39fn ewrite<T: AsRef<str>>(message: T) -> ErrorKind {
40 ErrorKind::Write(message.as_ref().to_owned())
41}
42
43/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
44/// mapings.
45#[derive(Clone)]
David Brown7ddec0b2017-07-06 10:47:35 -060046pub struct SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070047 data: Vec<u8>,
Marti Bolivar51d36dd2017-05-17 17:39:46 -040048 write_safe: Vec<bool>,
David Brownde7729e2017-01-09 10:41:35 -070049 sectors: Vec<usize>,
David Brown562a7a02017-01-23 11:19:03 -070050 // Alignment required for writes.
51 align: usize,
David Brownde7729e2017-01-09 10:41:35 -070052}
53
David Brown7ddec0b2017-07-06 10:47:35 -060054impl SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070055 /// Given a sector size map, construct a flash device for that.
David Brown7ddec0b2017-07-06 10:47:35 -060056 pub fn new(sectors: Vec<usize>, align: usize) -> SimFlash {
David Brown562a7a02017-01-23 11:19:03 -070057 // Verify that the alignment is a positive power of two.
58 assert!(align > 0);
59 assert!(align & (align - 1) == 0);
60
David Brownde7729e2017-01-09 10:41:35 -070061 let total = sectors.iter().sum();
David Brown7ddec0b2017-07-06 10:47:35 -060062 SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070063 data: vec![0xffu8; total],
Marti Bolivar51d36dd2017-05-17 17:39:46 -040064 write_safe: vec![true; total],
David Brownde7729e2017-01-09 10:41:35 -070065 sectors: sectors,
David Brown562a7a02017-01-23 11:19:03 -070066 align: align,
David Brownde7729e2017-01-09 10:41:35 -070067 }
68 }
69
David Brown7ddec0b2017-07-06 10:47:35 -060070 #[allow(dead_code)]
71 pub fn dump(&self) {
72 self.data.dump();
73 }
74
75 /// Dump this image to the given file.
76 #[allow(dead_code)]
77 pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
78 let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
79 fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
80 Ok(())
81 }
82
83 // Scan the sector map, and return the base and offset within a sector for this given byte.
84 // Returns None if the value is outside of the device.
85 fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
86 let mut offset = offset;
87 for (sector, &size) in self.sectors.iter().enumerate() {
88 if offset < size {
89 return Some((sector, offset));
90 }
91 offset -= size;
92 }
93 return None;
94 }
95
96}
97
98impl Flash for SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070099 /// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
100 /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
101 /// return an error.
David Brown7ddec0b2017-07-06 10:47:35 -0600102 fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700103 let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
104 let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
105
106 if slen != 0 {
107 bail!(ebounds("offset not at start of sector"));
108 }
109 if elen != self.sectors[end] - 1 {
110 bail!(ebounds("end not at start of sector"));
111 }
112
113 for x in &mut self.data[offset .. offset + len] {
114 *x = 0xff;
115 }
116
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400117 for x in &mut self.write_safe[offset .. offset + len] {
118 *x = true;
119 }
120
David Brownde7729e2017-01-09 10:41:35 -0700121 Ok(())
122 }
123
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400124 /// We restrict to only allowing writes of values that are:
125 ///
126 /// 1. being written to for the first time
127 /// 2. being written to after being erased
128 ///
129 /// This emulates a flash device which starts out erased, with the
130 /// added restriction that repeated writes to the same location
131 /// are disallowed, even if they would be safe to do.
David Brown7ddec0b2017-07-06 10:47:35 -0600132 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700133 if offset + payload.len() > self.data.len() {
David Brownf253fa82017-01-23 15:43:47 -0700134 panic!("Write outside of device");
David Brownde7729e2017-01-09 10:41:35 -0700135 }
136
David Brown562a7a02017-01-23 11:19:03 -0700137 // Verify the alignment (which must be a power of two).
138 if offset & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700139 panic!("Misaligned write address");
David Brown562a7a02017-01-23 11:19:03 -0700140 }
141
142 if payload.len() & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700143 panic!("Write length not multiple of alignment");
David Brown562a7a02017-01-23 11:19:03 -0700144 }
145
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400146 for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
147 if !(*x) {
Fabio Utzig40b4aa02017-06-28 09:16:19 -0300148 bail!(ewrite(format!("Write to unerased location at 0x{:x}",
149 offset + i)));
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300150 }
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400151 *x = false;
David Brownde7729e2017-01-09 10:41:35 -0700152 }
153
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400154 let mut sub = &mut self.data[offset .. offset + payload.len()];
David Brownde7729e2017-01-09 10:41:35 -0700155 sub.copy_from_slice(payload);
156 Ok(())
157 }
158
159 /// Read is simple.
David Brown7ddec0b2017-07-06 10:47:35 -0600160 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700161 if offset + data.len() > self.data.len() {
162 bail!(ebounds("Read outside of device"));
163 }
164
165 let sub = &self.data[offset .. offset + data.len()];
166 data.copy_from_slice(sub);
167 Ok(())
168 }
169
David Brownde7729e2017-01-09 10:41:35 -0700170 /// An iterator over each sector in the device.
David Brown7ddec0b2017-07-06 10:47:35 -0600171 fn sector_iter(&self) -> SectorIter {
David Brownde7729e2017-01-09 10:41:35 -0700172 SectorIter {
173 iter: self.sectors.iter().enumerate(),
174 base: 0,
175 }
176 }
177
David Brown7ddec0b2017-07-06 10:47:35 -0600178 fn device_size(&self) -> usize {
David Brownde7729e2017-01-09 10:41:35 -0700179 self.data.len()
180 }
David Brownde7729e2017-01-09 10:41:35 -0700181}
182
183/// It is possible to iterate over the sectors in the device, each element returning this.
184#[derive(Debug)]
185pub struct Sector {
186 /// Which sector is this, starting from 0.
187 pub num: usize,
188 /// The offset, in bytes, of the start of this sector.
189 pub base: usize,
190 /// The length, in bytes, of this sector.
191 pub size: usize,
192}
193
194pub struct SectorIter<'a> {
195 iter: Enumerate<slice::Iter<'a, usize>>,
196 base: usize,
197}
198
199impl<'a> Iterator for SectorIter<'a> {
200 type Item = Sector;
201
202 fn next(&mut self) -> Option<Sector> {
203 match self.iter.next() {
204 None => None,
205 Some((num, &size)) => {
206 let base = self.base;
207 self.base += size;
208 Some(Sector {
209 num: num,
210 base: base,
211 size: size,
212 })
213 }
214 }
215 }
216}
217
218#[cfg(test)]
219mod test {
David Brown7ddec0b2017-07-06 10:47:35 -0600220 use super::{Flash, SimFlash, Error, ErrorKind, Result, Sector};
David Brownde7729e2017-01-09 10:41:35 -0700221
222 #[test]
223 fn test_flash() {
224 // NXP-style, uniform sectors.
David Brown7ddec0b2017-07-06 10:47:35 -0600225 let mut f1 = SimFlash::new(vec![4096usize; 256], 1);
David Brownde7729e2017-01-09 10:41:35 -0700226 test_device(&mut f1);
227
228 // STM style, non-uniform sectors
David Brown7ddec0b2017-07-06 10:47:35 -0600229 let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
230 128 * 1024, 128 * 1024, 128 * 1024], 1);
David Brownde7729e2017-01-09 10:41:35 -0700231 test_device(&mut f2);
232 }
233
234 fn test_device(flash: &mut Flash) {
235 let sectors: Vec<Sector> = flash.sector_iter().collect();
236
237 flash.erase(0, sectors[0].size).unwrap();
238 let flash_size = flash.device_size();
239 flash.erase(0, flash_size).unwrap();
240 assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
241
242 // Verify that write and erase do something.
243 flash.write(0, &[0]).unwrap();
244 let mut buf = [0; 4];
245 flash.read(0, &mut buf).unwrap();
246 assert_eq!(buf, [0, 0xff, 0xff, 0xff]);
247
248 flash.erase(0, sectors[0].size).unwrap();
249 flash.read(0, &mut buf).unwrap();
250 assert_eq!(buf, [0xff; 4]);
251
252 // Program the first and last byte of each sector, verify that has been done, and then
253 // erase to verify the erase boundaries.
254 for sector in &sectors {
255 let byte = [(sector.num & 127) as u8];
256 flash.write(sector.base, &byte).unwrap();
257 flash.write(sector.base + sector.size - 1, &byte).unwrap();
258 }
259
260 // Verify the above
261 let mut buf = Vec::new();
262 for sector in &sectors {
263 let byte = (sector.num & 127) as u8;
264 buf.resize(sector.size, 0);
265 flash.read(sector.base, &mut buf).unwrap();
266 assert_eq!(buf.first(), Some(&byte));
267 assert_eq!(buf.last(), Some(&byte));
268 assert!(buf[1..buf.len()-1].iter().all(|&x| x == 0xff));
269 }
270 }
271
272 // Helper checks for the result type.
273 trait EChecker {
274 fn is_bounds(&self) -> bool;
275 }
276
277 impl<T> EChecker for Result<T> {
278
279 fn is_bounds(&self) -> bool {
280 match *self {
281 Err(Error(ErrorKind::OutOfBounds(_), _)) => true,
282 _ => false,
283 }
284 }
285 }
286}