blob: 1ebb405525e5b92ae42971e34d68a52027a471fd [file] [log] [blame]
David Brownc8d62012021-10-27 15:03:48 -06001// Copyright (c) 2017-2021 Linaro LTD
David Browne2acfae2020-01-21 16:45:01 -07002// 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 Brown5d155132024-06-10 14:07:32 -060012use std::borrow::BorrowMut;
David Brownde7729e2017-01-09 10:41:35 -070013
14/// Structure to build up the boot area table.
David Brownfc8e3c52021-03-10 05:11:26 -070015#[derive(Debug, Default, Clone)]
David Brownde7729e2017-01-09 10:41:35 -070016pub struct AreaDesc {
17 areas: Vec<Vec<FlashArea>>,
18 whole: Vec<FlashArea>,
Fabio Utzig1caef132018-10-26 15:40:53 -030019 sectors: HashMap<u8, Vec<Sector>>,
David Brownde7729e2017-01-09 10:41:35 -070020}
21
22impl AreaDesc {
Fabio Utzig1caef132018-10-26 15:40:53 -030023 pub fn new() -> AreaDesc {
David Brownde7729e2017-01-09 10:41:35 -070024 AreaDesc {
25 areas: vec![],
26 whole: vec![],
Fabio Utzig1caef132018-10-26 15:40:53 -030027 sectors: HashMap::new(),
David Brownde7729e2017-01-09 10:41:35 -070028 }
29 }
30
Fabio Utzig1caef132018-10-26 15:40:53 -030031 pub fn add_flash_sectors(&mut self, id: u8, flash: &SimFlash) {
32 self.sectors.insert(id, flash.sector_iter().collect());
33 }
34
David Brownde7729e2017-01-09 10:41:35 -070035 /// 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
David Vincze2d736ad2019-02-18 11:50:22 +010037 /// slots are PRIMARY_SLOT, SECONDARY_SLOT, and SCRATCH in that order.
Fabio Utzig1caef132018-10-26 15:40:53 -030038 pub fn add_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
David Brownde7729e2017-01-09 10:41:35 -070039 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
Fabio Utzig1caef132018-10-26 15:40:53 -030056 for sector in &self.sectors[&dev_id] {
David Brownde7729e2017-01-09 10:41:35 -070057 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,
Fabio Utzig1caef132018-10-26 15:40:53 -030069 device_id: dev_id,
David Brownde7729e2017-01-09 10:41:35 -070070 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,
Fabio Utzig1caef132018-10-26 15:40:53 -030086 device_id: dev_id,
David Brownde7729e2017-01-09 10:41:35 -070087 pad16: 0,
88 off: orig_base as u32,
89 size: orig_len as u32,
90 });
91 }
92
David Brown90c19132017-01-23 10:21:28 -070093 // 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.
Fabio Utzig1caef132018-10-26 15:40:53 -030097 pub fn add_simple_image(&mut self, base: usize, len: usize, id: FlashId, dev_id: u8) {
David Brown90c19132017-01-23 10:21:28 -070098 let area = vec![FlashArea {
99 flash_id: id,
Fabio Utzig1caef132018-10-26 15:40:53 -0300100 device_id: dev_id,
David Brown90c19132017-01-23 10:21:28 -0700101 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,
Fabio Utzig1caef132018-10-26 15:40:53 -0300109 device_id: dev_id,
David Brown90c19132017-01-23 10:21:28 -0700110 pad16: 0,
111 off: base as u32,
112 size: len as u32,
113 });
114 }
115
Fabio Utzigafb2bc92018-11-19 16:11:52 -0200116 // Look for the image with the given ID, and return its offset, size and
David Brown06ef06e2019-03-05 12:28:10 -0700117 // device id. Returns None if the area is not present.
118 pub fn find(&self, id: FlashId) -> Option<(usize, usize, u8)> {
David Brown5c6b6792017-03-20 12:51:28 -0600119 for area in &self.whole {
Fabio Utzig1caef132018-10-26 15:40:53 -0300120 // FIXME: should we ensure id is not duplicated over multiple devices?
David Brown5c6b6792017-03-20 12:51:28 -0600121 if area.flash_id == id {
David Brown06ef06e2019-03-05 12:28:10 -0700122 return Some((area.off as usize, area.size as usize, area.device_id));
David Brown5c6b6792017-03-20 12:51:28 -0600123 }
124 }
David Brown06ef06e2019-03-05 12:28:10 -0700125 None
David Brown5c6b6792017-03-20 12:51:28 -0600126 }
127
David Brown5d155132024-06-10 14:07:32 -0600128 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();
David Brownde7729e2017-01-09 10:41:35 -0700131
132 assert_eq!(self.areas.len(), self.whole.len());
133
134 for (i, area) in self.areas.iter().enumerate() {
David Brown4bbb93d2021-03-10 05:17:29 -0700135 if !area.is_empty() {
David Brownde7729e2017-01-09 10:41:35 -0700136 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
David Brown5d155132024-06-10 14:07:32 -0600145 areas_box
David Brownde7729e2017-01-09 10:41:35 -0700146 }
David Brown297029a2019-08-13 14:29:51 -0600147
148 /// Return an iterator over all `FlashArea`s present.
149 pub fn iter_areas(&self) -> impl Iterator<Item = &FlashArea> {
150 self.whole.iter()
151 }
David Brownde7729e2017-01-09 10:41:35 -0700152}
153
154/// The area descriptor, C format.
155#[repr(C)]
156#[derive(Debug, Default)]
David Brown0daa36c2017-03-07 12:08:27 +0100157pub struct CAreaDesc {
158 slots: [CArea; 16],
David Brownde7729e2017-01-09 10:41:35 -0700159 num_slots: u32,
160}
161
162#[repr(C)]
163#[derive(Debug)]
David Brown0daa36c2017-03-07 12:08:27 +0100164pub struct CArea {
David Brownde7729e2017-01-09 10:41:35 -0700165 whole: FlashArea,
166 areas: *const FlashArea,
167 num_areas: u32,
Fabio Utzig1caef132018-10-26 15:40:53 -0300168 // FIXME: is this not already available on whole/areas?
David Brownde7729e2017-01-09 10:41:35 -0700169 id: FlashId,
David Brownde7729e2017-01-09 10:41:35 -0700170}
171
David Brown0daa36c2017-03-07 12:08:27 +0100172impl Default for CArea {
173 fn default() -> CArea {
David Brownde7729e2017-01-09 10:41:35 -0700174 CArea {
175 areas: ptr::null(),
176 whole: Default::default(),
177 id: FlashId::BootLoader,
178 num_areas: 0,
David Brownde7729e2017-01-09 10:41:35 -0700179 }
180 }
181}
182
183/// Flash area map.
184#[repr(u8)]
185#[derive(Copy, Clone, Debug, Eq, PartialEq)]
186#[allow(dead_code)]
187pub enum FlashId {
188 BootLoader = 0,
189 Image0 = 1,
190 Image1 = 2,
191 ImageScratch = 3,
David Brown06ef06e2019-03-05 12:28:10 -0700192 Image2 = 4,
193 Image3 = 5,
David Brownde7729e2017-01-09 10:41:35 -0700194}
195
196impl Default for FlashId {
197 fn default() -> FlashId {
198 FlashId::BootLoader
199 }
200}
201
202#[repr(C)]
203#[derive(Debug, Clone, Default)]
204pub struct FlashArea {
David Brown297029a2019-08-13 14:29:51 -0600205 pub flash_id: FlashId,
206 pub device_id: u8,
David Brownde7729e2017-01-09 10:41:35 -0700207 pad16: u16,
David Brown297029a2019-08-13 14:29:51 -0600208 pub off: u32,
209 pub size: u32,
David Brownde7729e2017-01-09 10:41:35 -0700210}