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).unwrap_or(c"Unknown"); 78 info!("EFI version: {:?}, vendor: {:?}", header.revision, s); 79 } 80 81 /// 解析EFI config table parse_config_tables(&self, tables: &[ConfigurationTable]) -> Result<(), SystemError>82 pub fn parse_config_tables(&self, tables: &[ConfigurationTable]) -> Result<(), SystemError> { 83 for table in tables { 84 let mut flag = false; 85 'parser_loop: for parser in TABLE_PARSERS { 86 if let Some(r) = parser.match_table(table) { 87 // 有匹配结果 88 if let Err(e) = r { 89 warn!( 90 "Failed to parse cfg table: '{}', err: {e:?}", 91 parser.table.name() 92 ); 93 } 94 flag = true; 95 break 'parser_loop; 96 } 97 } 98 99 if !flag { 100 warn!("Cannot find parser for guid: {:?}", table.vendor_guid); 101 } 102 } 103 104 // 如果存在mem reserve table 105 if let Some(mem_reserve) = efi_manager().inner_read().memreserve_table_paddr { 106 let mut prev_paddr = mem_reserve; 107 while !prev_paddr.is_null() { 108 let vaddr = EarlyIoRemap::map_not_aligned(prev_paddr, MMArch::PAGE_SIZE, true) 109 .map_err(|e| { 110 error!( 111 "Failed to map UEFI memreserve table, paddr: {prev_paddr:?}, err: {e:?}" 112 ); 113 114 SystemError::ENOMEM 115 })?; 116 117 let p = unsafe { 118 (vaddr.data() as *const LinuxEFIMemReserveTable) 119 .as_ref() 120 .unwrap() 121 }; 122 123 // reserve the entry itself 124 let psize: usize = p.size.try_into().unwrap(); 125 mem_block_manager() 126 .reserve_block( 127 prev_paddr, 128 size_of::<LinuxEFIMemReserveTable>() 129 + size_of::<LinuxEFIMemReserveEntry>() * psize, 130 ) 131 .map_err(|e| { 132 error!("Failed to reserve block, paddr: {prev_paddr:?}, err: {e:?}"); 133 EarlyIoRemap::unmap(vaddr).unwrap(); 134 e 135 })?; 136 137 let entries = unsafe { 138 core::slice::from_raw_parts( 139 (vaddr.data() as *const LinuxEFIMemReserveTable).add(1) 140 as *const LinuxEFIMemReserveEntry, 141 p.count as usize, 142 ) 143 }; 144 // reserve the entries 145 for entry in entries { 146 mem_block_manager() 147 .reserve_block(PhysAddr::new(entry.base), entry.size) 148 .map_err(|e| { 149 error!("Failed to reserve block, paddr: {prev_paddr:?}, err: {e:?}"); 150 EarlyIoRemap::unmap(vaddr).unwrap(); 151 e 152 })?; 153 } 154 155 prev_paddr = p.next_paddr; 156 EarlyIoRemap::unmap(vaddr).unwrap(); 157 } 158 } 159 return Ok(()); 160 } 161 } 162 163 /// A structure describing a region of memory. 164 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 165 #[repr(C)] 166 pub struct MemoryDescriptor { 167 /// Type of memory occupying this range. 168 pub ty: MemoryType, 169 /// Starting physical address. 170 pub phys_start: uefi_raw::PhysicalAddress, 171 /// Starting virtual address. 172 pub virt_start: uefi_raw::VirtualAddress, 173 /// Number of 4 KiB pages contained in this range. 174 pub page_count: u64, 175 /// The capability attributes of this memory range. 176 pub att: MemoryAttribute, 177 } 178 179 #[allow(dead_code)] 180 impl MemoryDescriptor { 181 /// Memory descriptor version number. 182 pub const VERSION: u32 = 1; 183 184 /// 当前内存描述符是否表示真实的内存 185 #[inline] is_memory(&self) -> bool186 pub fn is_memory(&self) -> bool { 187 if self.att.contains(MemoryAttribute::WRITE_BACK) 188 || self.att.contains(MemoryAttribute::WRITE_THROUGH) 189 || self.att.contains(MemoryAttribute::WRITE_COMBINE) 190 { 191 return true; 192 } 193 194 return false; 195 } 196 197 /// 判断当前内存描述符所表示的区域是否能被作为系统内存使用 198 /// 199 /// ## 返回 200 /// 201 /// - `true` - 可以 202 /// - `false` - 不可以 is_usable_memory(&self) -> bool203 pub fn is_usable_memory(&self) -> bool { 204 match self.ty { 205 MemoryType::LOADER_CODE 206 | MemoryType::LOADER_DATA 207 | MemoryType::ACPI_RECLAIM 208 | MemoryType::BOOT_SERVICES_CODE 209 | MemoryType::BOOT_SERVICES_DATA 210 | MemoryType::CONVENTIONAL 211 | MemoryType::PERSISTENT_MEMORY => { 212 // SPECIAL_PURPOSE的内存是“软保留”的,这意味着它最初被留出, 213 // 但在启动后可以通过热插拔再次使用,或者分配给dax驱动程序。 214 if self.att.contains(MemoryAttribute::SPECIAL_PURPOSE) { 215 return false; 216 } 217 218 // 根据规范,在调用ExitBootServices()之后,这些区域就不再被保留了。 219 // 然而,只有当它们可以被映射为WRITE_BACK缓存时,我们才能将它们用作系统内存 220 return self.att.contains(MemoryAttribute::WRITE_BACK); 221 } 222 _ => { 223 return false; 224 } 225 } 226 } 227 } 228 229 impl Default for MemoryDescriptor { default() -> MemoryDescriptor230 fn default() -> MemoryDescriptor { 231 MemoryDescriptor { 232 ty: MemoryType::RESERVED, 233 phys_start: 0, 234 virt_start: 0, 235 page_count: 0, 236 att: MemoryAttribute::empty(), 237 } 238 } 239 } 240 241 trait MatchTable: Send + Sync { 242 /// 配置表名(仅用于日志显示) name(&self) -> &'static str243 fn name(&self) -> &'static str; 244 245 /// 当前table的guid guid(&self) -> &'static uefi_raw::Guid246 fn guid(&self) -> &'static uefi_raw::Guid; 247 248 /// 匹配阶段时,匹配器要映射vendor_table的大小。 249 /// 250 /// 如果为0,则不映射 map_size(&self) -> usize251 fn map_size(&self) -> usize; 252 253 /// 当表格被映射后,调用这个函数 254 /// 255 /// ## 锁 256 /// 257 /// 进入该函数前,不得持有efi_manager().inner的任何锁 post_process( &self, vendor_table_vaddr: Option<VirtAddr>, table_raw: &ConfigurationTable, ) -> Result<(), SystemError>258 fn post_process( 259 &self, 260 vendor_table_vaddr: Option<VirtAddr>, 261 table_raw: &ConfigurationTable, 262 ) -> Result<(), SystemError>; 263 } 264 265 /// `DRAGONSTUB_EFI_PAYLOAD_EFI_GUID` 的匹配器 266 struct MatchTableDragonStubPayloadEFI; 267 268 impl MatchTable for MatchTableDragonStubPayloadEFI { name(&self) -> &'static str269 fn name(&self) -> &'static str { 270 "DragonStub Payload" 271 } 272 guid(&self) -> &'static uefi_raw::Guid273 fn guid(&self) -> &'static uefi_raw::Guid { 274 &DRAGONSTUB_EFI_PAYLOAD_EFI_GUID 275 } 276 map_size(&self) -> usize277 fn map_size(&self) -> usize { 278 core::mem::size_of::<DragonStubPayloadEFI>() 279 } 280 post_process( &self, vendor_table_vaddr: Option<VirtAddr>, _table_raw: &ConfigurationTable, ) -> Result<(), SystemError>281 fn post_process( 282 &self, 283 vendor_table_vaddr: Option<VirtAddr>, 284 _table_raw: &ConfigurationTable, 285 ) -> Result<(), SystemError> { 286 let vendor_table_vaddr = vendor_table_vaddr.unwrap(); 287 let data = unsafe { *(vendor_table_vaddr.data() as *const DragonStubPayloadEFI) }; 288 289 efi_manager().inner_write().dragonstub_load_info = Some(data); 290 291 return Ok(()); 292 } 293 } 294 295 struct MatchTableMemoryAttributes; 296 297 impl MatchTable for MatchTableMemoryAttributes { name(&self) -> &'static str298 fn name(&self) -> &'static str { 299 "MemAttr" 300 } 301 guid(&self) -> &'static uefi_raw::Guid302 fn guid(&self) -> &'static uefi_raw::Guid { 303 &EFI_MEMORY_ATTRIBUTES_TABLE_GUID 304 } 305 map_size(&self) -> usize306 fn map_size(&self) -> usize { 307 // 不映射 308 0 309 } 310 post_process( &self, _vendor_table_vaddr: Option<VirtAddr>, table_raw: &ConfigurationTable, ) -> Result<(), SystemError>311 fn post_process( 312 &self, 313 _vendor_table_vaddr: Option<VirtAddr>, 314 table_raw: &ConfigurationTable, 315 ) -> Result<(), SystemError> { 316 efi_manager() 317 .inner 318 .write_irqsave() 319 .memory_attribute_table_paddr = Some(PhysAddr::new(table_raw.vendor_table as usize)); 320 return Ok(()); 321 } 322 } 323 324 struct MatchTableMemReserve; 325 326 impl MatchTable for MatchTableMemReserve { name(&self) -> &'static str327 fn name(&self) -> &'static str { 328 "MemReserve" 329 } 330 guid(&self) -> &'static uefi_raw::Guid331 fn guid(&self) -> &'static uefi_raw::Guid { 332 &EFI_MEMRESERVE_TABLE_GUID 333 } 334 map_size(&self) -> usize335 fn map_size(&self) -> usize { 336 // 不映射 337 0 338 } 339 post_process( &self, _vendor_table_vaddr: Option<VirtAddr>, table_raw: &ConfigurationTable, ) -> Result<(), SystemError>340 fn post_process( 341 &self, 342 _vendor_table_vaddr: Option<VirtAddr>, 343 table_raw: &ConfigurationTable, 344 ) -> Result<(), SystemError> { 345 efi_manager().inner.write_irqsave().memreserve_table_paddr = 346 Some(PhysAddr::new(table_raw.vendor_table as usize)); 347 debug!( 348 "memreserve_table_paddr: {:#x}", 349 table_raw.vendor_table as usize 350 ); 351 return Ok(()); 352 } 353 } 354 355 struct MatchTableEsrt; 356 357 impl MatchTable for MatchTableEsrt { name(&self) -> &'static str358 fn name(&self) -> &'static str { 359 "ESRT" 360 } 361 guid(&self) -> &'static uefi_raw::Guid362 fn guid(&self) -> &'static uefi_raw::Guid { 363 &EFI_SYSTEM_RESOURCE_TABLE_GUID 364 } 365 map_size(&self) -> usize366 fn map_size(&self) -> usize { 367 0 368 } 369 post_process( &self, _vendor_table_vaddr: Option<VirtAddr>, table_raw: &ConfigurationTable, ) -> Result<(), SystemError>370 fn post_process( 371 &self, 372 _vendor_table_vaddr: Option<VirtAddr>, 373 table_raw: &ConfigurationTable, 374 ) -> Result<(), SystemError> { 375 efi_manager().inner.write_irqsave().esrt_table_paddr = 376 Some(PhysAddr::new(table_raw.vendor_table as usize)); 377 debug!("esrt_table_paddr: {:#x}", table_raw.vendor_table as usize); 378 return Ok(()); 379 } 380 } 381 382 /// 用于匹配配置表的匹配器 383 struct TableMatcher { 384 table: &'static dyn MatchTable, 385 } 386 387 impl TableMatcher { new(table: &'static dyn MatchTable) -> Self388 const fn new(table: &'static dyn MatchTable) -> Self { 389 Self { table } 390 } 391 392 /// 判断配置表与当前匹配器是否匹配 393 #[inline(never)] match_table(&self, table: &ConfigurationTable) -> Option<Result<(), SystemError>>394 fn match_table(&self, table: &ConfigurationTable) -> Option<Result<(), SystemError>> { 395 if !table.vendor_guid.equivalent(self.table.guid()) { 396 return None; 397 } 398 399 let table_map_size = self.table.map_size(); 400 401 let vendor_table_vaddr: Option<VirtAddr> = if table_map_size > 0 { 402 let table_paddr: PhysAddr = PhysAddr::new(table.vendor_table as usize); 403 let vaddr = EarlyIoRemap::map_not_aligned(table_paddr, table_map_size, true); 404 405 if let Err(e) = vaddr { 406 return Some(Err(e)); 407 } 408 409 Some(vaddr.unwrap()) 410 } else { 411 None 412 }; 413 414 let r = self.table.post_process(vendor_table_vaddr, table); 415 416 if let Some(vaddr) = vendor_table_vaddr { 417 EarlyIoRemap::unmap(vaddr).unwrap(); 418 } 419 return Some(r); 420 } 421 } 422 423 #[repr(C)] 424 #[derive(Debug)] 425 struct LinuxEFIMemReserveTable { 426 /// allocated size of the array 427 size: i32, 428 /// number of entries used 429 count: i32, 430 /// pa of next struct instance 431 next_paddr: PhysAddr, 432 entry: [LinuxEFIMemReserveEntry; 0], 433 } 434 435 #[repr(C)] 436 #[derive(Debug)] 437 struct LinuxEFIMemReserveEntry { 438 base: usize, 439 size: usize, 440 } 441