1 use core::{ffi::CStr, mem::size_of}; 2 3 use hashbrown::Equivalent; 4 use system_error::SystemError; 5 use uefi_raw::table::{ 6 boot::{MemoryAttribute, MemoryType}, 7 configuration::ConfigurationTable, 8 }; 9 10 use crate::{ 11 arch::MMArch, 12 driver::firmware::efi::{ 13 efi_manager, 14 guid::{DragonStubPayloadEFI, DRAGONSTUB_EFI_PAYLOAD_EFI_GUID}, 15 }, 16 mm::{ 17 early_ioremap::EarlyIoRemap, memblock::mem_block_manager, MemoryManagementArch, PhysAddr, 18 VirtAddr, 19 }, 20 }; 21 22 use super::{ 23 guid::{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, EFI_MEMRESERVE_TABLE_GUID}, 24 EFIManager, 25 }; 26 27 /// 所有的要解析的表格的解析器 28 static TABLE_PARSERS: &'static [&'static TableMatcher] = &[ 29 &TableMatcher::new(&MatchTableDragonStubPayloadEFI), 30 &TableMatcher::new(&MatchTableMemoryAttributes), 31 &TableMatcher::new(&MatchTableMemReserve), 32 ]; 33 34 impl EFIManager { 35 /// 显示EFI系统表头的信息 36 /// 37 /// ## 参数 38 /// 39 /// - header: system table表头 40 /// - firmware_vendor: firmware vendor字符串的物理地址 41 #[inline(never)] 42 pub fn report_systable_header( 43 &self, 44 header: &uefi_raw::table::Header, 45 firmware_vendor: PhysAddr, 46 ) { 47 const TMPBUF_SIZE: usize = 100; 48 49 let mut tmp_buf = [0u8; TMPBUF_SIZE]; 50 51 let fw_ptr = 52 EarlyIoRemap::map_not_aligned(firmware_vendor, TMPBUF_SIZE * size_of::<u16>(), true); 53 if let Ok(fw_ptr) = fw_ptr { 54 let slice = 55 unsafe { core::slice::from_raw_parts(fw_ptr.data() as *const u16, TMPBUF_SIZE) }; 56 for i in 0..(TMPBUF_SIZE - 1) { 57 let val = slice[i]; 58 59 if (val & 0xff) == 0 { 60 break; 61 } 62 tmp_buf[i] = (val & 0xff) as u8; 63 } 64 65 EarlyIoRemap::unmap(fw_ptr).map_err(|e|{ 66 kerror!("report systable header: failed to unmap systable header, fw_ptr: {fw_ptr:?}, err: {e:?}"); 67 e 68 }).ok(); 69 } else { 70 kwarn!("report systable header: failed to map systable header, err: {fw_ptr:?}"); 71 } 72 73 let s = CStr::from_bytes_with_nul(&tmp_buf) 74 .unwrap_or_else(|_| CStr::from_bytes_with_nul(b"Unknown\0").unwrap()); 75 kinfo!("EFI version: {:?}, vendor: {:?}", header.revision, s); 76 } 77 78 /// 解析EFI config table 79 pub fn parse_config_tables(&self, tables: &[ConfigurationTable]) -> Result<(), SystemError> { 80 for table in tables { 81 let mut flag = false; 82 'parser_loop: for parser in TABLE_PARSERS { 83 if let Some(r) = parser.match_table(table) { 84 // 有匹配结果 85 if let Err(e) = r { 86 kwarn!( 87 "Failed to parse cfg table: '{}', err: {e:?}", 88 parser.table.name() 89 ); 90 } 91 flag = true; 92 break 'parser_loop; 93 } 94 } 95 96 if !flag { 97 kwarn!("Cannot find parser for guid: {:?}", table.vendor_guid); 98 } 99 } 100 101 // 如果存在mem reserve table 102 if let Some(mem_reserve) = efi_manager().inner.read().memreserve_table_paddr { 103 let mut prev_paddr = mem_reserve; 104 while !prev_paddr.is_null() { 105 let vaddr = EarlyIoRemap::map_not_aligned(prev_paddr, MMArch::PAGE_SIZE, true) 106 .map_err(|e| { 107 kerror!( 108 "Failed to map UEFI memreserve table, paddr: {prev_paddr:?}, err: {e:?}" 109 ); 110 111 SystemError::ENOMEM 112 })?; 113 114 let p = unsafe { 115 (vaddr.data() as *const LinuxEFIMemReserveTable) 116 .as_ref() 117 .unwrap() 118 }; 119 120 // reserve the entry itself 121 let psize: usize = p.size.try_into().unwrap(); 122 mem_block_manager() 123 .reserve_block( 124 prev_paddr, 125 size_of::<LinuxEFIMemReserveTable>() 126 + size_of::<LinuxEFIMemReserveEntry>() * psize, 127 ) 128 .map_err(|e| { 129 kerror!("Failed to reserve block, paddr: {prev_paddr:?}, err: {e:?}"); 130 EarlyIoRemap::unmap(vaddr).unwrap(); 131 e 132 })?; 133 134 let entries = unsafe { 135 core::slice::from_raw_parts( 136 (vaddr.data() as *const LinuxEFIMemReserveTable).add(1) 137 as *const LinuxEFIMemReserveEntry, 138 p.count as usize, 139 ) 140 }; 141 // reserve the entries 142 for entry in entries { 143 mem_block_manager() 144 .reserve_block(PhysAddr::new(entry.base), entry.size) 145 .map_err(|e| { 146 kerror!("Failed to reserve block, paddr: {prev_paddr:?}, err: {e:?}"); 147 EarlyIoRemap::unmap(vaddr).unwrap(); 148 e 149 })?; 150 } 151 152 prev_paddr = p.next_paddr; 153 EarlyIoRemap::unmap(vaddr).unwrap(); 154 } 155 } 156 return Ok(()); 157 } 158 } 159 160 /// A structure describing a region of memory. 161 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 162 #[repr(C)] 163 pub struct MemoryDescriptor { 164 /// Type of memory occupying this range. 165 pub ty: MemoryType, 166 /// Starting physical address. 167 pub phys_start: uefi_raw::PhysicalAddress, 168 /// Starting virtual address. 169 pub virt_start: uefi_raw::VirtualAddress, 170 /// Number of 4 KiB pages contained in this range. 171 pub page_count: u64, 172 /// The capability attributes of this memory range. 173 pub att: MemoryAttribute, 174 } 175 176 #[allow(dead_code)] 177 impl MemoryDescriptor { 178 /// Memory descriptor version number. 179 pub const VERSION: u32 = 1; 180 181 /// 当前内存描述符是否表示真实的内存 182 #[inline] 183 pub fn is_memory(&self) -> bool { 184 if self.att.contains(MemoryAttribute::WRITE_BACK) 185 || self.att.contains(MemoryAttribute::WRITE_THROUGH) 186 || self.att.contains(MemoryAttribute::WRITE_COMBINE) 187 { 188 return true; 189 } 190 191 return false; 192 } 193 194 /// 判断当前内存描述符所表示的区域是否能被作为系统内存使用 195 /// 196 /// ## 返回 197 /// 198 /// - `true` - 可以 199 /// - `false` - 不可以 200 pub fn is_usable_memory(&self) -> bool { 201 match self.ty { 202 MemoryType::LOADER_CODE 203 | MemoryType::LOADER_DATA 204 | MemoryType::ACPI_RECLAIM 205 | MemoryType::BOOT_SERVICES_CODE 206 | MemoryType::BOOT_SERVICES_DATA 207 | MemoryType::CONVENTIONAL 208 | MemoryType::PERSISTENT_MEMORY => { 209 // SPECIAL_PURPOSE的内存是“软保留”的,这意味着它最初被留出, 210 // 但在启动后可以通过热插拔再次使用,或者分配给dax驱动程序。 211 if self.att.contains(MemoryAttribute::SPECIAL_PURPOSE) { 212 return false; 213 } 214 215 // 根据规范,在调用ExitBootServices()之后,这些区域就不再被保留了。 216 // 然而,只有当它们可以被映射为WRITE_BACK缓存时,我们才能将它们用作系统内存 217 return self.att.contains(MemoryAttribute::WRITE_BACK); 218 } 219 _ => { 220 return false; 221 } 222 } 223 } 224 } 225 226 impl Default for MemoryDescriptor { 227 fn default() -> MemoryDescriptor { 228 MemoryDescriptor { 229 ty: MemoryType::RESERVED, 230 phys_start: 0, 231 virt_start: 0, 232 page_count: 0, 233 att: MemoryAttribute::empty(), 234 } 235 } 236 } 237 238 trait MatchTable: Send + Sync { 239 /// 配置表名(仅用于日志显示) 240 fn name(&self) -> &'static str; 241 242 /// 当前table的guid 243 fn guid(&self) -> &'static uefi_raw::Guid; 244 245 /// 匹配阶段时,匹配器要映射vendor_table的大小。 246 /// 247 /// 如果为0,则不映射 248 fn map_size(&self) -> usize; 249 250 /// 当表格被映射后,调用这个函数 251 /// 252 /// ## 锁 253 /// 254 /// 进入该函数前,不得持有efi_manager().inner的任何锁 255 fn post_process( 256 &self, 257 vendor_table_vaddr: Option<VirtAddr>, 258 table_raw: &ConfigurationTable, 259 ) -> Result<(), SystemError>; 260 } 261 262 /// `DRAGONSTUB_EFI_PAYLOAD_EFI_GUID` 的匹配器 263 struct MatchTableDragonStubPayloadEFI; 264 265 impl MatchTable for MatchTableDragonStubPayloadEFI { 266 fn name(&self) -> &'static str { 267 "DragonStub Payload" 268 } 269 270 fn guid(&self) -> &'static uefi_raw::Guid { 271 &DRAGONSTUB_EFI_PAYLOAD_EFI_GUID 272 } 273 274 fn map_size(&self) -> usize { 275 core::mem::size_of::<DragonStubPayloadEFI>() 276 } 277 278 fn post_process( 279 &self, 280 vendor_table_vaddr: Option<VirtAddr>, 281 _table_raw: &ConfigurationTable, 282 ) -> Result<(), SystemError> { 283 let vendor_table_vaddr = vendor_table_vaddr.unwrap(); 284 let data = unsafe { *(vendor_table_vaddr.data() as *const DragonStubPayloadEFI) }; 285 286 efi_manager().inner.write().dragonstub_load_info = Some(data); 287 288 return Ok(()); 289 } 290 } 291 292 struct MatchTableMemoryAttributes; 293 294 impl MatchTable for MatchTableMemoryAttributes { 295 fn name(&self) -> &'static str { 296 "MemAttr" 297 } 298 299 fn guid(&self) -> &'static uefi_raw::Guid { 300 &EFI_MEMORY_ATTRIBUTES_TABLE_GUID 301 } 302 303 fn map_size(&self) -> usize { 304 // 不映射 305 0 306 } 307 308 fn post_process( 309 &self, 310 _vendor_table_vaddr: Option<VirtAddr>, 311 table_raw: &ConfigurationTable, 312 ) -> Result<(), SystemError> { 313 efi_manager() 314 .inner 315 .write_irqsave() 316 .memory_attribute_table_paddr = Some(PhysAddr::new(table_raw.vendor_table as usize)); 317 return Ok(()); 318 } 319 } 320 321 struct MatchTableMemReserve; 322 323 impl MatchTable for MatchTableMemReserve { 324 fn name(&self) -> &'static str { 325 "MemReserve" 326 } 327 328 fn guid(&self) -> &'static uefi_raw::Guid { 329 &EFI_MEMRESERVE_TABLE_GUID 330 } 331 332 fn map_size(&self) -> usize { 333 // 不映射 334 0 335 } 336 337 fn post_process( 338 &self, 339 _vendor_table_vaddr: Option<VirtAddr>, 340 table_raw: &ConfigurationTable, 341 ) -> Result<(), SystemError> { 342 efi_manager().inner.write_irqsave().memreserve_table_paddr = 343 Some(PhysAddr::new(table_raw.vendor_table as usize)); 344 kdebug!( 345 "memreserve_table_paddr: {:#x}", 346 table_raw.vendor_table as usize 347 ); 348 return Ok(()); 349 } 350 } 351 352 /// 用于匹配配置表的匹配器 353 struct TableMatcher { 354 table: &'static dyn MatchTable, 355 } 356 357 impl TableMatcher { 358 const fn new(table: &'static dyn MatchTable) -> Self { 359 Self { table } 360 } 361 362 /// 判断配置表与当前匹配器是否匹配 363 #[inline(never)] 364 fn match_table(&self, table: &ConfigurationTable) -> Option<Result<(), SystemError>> { 365 if table.vendor_guid.equivalent(self.table.guid()) == false { 366 return None; 367 } 368 369 let table_map_size = self.table.map_size(); 370 let vendor_table_vaddr: Option<VirtAddr>; 371 if table_map_size > 0 { 372 let table_paddr: PhysAddr = PhysAddr::new(table.vendor_table as usize); 373 let vaddr = EarlyIoRemap::map_not_aligned(table_paddr, table_map_size, true); 374 375 if let Err(e) = vaddr { 376 return Some(Err(e)); 377 } 378 379 vendor_table_vaddr = Some(vaddr.unwrap()); 380 } else { 381 vendor_table_vaddr = None; 382 } 383 384 let r = self.table.post_process(vendor_table_vaddr, table); 385 386 if let Some(vaddr) = vendor_table_vaddr { 387 EarlyIoRemap::unmap(vaddr).unwrap(); 388 } 389 return Some(r); 390 } 391 } 392 393 #[repr(C)] 394 #[derive(Debug)] 395 struct LinuxEFIMemReserveTable { 396 /// allocated size of the array 397 size: i32, 398 /// number of entries used 399 count: i32, 400 /// pa of next struct instance 401 next_paddr: PhysAddr, 402 entry: [LinuxEFIMemReserveEntry; 0], 403 } 404 405 #[repr(C)] 406 #[derive(Debug)] 407 struct LinuxEFIMemReserveEntry { 408 base: usize, 409 size: usize, 410 } 411