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