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

Configure Feed

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

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 28pub fn slot_of_addr<T>(addr: *const T) -> u8 { 29 ((addr as usize - XIP_BASE as usize) / SLOT_SIZE) as u8 30} 31 32 33pub struct Programs { 34 id: u8, 35} 36 37impl Programs { 38 pub fn new() -> Self { 39 Self { id: 0 } 40 } 41} 42 43impl Iterator for Programs { 44 type Item = *const ProgramSlotHeader; 45 46 fn next(&mut self) -> Option<Self::Item> { 47 loop { 48 self.id += 1; 49 50 if self.id > 31 { 51 return None; 52 } 53 54 let s = unsafe { slot(self.id) }; 55 56 unsafe { 57 if (*s).is_valid() { 58 #[cfg(feature = "defmt")] 59 debug!("Found program {} version {} in slot {}", (*s).name().unwrap(), (*s).version().unwrap(), self.id); 60 return Some(s); 61 } else { 62 #[cfg(feature = "defmt")] 63 debug!("No program found in slot {}", self.id); 64 } 65 } 66 } 67 } 68 69 fn size_hint(&self) -> (usize, Option<usize>) { 70 (0, Some(32 - self.id as usize)) 71 } 72} 73 74#[repr(C)] 75pub struct ProgramSlotHeader { 76 pub block_erase_cycles: usize, 77 pub crc: u32, 78 pub len: usize, 79 80 pub data_len: usize, 81 pub data_lma: *const u8, 82 pub data_vma: *mut u8, 83 84 pub bss_len: usize, 85 pub bss_vma: *mut u8, 86 87 pub name_len: usize, 88 pub name_ptr: *const u8, 89 90 pub version_len: usize, 91 pub version_ptr: *const u8, 92 93 pub entry: unsafe extern "C" fn(), 94} 95 96unsafe impl Sync for ProgramSlotHeader {} 97 98impl ProgramSlotHeader { 99 pub const fn partial(name: &'static str, version: &'static str, entry: unsafe extern "C" fn()) -> Self { 100 Self { 101 block_erase_cycles: 0, 102 crc: 0, 103 len: 0, 104 data_len: 0, 105 data_lma: core::ptr::null(), 106 data_vma: core::ptr::null_mut(), 107 bss_len: 0, 108 bss_vma: core::ptr::null_mut(), 109 name_len: name.len(), 110 name_ptr: name.as_ptr(), 111 version_len: version.len(), 112 version_ptr: version.as_ptr(), 113 entry, 114 } 115 } 116 117 pub fn is_valid(&self) -> bool { 118 // Erased flash contains all 1s 119 if self.len == 0 || self.len == usize::MAX { 120 return false; 121 } 122 123 if self.len > SLOT_SIZE { 124 #[cfg(feature = "defmt")] 125 warn!("Program header has invalid size"); 126 return false; 127 } 128 129 if !self.check_crc() { 130 #[cfg(feature = "defmt")] 131 warn!("Program has invalid CRC"); 132 return false; 133 } 134 135 if unsafe { self.name() }.is_err() { 136 #[cfg(feature = "defmt")] 137 warn!("Program name is not valid UTF-8"); 138 return false; 139 } 140 141 if unsafe { self.version() }.is_err() { 142 #[cfg(feature = "defmt")] 143 warn!("Program version string is not valid UTF-8"); 144 return false; 145 } 146 147 let slot_min = (&raw const *self) as usize; 148 let slot_max = slot_min + SLOT_SIZE; 149 let slot_range = slot_min..slot_max; 150 let ram_min = PROGRAM_RAM_AREA_BASE as usize; 151 let ram_max = ram_min + 136 * 1024; 152 let ram_range = ram_min..ram_max; 153 154 if self.data_len > 0 { 155 if !slot_range.contains(&(self.data_lma as usize)) || !slot_range.contains(&(self.data_lma as usize + self.data_len - 1)) { 156 #[cfg(feature = "defmt")] 157 warn!("Program has invalid data section addresses"); 158 return false; 159 } 160 161 if !ram_range.contains(&(self.data_vma as usize)) || !ram_range.contains(&(self.data_vma as usize + self.data_len - 1)) { 162 #[cfg(feature = "defmt")] 163 warn!("Program has invalid data section load addresses"); 164 return false; 165 } 166 } 167 168 if self.bss_len > 0 { 169 if !ram_range.contains(&(self.bss_vma as usize)) || !ram_range.contains(&(self.bss_vma as usize + self.bss_len - 1)) { 170 #[cfg(feature = "defmt")] 171 warn!("Program has invalid bss section addresses"); 172 return false; 173 } 174 } 175 176 true 177 } 178 179 pub fn slot(&self) -> u8 { 180 (((&raw const *self as usize) - XIP_BASE as usize) / SLOT_SIZE) as u8 181 } 182 183 pub fn check_crc(&self) -> bool { 184 if self.len >= SLOT_SIZE || self.len < size_of::<ProgramSlotHeader>() { 185 return false; 186 } 187 188 let ptr = unsafe { (&raw const *self).cast::<u8>().add(8) }; 189 let slice = unsafe { core::slice::from_raw_parts(ptr, self.len - 8) }; 190 let crc = crc32fast::hash(slice); 191 crc == self.crc 192 } 193 194 pub unsafe fn name(&self) -> Result<&str, Utf8Error> { 195 unsafe { 196 core::str::from_utf8(core::slice::from_raw_parts(self.name_ptr, self.name_len)) 197 } 198 } 199 200 pub unsafe fn version(&self) -> Result<&str, Utf8Error> { 201 unsafe { 202 core::str::from_utf8(core::slice::from_raw_parts(self.version_ptr, self.version_len)) 203 } 204 } 205 206 pub unsafe fn load(&self) { unsafe { 207 if self.data_len > 0 { 208 core::ptr::copy_nonoverlapping(self.data_lma, self.data_vma, self.data_len); 209 } 210 211 if self.bss_len > 0 { 212 self.bss_vma.write_bytes(0, self.bss_len); 213 } 214 }} 215} 216 217/// Get the slot number of the (first) program with the specified name, if it exists. 218pub fn find_program_by_name(name: &str) -> Option<u8> { 219 Programs::new() 220 .find(|psh| { 221 // SAFETY: a header returned by Programs must be valid 222 let prog_name = unsafe { (**psh).name() }; 223 prog_name == Ok(name) 224 }) 225 .map(slot_of_addr) 226}