blob: 779157a3b6c378cdd906cd23ac030e0cfdc75ee5 [file] [log] [blame]
David Brownde7729e2017-01-09 10:41:35 -07001//! Describe flash areas.
2
David Brown2cbc4702017-07-06 14:18:58 -06003use simflash::{Flash, SimFlash, Sector};
David Brownde7729e2017-01-09 10:41:35 -07004use std::ptr;
Fabio Utzig1caef132018-10-26 15:40:53 -03005use std::collections::HashMap;
David Brownde7729e2017-01-09 10:41:35 -07006
7/// Structure to build up the boot area table.
David Brown3f687dc2017-11-06 13:41:18 -07008#[derive(Debug, Clone)]
David Brownde7729e2017-01-09 10:41:35 -07009pub struct AreaDesc {
10 areas: Vec<Vec<FlashArea>>,
11 whole: Vec<FlashArea>,
Fabio Utzig1caef132018-10-26 15:40:53 -030012 sectors: HashMap<u8, Vec<Sector>>,
David Brownde7729e2017-01-09 10:41:35 -070013}
14
15impl AreaDesc {
Fabio Utzig1caef132018-10-26 15:40:53 -030016 pub fn new() -> AreaDesc {
David Brownde7729e2017-01-09 10:41:35 -070017 AreaDesc {
18 areas: vec![],
19 whole: vec![],
Fabio Utzig1caef132018-10-26 15:40:53 -030020 sectors: HashMap::new(),
David Brownde7729e2017-01-09 10:41:35 -070021 }
22 }
23
Fabio Utzig1caef132018-10-26 15:40:53 -030024 pub fn add_flash_sectors(&mut self, id: u8, flash: &SimFlash) {
25 self.sectors.insert(id, flash.sector_iter().collect());
26 }
27
David Brownde7729e2017-01-09 10:41:35 -070028 /// Add a slot to the image. The slot must align with erasable units in the flash device.
29 /// Panics if the description is not valid. There are also bootloader assumptions that the
David Vincze2d736ad2019-02-18 11:50:22 +010030 /// slots are PRIMARY_SLOT, SECONDARY_SLOT, and SCRATCH in that order.
Fabio Utzig1caef132018-10-26 15:40:53 -030031 pub fn add_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
David Brownde7729e2017-01-09 10:41:35 -070032 let nid = id as usize;
33 let orig_base = base;
34 let orig_len = len;
35 let mut base = base;
36 let mut len = len;
37
38 while nid > self.areas.len() {
39 self.areas.push(vec![]);
40 self.whole.push(Default::default());
41 }
42
43 if nid != self.areas.len() {
44 panic!("Flash areas not added in order");
45 }
46
47 let mut area = vec![];
48
Fabio Utzig1caef132018-10-26 15:40:53 -030049 for sector in &self.sectors[&dev_id] {
David Brownde7729e2017-01-09 10:41:35 -070050 if len == 0 {
51 break;
52 };
53 if base > sector.base + sector.size - 1 {
54 continue;
55 }
56 if sector.base != base {
57 panic!("Image does not start on a sector boundary");
58 }
59
60 area.push(FlashArea {
61 flash_id: id,
Fabio Utzig1caef132018-10-26 15:40:53 -030062 device_id: dev_id,
David Brownde7729e2017-01-09 10:41:35 -070063 pad16: 0,
64 off: sector.base as u32,
65 size: sector.size as u32,
66 });
67
68 base += sector.size;
69 len -= sector.size;
70 }
71
72 if len != 0 {
73 panic!("Image goes past end of device");
74 }
75
76 self.areas.push(area);
77 self.whole.push(FlashArea {
78 flash_id: id,
Fabio Utzig1caef132018-10-26 15:40:53 -030079 device_id: dev_id,
David Brownde7729e2017-01-09 10:41:35 -070080 pad16: 0,
81 off: orig_base as u32,
82 size: orig_len as u32,
83 });
84 }
85
David Brown90c19132017-01-23 10:21:28 -070086 // Add a simple slot to the image. This ignores the device layout, and just adds the area as a
87 // single unit. It assumes that the image lines up with image boundaries. This tests
88 // configurations where the partition table uses larger sectors than the underlying flash
89 // device.
Fabio Utzig1caef132018-10-26 15:40:53 -030090 pub fn add_simple_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
David Brown90c19132017-01-23 10:21:28 -070091 let area = vec![FlashArea {
92 flash_id: id,
Fabio Utzig1caef132018-10-26 15:40:53 -030093 device_id: dev_id,
David Brown90c19132017-01-23 10:21:28 -070094 pad16: 0,
95 off: base as u32,
96 size: len as u32,
97 }];
98
99 self.areas.push(area);
100 self.whole.push(FlashArea {
101 flash_id: id,
Fabio Utzig1caef132018-10-26 15:40:53 -0300102 device_id: dev_id,
David Brown90c19132017-01-23 10:21:28 -0700103 pad16: 0,
104 off: base as u32,
105 size: len as u32,
106 });
107 }
108
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200109 // Look for the image with the given ID, and return its offset, size and
David Brown06ef06e2019-03-05 12:28:10 -0700110 // device id. Returns None if the area is not present.
111 pub fn find(&self, id: FlashId) -> Option<(usize, usize, u8)> {
David Brown5c6b6792017-03-20 12:51:28 -0600112 for area in &self.whole {
Fabio Utzig1caef132018-10-26 15:40:53 -0300113 // FIXME: should we ensure id is not duplicated over multiple devices?
David Brown5c6b6792017-03-20 12:51:28 -0600114 if area.flash_id == id {
David Brown06ef06e2019-03-05 12:28:10 -0700115 return Some((area.off as usize, area.size as usize, area.device_id));
David Brown5c6b6792017-03-20 12:51:28 -0600116 }
117 }
David Brown06ef06e2019-03-05 12:28:10 -0700118 None
David Brown5c6b6792017-03-20 12:51:28 -0600119 }
120
David Brownde7729e2017-01-09 10:41:35 -0700121 pub fn get_c(&self) -> CAreaDesc {
122 let mut areas: CAreaDesc = Default::default();
123
124 assert_eq!(self.areas.len(), self.whole.len());
125
126 for (i, area) in self.areas.iter().enumerate() {
127 if area.len() > 0 {
128 areas.slots[i].areas = &area[0];
129 areas.slots[i].whole = self.whole[i].clone();
130 areas.slots[i].num_areas = area.len() as u32;
131 areas.slots[i].id = area[0].flash_id;
132 }
133 }
134
135 areas.num_slots = self.areas.len() as u32;
136
137 areas
138 }
David Brown297029a2019-08-13 14:29:51 -0600139
140 /// Return an iterator over all `FlashArea`s present.
141 pub fn iter_areas(&self) -> impl Iterator<Item = &FlashArea> {
142 self.whole.iter()
143 }
David Brownde7729e2017-01-09 10:41:35 -0700144}
145
146/// The area descriptor, C format.
147#[repr(C)]
148#[derive(Debug, Default)]
David Brown0daa36c2017-03-07 12:08:27 +0100149pub struct CAreaDesc {
150 slots: [CArea; 16],
David Brownde7729e2017-01-09 10:41:35 -0700151 num_slots: u32,
152}
153
154#[repr(C)]
155#[derive(Debug)]
David Brown0daa36c2017-03-07 12:08:27 +0100156pub struct CArea {
David Brownde7729e2017-01-09 10:41:35 -0700157 whole: FlashArea,
158 areas: *const FlashArea,
159 num_areas: u32,
Fabio Utzig1caef132018-10-26 15:40:53 -0300160 // FIXME: is this not already available on whole/areas?
David Brownde7729e2017-01-09 10:41:35 -0700161 id: FlashId,
David Brownde7729e2017-01-09 10:41:35 -0700162}
163
David Brown0daa36c2017-03-07 12:08:27 +0100164impl Default for CArea {
165 fn default() -> CArea {
David Brownde7729e2017-01-09 10:41:35 -0700166 CArea {
167 areas: ptr::null(),
168 whole: Default::default(),
169 id: FlashId::BootLoader,
170 num_areas: 0,
David Brownde7729e2017-01-09 10:41:35 -0700171 }
172 }
173}
174
175/// Flash area map.
176#[repr(u8)]
177#[derive(Copy, Clone, Debug, Eq, PartialEq)]
178#[allow(dead_code)]
179pub enum FlashId {
180 BootLoader = 0,
181 Image0 = 1,
182 Image1 = 2,
183 ImageScratch = 3,
David Brown06ef06e2019-03-05 12:28:10 -0700184 Image2 = 4,
185 Image3 = 5,
David Brownde7729e2017-01-09 10:41:35 -0700186}
187
188impl Default for FlashId {
189 fn default() -> FlashId {
190 FlashId::BootLoader
191 }
192}
193
194#[repr(C)]
195#[derive(Debug, Clone, Default)]
196pub struct FlashArea {
David Brown297029a2019-08-13 14:29:51 -0600197 pub flash_id: FlashId,
198 pub device_id: u8,
David Brownde7729e2017-01-09 10:41:35 -0700199 pad16: u16,
David Brown297029a2019-08-13 14:29:51 -0600200 pub off: u32,
201 pub size: u32,
David Brownde7729e2017-01-09 10:41:35 -0700202}