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