blob: 9d650787e56856f673e4acdf0476f41909b8cd3f [file] [log] [blame]
David Browne2acfae2020-01-21 16:45:01 -07001// Copyright (c) 2017-2019 Linaro LTD
2// Copyright (c) 2018-2019 JUUL Labs
3// Copyright (c) 2019 Arm Limited
4//
5// SPDX-License-Identifier: Apache-2.0
6
David Brownde7729e2017-01-09 10:41:35 -07007//! Describe flash areas.
8
David Brown2cbc4702017-07-06 14:18:58 -06009use simflash::{Flash, SimFlash, Sector};
David Brownde7729e2017-01-09 10:41:35 -070010use std::ptr;
Fabio Utzig1caef132018-10-26 15:40:53 -030011use std::collections::HashMap;
David Brownde7729e2017-01-09 10:41:35 -070012
13/// Structure to build up the boot area table.
David Brownfc8e3c52021-03-10 05:11:26 -070014#[derive(Debug, Default, Clone)]
David Brownde7729e2017-01-09 10:41:35 -070015pub struct AreaDesc {
16 areas: Vec<Vec<FlashArea>>,
17 whole: Vec<FlashArea>,
Fabio Utzig1caef132018-10-26 15:40:53 -030018 sectors: HashMap<u8, Vec<Sector>>,
David Brownde7729e2017-01-09 10:41:35 -070019}
20
21impl AreaDesc {
Fabio Utzig1caef132018-10-26 15:40:53 -030022 pub fn new() -> AreaDesc {
David Brownde7729e2017-01-09 10:41:35 -070023 AreaDesc {
24 areas: vec![],
25 whole: vec![],
Fabio Utzig1caef132018-10-26 15:40:53 -030026 sectors: HashMap::new(),
David Brownde7729e2017-01-09 10:41:35 -070027 }
28 }
29
Fabio Utzig1caef132018-10-26 15:40:53 -030030 pub fn add_flash_sectors(&mut self, id: u8, flash: &SimFlash) {
31 self.sectors.insert(id, flash.sector_iter().collect());
32 }
33
David Brownde7729e2017-01-09 10:41:35 -070034 /// 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
David Vincze2d736ad2019-02-18 11:50:22 +010036 /// slots are PRIMARY_SLOT, SECONDARY_SLOT, and SCRATCH in that order.
Fabio Utzig1caef132018-10-26 15:40:53 -030037 pub fn add_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
David Brownde7729e2017-01-09 10:41:35 -070038 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
Fabio Utzig1caef132018-10-26 15:40:53 -030055 for sector in &self.sectors[&dev_id] {
David Brownde7729e2017-01-09 10:41:35 -070056 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,
Fabio Utzig1caef132018-10-26 15:40:53 -030068 device_id: dev_id,
David Brownde7729e2017-01-09 10:41:35 -070069 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,
Fabio Utzig1caef132018-10-26 15:40:53 -030085 device_id: dev_id,
David Brownde7729e2017-01-09 10:41:35 -070086 pad16: 0,
87 off: orig_base as u32,
88 size: orig_len as u32,
89 });
90 }
91
David Brown90c19132017-01-23 10:21:28 -070092 // 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.
Fabio Utzig1caef132018-10-26 15:40:53 -030096 pub fn add_simple_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
David Brown90c19132017-01-23 10:21:28 -070097 let area = vec![FlashArea {
98 flash_id: id,
Fabio Utzig1caef132018-10-26 15:40:53 -030099 device_id: dev_id,
David Brown90c19132017-01-23 10:21:28 -0700100 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,
Fabio Utzig1caef132018-10-26 15:40:53 -0300108 device_id: dev_id,
David Brown90c19132017-01-23 10:21:28 -0700109 pad16: 0,
110 off: base as u32,
111 size: len as u32,
112 });
113 }
114
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200115 // Look for the image with the given ID, and return its offset, size and
David Brown06ef06e2019-03-05 12:28:10 -0700116 // device id. Returns None if the area is not present.
117 pub fn find(&self, id: FlashId) -> Option<(usize, usize, u8)> {
David Brown5c6b6792017-03-20 12:51:28 -0600118 for area in &self.whole {
Fabio Utzig1caef132018-10-26 15:40:53 -0300119 // FIXME: should we ensure id is not duplicated over multiple devices?
David Brown5c6b6792017-03-20 12:51:28 -0600120 if area.flash_id == id {
David Brown06ef06e2019-03-05 12:28:10 -0700121 return Some((area.off as usize, area.size as usize, area.device_id));
David Brown5c6b6792017-03-20 12:51:28 -0600122 }
123 }
David Brown06ef06e2019-03-05 12:28:10 -0700124 None
David Brown5c6b6792017-03-20 12:51:28 -0600125 }
126
David Brownde7729e2017-01-09 10:41:35 -0700127 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() {
David Brown4bbb93d2021-03-10 05:17:29 -0700133 if !area.is_empty() {
David Brownde7729e2017-01-09 10:41:35 -0700134 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 }
David Brown297029a2019-08-13 14:29:51 -0600145
146 /// Return an iterator over all `FlashArea`s present.
147 pub fn iter_areas(&self) -> impl Iterator<Item = &FlashArea> {
148 self.whole.iter()
149 }
David Brownde7729e2017-01-09 10:41:35 -0700150}
151
152/// The area descriptor, C format.
153#[repr(C)]
154#[derive(Debug, Default)]
David Brown0daa36c2017-03-07 12:08:27 +0100155pub struct CAreaDesc {
156 slots: [CArea; 16],
David Brownde7729e2017-01-09 10:41:35 -0700157 num_slots: u32,
158}
159
160#[repr(C)]
161#[derive(Debug)]
David Brown0daa36c2017-03-07 12:08:27 +0100162pub struct CArea {
David Brownde7729e2017-01-09 10:41:35 -0700163 whole: FlashArea,
164 areas: *const FlashArea,
165 num_areas: u32,
Fabio Utzig1caef132018-10-26 15:40:53 -0300166 // FIXME: is this not already available on whole/areas?
David Brownde7729e2017-01-09 10:41:35 -0700167 id: FlashId,
David Brownde7729e2017-01-09 10:41:35 -0700168}
169
David Brown0daa36c2017-03-07 12:08:27 +0100170impl Default for CArea {
171 fn default() -> CArea {
David Brownde7729e2017-01-09 10:41:35 -0700172 CArea {
173 areas: ptr::null(),
174 whole: Default::default(),
175 id: FlashId::BootLoader,
176 num_areas: 0,
David Brownde7729e2017-01-09 10:41:35 -0700177 }
178 }
179}
180
181/// Flash area map.
182#[repr(u8)]
183#[derive(Copy, Clone, Debug, Eq, PartialEq)]
184#[allow(dead_code)]
185pub enum FlashId {
186 BootLoader = 0,
187 Image0 = 1,
188 Image1 = 2,
189 ImageScratch = 3,
David Brown06ef06e2019-03-05 12:28:10 -0700190 Image2 = 4,
191 Image3 = 5,
David Brownde7729e2017-01-09 10:41:35 -0700192}
193
194impl Default for FlashId {
195 fn default() -> FlashId {
196 FlashId::BootLoader
197 }
198}
199
200#[repr(C)]
201#[derive(Debug, Clone, Default)]
202pub struct FlashArea {
David Brown297029a2019-08-13 14:29:51 -0600203 pub flash_id: FlashId,
204 pub device_id: u8,
David Brownde7729e2017-01-09 10:41:35 -0700205 pad16: u16,
David Brown297029a2019-08-13 14:29:51 -0600206 pub off: u32,
207 pub size: u32,
David Brownde7729e2017-01-09 10:41:35 -0700208}