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