blob: 56835955345285057aa4e4f847d3b15e97dfc2f7 [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 Brown163ab232017-01-23 15:48:35 -07009use std::fs::File;
10use std::io::Write;
David Brownde7729e2017-01-09 10:41:35 -070011use std::iter::Enumerate;
David Brown163ab232017-01-23 15:48:35 -070012use std::path::Path;
David Brownde7729e2017-01-09 10:41:35 -070013use std::slice;
14use pdump::HexDump;
15
16error_chain! {
17 errors {
18 OutOfBounds(t: String) {
19 description("Offset is out of bounds")
20 display("Offset out of bounds: {}", t)
21 }
22 Write(t: String) {
23 description("Invalid write")
24 display("Invalid write: {}", t)
25 }
26 }
27}
28
David Brown7ddec0b2017-07-06 10:47:35 -060029pub trait Flash {
30 fn erase(&mut self, offset: usize, len: usize) -> Result<()>;
31 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()>;
32 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()>;
33
34 fn sector_iter(&self) -> SectorIter;
35 fn device_size(&self) -> usize;
36}
37
David Brownde7729e2017-01-09 10:41:35 -070038fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
39 ErrorKind::OutOfBounds(message.as_ref().to_owned())
40}
41
Fabio Utzig65935d72017-07-17 15:34:36 -030042#[allow(dead_code)]
David Brownde7729e2017-01-09 10:41:35 -070043fn ewrite<T: AsRef<str>>(message: T) -> ErrorKind {
44 ErrorKind::Write(message.as_ref().to_owned())
45}
46
47/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
48/// mapings.
49#[derive(Clone)]
David Brown7ddec0b2017-07-06 10:47:35 -060050pub struct SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070051 data: Vec<u8>,
Marti Bolivar51d36dd2017-05-17 17:39:46 -040052 write_safe: Vec<bool>,
David Brownde7729e2017-01-09 10:41:35 -070053 sectors: Vec<usize>,
David Brown562a7a02017-01-23 11:19:03 -070054 // Alignment required for writes.
55 align: usize,
David Brownde7729e2017-01-09 10:41:35 -070056}
57
David Brown7ddec0b2017-07-06 10:47:35 -060058impl SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070059 /// Given a sector size map, construct a flash device for that.
David Brown7ddec0b2017-07-06 10:47:35 -060060 pub fn new(sectors: Vec<usize>, align: usize) -> SimFlash {
David Brown562a7a02017-01-23 11:19:03 -070061 // Verify that the alignment is a positive power of two.
62 assert!(align > 0);
63 assert!(align & (align - 1) == 0);
64
David Brownde7729e2017-01-09 10:41:35 -070065 let total = sectors.iter().sum();
David Brown7ddec0b2017-07-06 10:47:35 -060066 SimFlash {
David Brownde7729e2017-01-09 10:41:35 -070067 data: vec![0xffu8; total],
Marti Bolivar51d36dd2017-05-17 17:39:46 -040068 write_safe: vec![true; total],
David Brownde7729e2017-01-09 10:41:35 -070069 sectors: sectors,
David Brown562a7a02017-01-23 11:19:03 -070070 align: align,
David Brownde7729e2017-01-09 10:41:35 -070071 }
72 }
73
David Brown7ddec0b2017-07-06 10:47:35 -060074 #[allow(dead_code)]
75 pub fn dump(&self) {
76 self.data.dump();
77 }
78
79 /// Dump this image to the given file.
80 #[allow(dead_code)]
81 pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
82 let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
83 fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
84 Ok(())
85 }
86
87 // Scan the sector map, and return the base and offset within a sector for this given byte.
88 // Returns None if the value is outside of the device.
89 fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
90 let mut offset = offset;
91 for (sector, &size) in self.sectors.iter().enumerate() {
92 if offset < size {
93 return Some((sector, offset));
94 }
95 offset -= size;
96 }
97 return None;
98 }
99
100}
101
102impl Flash for SimFlash {
David Brownde7729e2017-01-09 10:41:35 -0700103 /// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
104 /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
105 /// return an error.
David Brown7ddec0b2017-07-06 10:47:35 -0600106 fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700107 let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
108 let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
109
110 if slen != 0 {
111 bail!(ebounds("offset not at start of sector"));
112 }
113 if elen != self.sectors[end] - 1 {
114 bail!(ebounds("end not at start of sector"));
115 }
116
117 for x in &mut self.data[offset .. offset + len] {
118 *x = 0xff;
119 }
120
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400121 for x in &mut self.write_safe[offset .. offset + len] {
122 *x = true;
123 }
124
David Brownde7729e2017-01-09 10:41:35 -0700125 Ok(())
126 }
127
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400128 /// We restrict to only allowing writes of values that are:
129 ///
130 /// 1. being written to for the first time
131 /// 2. being written to after being erased
132 ///
133 /// This emulates a flash device which starts out erased, with the
134 /// added restriction that repeated writes to the same location
135 /// are disallowed, even if they would be safe to do.
David Brown7ddec0b2017-07-06 10:47:35 -0600136 fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700137 if offset + payload.len() > self.data.len() {
David Brownf253fa82017-01-23 15:43:47 -0700138 panic!("Write outside of device");
David Brownde7729e2017-01-09 10:41:35 -0700139 }
140
David Brown562a7a02017-01-23 11:19:03 -0700141 // Verify the alignment (which must be a power of two).
142 if offset & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700143 panic!("Misaligned write address");
David Brown562a7a02017-01-23 11:19:03 -0700144 }
145
146 if payload.len() & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700147 panic!("Write length not multiple of alignment");
David Brown562a7a02017-01-23 11:19:03 -0700148 }
149
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400150 for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
151 if !(*x) {
Fabio Utzig65935d72017-07-17 15:34:36 -0300152 panic!("Write to unerased location at 0x{:x}", offset + i);
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300153 }
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400154 *x = false;
David Brownde7729e2017-01-09 10:41:35 -0700155 }
156
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400157 let mut sub = &mut self.data[offset .. offset + payload.len()];
David Brownde7729e2017-01-09 10:41:35 -0700158 sub.copy_from_slice(payload);
159 Ok(())
160 }
161
162 /// Read is simple.
David Brown7ddec0b2017-07-06 10:47:35 -0600163 fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
David Brownde7729e2017-01-09 10:41:35 -0700164 if offset + data.len() > self.data.len() {
165 bail!(ebounds("Read outside of device"));
166 }
167
168 let sub = &self.data[offset .. offset + data.len()];
169 data.copy_from_slice(sub);
170 Ok(())
171 }
172
David Brownde7729e2017-01-09 10:41:35 -0700173 /// An iterator over each sector in the device.
David Brown7ddec0b2017-07-06 10:47:35 -0600174 fn sector_iter(&self) -> SectorIter {
David Brownde7729e2017-01-09 10:41:35 -0700175 SectorIter {
176 iter: self.sectors.iter().enumerate(),
177 base: 0,
178 }
179 }
180
David Brown7ddec0b2017-07-06 10:47:35 -0600181 fn device_size(&self) -> usize {
David Brownde7729e2017-01-09 10:41:35 -0700182 self.data.len()
183 }
David Brownde7729e2017-01-09 10:41:35 -0700184}
185
186/// It is possible to iterate over the sectors in the device, each element returning this.
187#[derive(Debug)]
188pub struct Sector {
189 /// Which sector is this, starting from 0.
190 pub num: usize,
191 /// The offset, in bytes, of the start of this sector.
192 pub base: usize,
193 /// The length, in bytes, of this sector.
194 pub size: usize,
195}
196
197pub struct SectorIter<'a> {
198 iter: Enumerate<slice::Iter<'a, usize>>,
199 base: usize,
200}
201
202impl<'a> Iterator for SectorIter<'a> {
203 type Item = Sector;
204
205 fn next(&mut self) -> Option<Sector> {
206 match self.iter.next() {
207 None => None,
208 Some((num, &size)) => {
209 let base = self.base;
210 self.base += size;
211 Some(Sector {
212 num: num,
213 base: base,
214 size: size,
215 })
216 }
217 }
218 }
219}
220
221#[cfg(test)]
222mod test {
David Brown7ddec0b2017-07-06 10:47:35 -0600223 use super::{Flash, SimFlash, Error, ErrorKind, Result, Sector};
David Brownde7729e2017-01-09 10:41:35 -0700224
225 #[test]
226 fn test_flash() {
227 // NXP-style, uniform sectors.
David Brown7ddec0b2017-07-06 10:47:35 -0600228 let mut f1 = SimFlash::new(vec![4096usize; 256], 1);
David Brownde7729e2017-01-09 10:41:35 -0700229 test_device(&mut f1);
230
231 // STM style, non-uniform sectors
David Brown7ddec0b2017-07-06 10:47:35 -0600232 let mut f2 = SimFlash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
233 128 * 1024, 128 * 1024, 128 * 1024], 1);
David Brownde7729e2017-01-09 10:41:35 -0700234 test_device(&mut f2);
235 }
236
237 fn test_device(flash: &mut Flash) {
238 let sectors: Vec<Sector> = flash.sector_iter().collect();
239
240 flash.erase(0, sectors[0].size).unwrap();
241 let flash_size = flash.device_size();
242 flash.erase(0, flash_size).unwrap();
243 assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
244
245 // Verify that write and erase do something.
246 flash.write(0, &[0]).unwrap();
247 let mut buf = [0; 4];
248 flash.read(0, &mut buf).unwrap();
249 assert_eq!(buf, [0, 0xff, 0xff, 0xff]);
250
251 flash.erase(0, sectors[0].size).unwrap();
252 flash.read(0, &mut buf).unwrap();
253 assert_eq!(buf, [0xff; 4]);
254
255 // Program the first and last byte of each sector, verify that has been done, and then
256 // erase to verify the erase boundaries.
257 for sector in &sectors {
258 let byte = [(sector.num & 127) as u8];
259 flash.write(sector.base, &byte).unwrap();
260 flash.write(sector.base + sector.size - 1, &byte).unwrap();
261 }
262
263 // Verify the above
264 let mut buf = Vec::new();
265 for sector in &sectors {
266 let byte = (sector.num & 127) as u8;
267 buf.resize(sector.size, 0);
268 flash.read(sector.base, &mut buf).unwrap();
269 assert_eq!(buf.first(), Some(&byte));
270 assert_eq!(buf.last(), Some(&byte));
271 assert!(buf[1..buf.len()-1].iter().all(|&x| x == 0xff));
272 }
273 }
274
275 // Helper checks for the result type.
276 trait EChecker {
277 fn is_bounds(&self) -> bool;
278 }
279
280 impl<T> EChecker for Result<T> {
281
282 fn is_bounds(&self) -> bool {
283 match *self {
284 Err(Error(ErrorKind::OutOfBounds(_), _)) => true,
285 _ => false,
286 }
287 }
288 }
289}