firmware for my Touchscreen E-Paper Input Module for Framework Laptop 16
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

at f6676c82689a4e7314b93c8eb98ddd08152fe708 211 lines 5.9 kB view raw
1use core::str::Utf8Error; 2 3#[cfg(feature = "defmt")] 4use defmt::{warn, debug}; 5 6pub const XIP_BASE: *const u8 = 0x10000000 as *const u8; 7pub const PROGRAM_RAM_AREA_BASE: *mut u8 = 0x20020000 as *mut u8; 8 9pub const SLOT_SIZE: usize = 0x80000; 10 11pub const unsafe fn slot_ptr(id: u8) -> *const u8 { unsafe { 12 if id > 31 { 13 panic!("slot ID must be between 0 and 31"); 14 } 15 16 if id == 0 { 17 // "Slot 0" is used for the launcher, which is stored 128K into the flash 18 XIP_BASE.add(128 * 1024) 19 } else { 20 XIP_BASE.add(SLOT_SIZE * id as usize) 21 } 22}} 23 24pub const unsafe fn slot(id: u8) -> *const ProgramSlotHeader { unsafe { 25 slot_ptr(id).cast() 26}} 27 28 29pub struct Programs { 30 id: u8, 31} 32 33impl Programs { 34 pub fn new() -> Self { 35 Self { id: 0 } 36 } 37} 38 39impl Iterator for Programs { 40 type Item = *const ProgramSlotHeader; 41 42 fn next(&mut self) -> Option<Self::Item> { 43 loop { 44 self.id += 1; 45 46 if self.id > 31 { 47 return None; 48 } 49 50 let s = unsafe { slot(self.id) }; 51 52 unsafe { 53 if (*s).is_valid() { 54 #[cfg(feature = "defmt")] 55 debug!("Found program {} version {} in slot {}", (*s).name().unwrap(), (*s).version().unwrap(), self.id); 56 return Some(s); 57 } else { 58 #[cfg(feature = "defmt")] 59 debug!("No program found in slot {}", self.id); 60 } 61 } 62 } 63 } 64 65 fn size_hint(&self) -> (usize, Option<usize>) { 66 (0, Some(32 - self.id as usize)) 67 } 68} 69 70#[repr(C)] 71pub struct ProgramSlotHeader { 72 pub block_erase_cycles: usize, 73 pub crc: u32, 74 pub len: usize, 75 76 pub data_len: usize, 77 pub data_lma: *const u8, 78 pub data_vma: *mut u8, 79 80 pub bss_len: usize, 81 pub bss_vma: *mut u8, 82 83 pub name_len: usize, 84 pub name_ptr: *const u8, 85 86 pub version_len: usize, 87 pub version_ptr: *const u8, 88 89 pub entry: unsafe extern "C" fn(), 90} 91 92unsafe impl Sync for ProgramSlotHeader {} 93 94impl ProgramSlotHeader { 95 pub const fn partial(name: &'static str, version: &'static str, entry: unsafe extern "C" fn()) -> Self { 96 Self { 97 block_erase_cycles: 0, 98 crc: 0, 99 len: 0, 100 data_len: 0, 101 data_lma: core::ptr::null(), 102 data_vma: core::ptr::null_mut(), 103 bss_len: 0, 104 bss_vma: core::ptr::null_mut(), 105 name_len: name.len(), 106 name_ptr: name.as_ptr(), 107 version_len: version.len(), 108 version_ptr: version.as_ptr(), 109 entry, 110 } 111 } 112 113 pub fn is_valid(&self) -> bool { 114 // Erased flash contains all 1s 115 if self.len == 0 || self.len == usize::MAX { 116 return false; 117 } 118 119 if self.len > SLOT_SIZE { 120 #[cfg(feature = "defmt")] 121 warn!("Program header has invalid size"); 122 return false; 123 } 124 125 if !self.check_crc() { 126 #[cfg(feature = "defmt")] 127 warn!("Program has invalid CRC"); 128 return false; 129 } 130 131 if unsafe { self.name() }.is_err() { 132 #[cfg(feature = "defmt")] 133 warn!("Program name is not valid UTF-8"); 134 return false; 135 } 136 137 if unsafe { self.version() }.is_err() { 138 #[cfg(feature = "defmt")] 139 warn!("Program version string is not valid UTF-8"); 140 return false; 141 } 142 143 let slot_min = (&raw const *self) as usize; 144 let slot_max = slot_min + SLOT_SIZE; 145 let slot_range = slot_min..slot_max; 146 let ram_min = PROGRAM_RAM_AREA_BASE as usize; 147 let ram_max = ram_min + 136 * 1024; 148 let ram_range = ram_min..ram_max; 149 150 if self.data_len > 0 { 151 if !slot_range.contains(&(self.data_lma as usize)) || !slot_range.contains(&(self.data_lma as usize + self.data_len - 1)) { 152 #[cfg(feature = "defmt")] 153 warn!("Program has invalid data section addresses"); 154 return false; 155 } 156 157 if !ram_range.contains(&(self.data_vma as usize)) || !ram_range.contains(&(self.data_vma as usize + self.data_len - 1)) { 158 #[cfg(feature = "defmt")] 159 warn!("Program has invalid data section load addresses"); 160 return false; 161 } 162 } 163 164 if self.bss_len > 0 { 165 if !ram_range.contains(&(self.bss_vma as usize)) || !ram_range.contains(&(self.bss_vma as usize + self.bss_len - 1)) { 166 #[cfg(feature = "defmt")] 167 warn!("Program has invalid bss section addresses"); 168 return false; 169 } 170 } 171 172 true 173 } 174 175 pub fn slot(&self) -> u8 { 176 (((&raw const *self as usize) - XIP_BASE as usize) / SLOT_SIZE) as u8 177 } 178 179 pub fn check_crc(&self) -> bool { 180 if self.len >= SLOT_SIZE || self.len < size_of::<ProgramSlotHeader>() { 181 return false; 182 } 183 184 let ptr = unsafe { (&raw const *self).cast::<u8>().add(8) }; 185 let slice = unsafe { core::slice::from_raw_parts(ptr, self.len - 8) }; 186 let crc = crc32fast::hash(slice); 187 crc == self.crc 188 } 189 190 pub unsafe fn name(&self) -> Result<&str, Utf8Error> { 191 unsafe { 192 core::str::from_utf8(core::slice::from_raw_parts(self.name_ptr, self.name_len)) 193 } 194 } 195 196 pub unsafe fn version(&self) -> Result<&str, Utf8Error> { 197 unsafe { 198 core::str::from_utf8(core::slice::from_raw_parts(self.version_ptr, self.version_len)) 199 } 200 } 201 202 pub unsafe fn load(&self) { unsafe { 203 if self.data_len > 0 { 204 core::ptr::copy_nonoverlapping(self.data_lma, self.data_vma, self.data_len); 205 } 206 207 if self.bss_len > 0 { 208 self.bss_vma.write_bytes(0, self.bss_len); 209 } 210 }} 211}