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