1 // Copyright (c) 2017-2021 Linaro LTD
2 // Copyright (c) 2018-2019 JUUL Labs
3 // Copyright (c) 2019 Arm Limited
4 //
5 // SPDX-License-Identifier: Apache-2.0
6 
7 //! Describe flash areas.
8 
9 use simflash::{Flash, SimFlash, Sector};
10 use std::ptr;
11 use std::collections::HashMap;
12 
13 /// Structure to build up the boot area table.
14 #[derive(Debug, Default, Clone)]
15 pub struct AreaDesc {
16     areas: Vec<Vec<FlashArea>>,
17     whole: Vec<FlashArea>,
18     sectors: HashMap<u8, Vec<Sector>>,
19 }
20 
21 impl AreaDesc {
new() -> AreaDesc22     pub fn new() -> AreaDesc {
23         AreaDesc {
24             areas: vec![],
25             whole: vec![],
26             sectors: HashMap::new(),
27         }
28     }
29 
add_flash_sectors(&mut self, id: u8, flash: &SimFlash)30     pub fn add_flash_sectors(&mut self, id: u8, flash: &SimFlash) {
31         self.sectors.insert(id, flash.sector_iter().collect());
32     }
33 
34     /// Add a slot to the image.  The slot must align with erasable units in the flash device.
35     /// Panics if the description is not valid.  There are also bootloader assumptions that the
36     /// slots are PRIMARY_SLOT, SECONDARY_SLOT, and SCRATCH in that order.
add_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8)37     pub fn add_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
38         let nid = id as usize;
39         let orig_base = base;
40         let orig_len = len;
41         let mut base = base;
42         let mut len = len;
43 
44         while nid > self.areas.len() {
45             self.areas.push(vec![]);
46             self.whole.push(Default::default());
47         }
48 
49         if nid != self.areas.len() {
50             panic!("Flash areas not added in order");
51         }
52 
53         let mut area = vec![];
54 
55         for sector in &self.sectors[&dev_id] {
56             if len == 0 {
57                 break;
58             };
59             if base > sector.base + sector.size - 1 {
60                 continue;
61             }
62             if sector.base != base {
63                 panic!("Image does not start on a sector boundary");
64             }
65 
66             area.push(FlashArea {
67                 flash_id: id,
68                 device_id: dev_id,
69                 pad16: 0,
70                 off: sector.base as u32,
71                 size: sector.size as u32,
72             });
73 
74             base += sector.size;
75             len -= sector.size;
76         }
77 
78         if len != 0 {
79             panic!("Image goes past end of device");
80         }
81 
82         self.areas.push(area);
83         self.whole.push(FlashArea {
84             flash_id: id,
85             device_id: dev_id,
86             pad16: 0,
87             off: orig_base as u32,
88             size: orig_len as u32,
89         });
90     }
91 
92     // Add a simple slot to the image.  This ignores the device layout, and just adds the area as a
93     // single unit.  It assumes that the image lines up with image boundaries.  This tests
94     // configurations where the partition table uses larger sectors than the underlying flash
95     // device.
add_simple_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8)96     pub fn add_simple_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
97         let area = vec![FlashArea {
98             flash_id: id,
99             device_id: dev_id,
100             pad16: 0,
101             off: base as u32,
102             size: len as u32,
103         }];
104 
105         self.areas.push(area);
106         self.whole.push(FlashArea {
107             flash_id: id,
108             device_id: dev_id,
109             pad16: 0,
110             off: base as u32,
111             size: len as u32,
112         });
113     }
114 
115     // Look for the image with the given ID, and return its offset, size and
116     // device id. Returns None if the area is not present.
find(&self, id: FlashId) -> Option<(usize, usize, u8)>117     pub fn find(&self, id: FlashId) -> Option<(usize, usize, u8)> {
118         for area in &self.whole {
119             // FIXME: should we ensure id is not duplicated over multiple devices?
120             if area.flash_id == id {
121                 return Some((area.off as usize, area.size as usize, area.device_id));
122             }
123         }
124         None
125     }
126 
get_c(&self) -> CAreaDesc127     pub fn get_c(&self) -> CAreaDesc {
128         let mut areas: CAreaDesc = Default::default();
129 
130         assert_eq!(self.areas.len(), self.whole.len());
131 
132         for (i, area) in self.areas.iter().enumerate() {
133             if !area.is_empty() {
134                 areas.slots[i].areas = &area[0];
135                 areas.slots[i].whole = self.whole[i].clone();
136                 areas.slots[i].num_areas = area.len() as u32;
137                 areas.slots[i].id = area[0].flash_id;
138             }
139         }
140 
141         areas.num_slots = self.areas.len() as u32;
142 
143         areas
144     }
145 
146     /// Return an iterator over all `FlashArea`s present.
iter_areas(&self) -> impl Iterator<Item = &FlashArea>147     pub fn iter_areas(&self) -> impl Iterator<Item = &FlashArea> {
148         self.whole.iter()
149     }
150 }
151 
152 /// The area descriptor, C format.
153 #[repr(C)]
154 #[derive(Debug, Default)]
155 pub struct CAreaDesc {
156     slots: [CArea; 16],
157     num_slots: u32,
158 }
159 
160 #[repr(C)]
161 #[derive(Debug)]
162 pub struct CArea {
163     whole: FlashArea,
164     areas: *const FlashArea,
165     num_areas: u32,
166     // FIXME: is this not already available on whole/areas?
167     id: FlashId,
168 }
169 
170 impl Default for CArea {
default() -> CArea171     fn default() -> CArea {
172         CArea {
173             areas: ptr::null(),
174             whole: Default::default(),
175             id: FlashId::BootLoader,
176             num_areas: 0,
177         }
178     }
179 }
180 
181 /// Flash area map.
182 #[repr(u8)]
183 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
184 #[allow(dead_code)]
185 pub enum FlashId {
186     BootLoader = 0,
187     Image0 = 1,
188     Image1 = 2,
189     ImageScratch = 3,
190     Image2 = 4,
191     Image3 = 5,
192 }
193 
194 impl Default for FlashId {
default() -> FlashId195     fn default() -> FlashId {
196         FlashId::BootLoader
197     }
198 }
199 
200 #[repr(C)]
201 #[derive(Debug, Clone, Default)]
202 pub struct FlashArea {
203     pub flash_id: FlashId,
204     pub device_id: u8,
205     pad16: u16,
206     pub off: u32,
207     pub size: u32,
208 }
209