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::{ 24 EFI_MEMORY_ATTRIBUTES_TABLE_GUID, EFI_MEMRESERVE_TABLE_GUID, EFI_SYSTEM_RESOURCE_TABLE_GUID, 25 }, 26 EFIManager, 27 }; 28 29 /// 所有的要解析的表格的解析器 30 static TABLE_PARSERS: &[&TableMatcher] = &[ 31 &TableMatcher::new(&MatchTableDragonStubPayloadEFI), 32 &TableMatcher::new(&MatchTableMemoryAttributes), 33 &TableMatcher::new(&MatchTableMemReserve), 34 &TableMatcher::new(&MatchTableEsrt), 35 ]; 36 37 impl EFIManager { 38 /// 显示EFI系统表头的信息 39 /// 40 /// ## 参数 41 /// 42 /// - header: system table表头 43 /// - firmware_vendor: firmware vendor字符串的物理地址 44 #[inline(never)] 45 pub fn report_systable_header( 46 &self, 47 header: &uefi_raw::table::Header, 48 firmware_vendor: PhysAddr, 49 ) { 50 const TMPBUF_SIZE: usize = 100; 51 52 let mut tmp_buf = [0u8; TMPBUF_SIZE]; 53 54 let fw_ptr = 55 EarlyIoRemap::map_not_aligned(firmware_vendor, TMPBUF_SIZE * size_of::<u16>(), true); 56 if let Ok(fw_ptr) = fw_ptr { 57 let slice = 58 unsafe { core::slice::from_raw_parts(fw_ptr.data() as *const u16, TMPBUF_SIZE) }; 59 for i in 0..(TMPBUF_SIZE - 1) { 60 let val = slice[i]; 61 62 if (val & 0xff) == 0 { 63 break; 64 } 65 tmp_buf[i] = (val & 0xff) as u8; 66 } 67 68 EarlyIoRemap::unmap(fw_ptr).map_err(|e|{ 69 kerror!("report systable header: failed to unmap systable header, fw_ptr: {fw_ptr:?}, err: {e:?}"); 70 e 71 }).ok(); 72 } else { 73 kwarn!("report systable header: failed to map systable header, err: {fw_ptr:?}"); 74 } 75 76 let s = CStr::from_bytes_with_nul(&tmp_buf) 77 .unwrap_or_else(|_| CStr::from_bytes_with_nul(b"Unknown\0").unwrap()); 78 kinfo!("EFI version: {:?}, vendor: {:?}", header.revision, s); 79 } 80 81 /// 解析EFI config table 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 kwarn!( 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 kwarn!("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 kerror!( 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 kerror!("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 kerror!("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] 186 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` - 不可以 203 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 { 230 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 /// 配置表名(仅用于日志显示) 243 fn name(&self) -> &'static str; 244 245 /// 当前table的guid 246 fn guid(&self) -> &'static uefi_raw::Guid; 247 248 /// 匹配阶段时,匹配器要映射vendor_table的大小。 249 /// 250 /// 如果为0,则不映射 251 fn map_size(&self) -> usize; 252 253 /// 当表格被映射后,调用这个函数 254 /// 255 /// ## 锁 256 /// 257 /// 进入该函数前,不得持有efi_manager().inner的任何锁 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 { 269 fn name(&self) -> &'static str { 270 "DragonStub Payload" 271 } 272 273 fn guid(&self) -> &'static uefi_raw::Guid { 274 &DRAGONSTUB_EFI_PAYLOAD_EFI_GUID 275 } 276 277 fn map_size(&self) -> usize { 278 core::mem::size_of::<DragonStubPayloadEFI>() 279 } 280 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 { 298 fn name(&self) -> &'static str { 299 "MemAttr" 300 } 301 302 fn guid(&self) -> &'static uefi_raw::Guid { 303 &EFI_MEMORY_ATTRIBUTES_TABLE_GUID 304 } 305 306 fn map_size(&self) -> usize { 307 // 不映射 308 0 309 } 310 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 { 327 fn name(&self) -> &'static str { 328 "MemReserve" 329 } 330 331 fn guid(&self) -> &'static uefi_raw::Guid { 332 &EFI_MEMRESERVE_TABLE_GUID 333 } 334 335 fn map_size(&self) -> usize { 336 // 不映射 337 0 338 } 339 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 kdebug!( 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 { 358 fn name(&self) -> &'static str { 359 "ESRT" 360 } 361 362 fn guid(&self) -> &'static uefi_raw::Guid { 363 &EFI_SYSTEM_RESOURCE_TABLE_GUID 364 } 365 366 fn map_size(&self) -> usize { 367 0 368 } 369 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 kdebug!("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 { 388 const fn new(table: &'static dyn MatchTable) -> Self { 389 Self { table } 390 } 391 392 /// 判断配置表与当前匹配器是否匹配 393 #[inline(never)] 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