blob: 5e08f8de32574cbaacd21a928611de18e9161af6 [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
26fn ebounds<T: AsRef<str>>(message: T) -> ErrorKind {
27 ErrorKind::OutOfBounds(message.as_ref().to_owned())
28}
29
30fn ewrite<T: AsRef<str>>(message: T) -> ErrorKind {
31 ErrorKind::Write(message.as_ref().to_owned())
32}
33
34/// An emulated flash device. It is represented as a block of bytes, and a list of the sector
35/// mapings.
36#[derive(Clone)]
37pub struct Flash {
38 data: Vec<u8>,
Marti Bolivar51d36dd2017-05-17 17:39:46 -040039 write_safe: Vec<bool>,
David Brownde7729e2017-01-09 10:41:35 -070040 sectors: Vec<usize>,
David Brown562a7a02017-01-23 11:19:03 -070041 // Alignment required for writes.
42 align: usize,
David Brownde7729e2017-01-09 10:41:35 -070043}
44
45impl Flash {
46 /// Given a sector size map, construct a flash device for that.
David Brown562a7a02017-01-23 11:19:03 -070047 pub fn new(sectors: Vec<usize>, align: usize) -> Flash {
48 // Verify that the alignment is a positive power of two.
49 assert!(align > 0);
50 assert!(align & (align - 1) == 0);
51
David Brownde7729e2017-01-09 10:41:35 -070052 let total = sectors.iter().sum();
53 Flash {
54 data: vec![0xffu8; total],
Marti Bolivar51d36dd2017-05-17 17:39:46 -040055 write_safe: vec![true; total],
David Brownde7729e2017-01-09 10:41:35 -070056 sectors: sectors,
David Brown562a7a02017-01-23 11:19:03 -070057 align: align,
David Brownde7729e2017-01-09 10:41:35 -070058 }
59 }
60
61 /// The flash drivers tend to erase beyond the bounds of the given range. Instead, we'll be
62 /// strict, and make sure that the passed arguments are exactly at a sector boundary, otherwise
63 /// return an error.
64 pub fn erase(&mut self, offset: usize, len: usize) -> Result<()> {
65 let (_start, slen) = self.get_sector(offset).ok_or_else(|| ebounds("start"))?;
66 let (end, elen) = self.get_sector(offset + len - 1).ok_or_else(|| ebounds("end"))?;
67
68 if slen != 0 {
69 bail!(ebounds("offset not at start of sector"));
70 }
71 if elen != self.sectors[end] - 1 {
72 bail!(ebounds("end not at start of sector"));
73 }
74
75 for x in &mut self.data[offset .. offset + len] {
76 *x = 0xff;
77 }
78
Marti Bolivar51d36dd2017-05-17 17:39:46 -040079 for x in &mut self.write_safe[offset .. offset + len] {
80 *x = true;
81 }
82
David Brownde7729e2017-01-09 10:41:35 -070083 Ok(())
84 }
85
Marti Bolivar51d36dd2017-05-17 17:39:46 -040086 /// We restrict to only allowing writes of values that are:
87 ///
88 /// 1. being written to for the first time
89 /// 2. being written to after being erased
90 ///
91 /// This emulates a flash device which starts out erased, with the
92 /// added restriction that repeated writes to the same location
93 /// are disallowed, even if they would be safe to do.
David Brownde7729e2017-01-09 10:41:35 -070094 pub fn write(&mut self, offset: usize, payload: &[u8]) -> Result<()> {
95 if offset + payload.len() > self.data.len() {
David Brownf253fa82017-01-23 15:43:47 -070096 panic!("Write outside of device");
David Brownde7729e2017-01-09 10:41:35 -070097 }
98
David Brown562a7a02017-01-23 11:19:03 -070099 // Verify the alignment (which must be a power of two).
100 if offset & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700101 panic!("Misaligned write address");
David Brown562a7a02017-01-23 11:19:03 -0700102 }
103
104 if payload.len() & (self.align - 1) != 0 {
David Brownf253fa82017-01-23 15:43:47 -0700105 panic!("Write length not multiple of alignment");
David Brown562a7a02017-01-23 11:19:03 -0700106 }
107
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400108 for (i, x) in &mut self.write_safe[offset .. offset + payload.len()].iter_mut().enumerate() {
109 if !(*x) {
Fabio Utzig40b4aa02017-06-28 09:16:19 -0300110 bail!(ewrite(format!("Write to unerased location at 0x{:x}",
111 offset + i)));
Fabio Utzig19b2c1a2017-04-20 07:32:44 -0300112 }
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400113 *x = false;
David Brownde7729e2017-01-09 10:41:35 -0700114 }
115
Marti Bolivar51d36dd2017-05-17 17:39:46 -0400116 let mut sub = &mut self.data[offset .. offset + payload.len()];
David Brownde7729e2017-01-09 10:41:35 -0700117 sub.copy_from_slice(payload);
118 Ok(())
119 }
120
121 /// Read is simple.
122 pub fn read(&self, offset: usize, data: &mut [u8]) -> Result<()> {
123 if offset + data.len() > self.data.len() {
124 bail!(ebounds("Read outside of device"));
125 }
126
127 let sub = &self.data[offset .. offset + data.len()];
128 data.copy_from_slice(sub);
129 Ok(())
130 }
131
132 // Scan the sector map, and return the base and offset within a sector for this given byte.
133 // Returns None if the value is outside of the device.
134 fn get_sector(&self, offset: usize) -> Option<(usize, usize)> {
135 let mut offset = offset;
136 for (sector, &size) in self.sectors.iter().enumerate() {
137 if offset < size {
138 return Some((sector, offset));
139 }
140 offset -= size;
141 }
142 return None;
143 }
144
145 /// An iterator over each sector in the device.
146 pub fn sector_iter(&self) -> SectorIter {
147 SectorIter {
148 iter: self.sectors.iter().enumerate(),
149 base: 0,
150 }
151 }
152
153 pub fn device_size(&self) -> usize {
154 self.data.len()
155 }
156
157 pub fn dump(&self) {
158 self.data.dump();
159 }
David Brown163ab232017-01-23 15:48:35 -0700160
161 /// Dump this image to the given file.
162 pub fn write_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
163 let mut fd = File::create(path).chain_err(|| "Unable to write image file")?;
164 fd.write_all(&self.data).chain_err(|| "Unable to write to image file")?;
165 Ok(())
166 }
David Brownde7729e2017-01-09 10:41:35 -0700167}
168
169/// It is possible to iterate over the sectors in the device, each element returning this.
170#[derive(Debug)]
171pub struct Sector {
172 /// Which sector is this, starting from 0.
173 pub num: usize,
174 /// The offset, in bytes, of the start of this sector.
175 pub base: usize,
176 /// The length, in bytes, of this sector.
177 pub size: usize,
178}
179
180pub struct SectorIter<'a> {
181 iter: Enumerate<slice::Iter<'a, usize>>,
182 base: usize,
183}
184
185impl<'a> Iterator for SectorIter<'a> {
186 type Item = Sector;
187
188 fn next(&mut self) -> Option<Sector> {
189 match self.iter.next() {
190 None => None,
191 Some((num, &size)) => {
192 let base = self.base;
193 self.base += size;
194 Some(Sector {
195 num: num,
196 base: base,
197 size: size,
198 })
199 }
200 }
201 }
202}
203
204#[cfg(test)]
205mod test {
206 use super::{Flash, Error, ErrorKind, Result, Sector};
207
208 #[test]
209 fn test_flash() {
210 // NXP-style, uniform sectors.
211 let mut f1 = Flash::new(vec![4096usize; 256]);
212 test_device(&mut f1);
213
214 // STM style, non-uniform sectors
215 let mut f2 = Flash::new(vec![16 * 1024, 16 * 1024, 16 * 1024, 64 * 1024,
216 128 * 1024, 128 * 1024, 128 * 1024]);
217 test_device(&mut f2);
218 }
219
220 fn test_device(flash: &mut Flash) {
221 let sectors: Vec<Sector> = flash.sector_iter().collect();
222
223 flash.erase(0, sectors[0].size).unwrap();
224 let flash_size = flash.device_size();
225 flash.erase(0, flash_size).unwrap();
226 assert!(flash.erase(0, sectors[0].size - 1).is_bounds());
227
228 // Verify that write and erase do something.
229 flash.write(0, &[0]).unwrap();
230 let mut buf = [0; 4];
231 flash.read(0, &mut buf).unwrap();
232 assert_eq!(buf, [0, 0xff, 0xff, 0xff]);
233
234 flash.erase(0, sectors[0].size).unwrap();
235 flash.read(0, &mut buf).unwrap();
236 assert_eq!(buf, [0xff; 4]);
237
238 // Program the first and last byte of each sector, verify that has been done, and then
239 // erase to verify the erase boundaries.
240 for sector in &sectors {
241 let byte = [(sector.num & 127) as u8];
242 flash.write(sector.base, &byte).unwrap();
243 flash.write(sector.base + sector.size - 1, &byte).unwrap();
244 }
245
246 // Verify the above
247 let mut buf = Vec::new();
248 for sector in &sectors {
249 let byte = (sector.num & 127) as u8;
250 buf.resize(sector.size, 0);
251 flash.read(sector.base, &mut buf).unwrap();
252 assert_eq!(buf.first(), Some(&byte));
253 assert_eq!(buf.last(), Some(&byte));
254 assert!(buf[1..buf.len()-1].iter().all(|&x| x == 0xff));
255 }
256 }
257
258 // Helper checks for the result type.
259 trait EChecker {
260 fn is_bounds(&self) -> bool;
261 }
262
263 impl<T> EChecker for Result<T> {
264
265 fn is_bounds(&self) -> bool {
266 match *self {
267 Err(Error(ErrorKind::OutOfBounds(_), _)) => true,
268 _ => false,
269 }
270 }
271 }
272}