123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- use core::{ffi::CStr, mem::size_of};
- use hashbrown::Equivalent;
- use system_error::SystemError;
- use uefi_raw::table::{
- boot::{MemoryAttribute, MemoryType},
- configuration::ConfigurationTable,
- };
- use crate::{
- arch::MMArch,
- driver::firmware::efi::{
- efi_manager,
- guid::{DragonStubPayloadEFI, DRAGONSTUB_EFI_PAYLOAD_EFI_GUID},
- },
- mm::{
- early_ioremap::EarlyIoRemap, memblock::mem_block_manager, MemoryManagementArch, PhysAddr,
- VirtAddr,
- },
- };
- use super::{
- guid::{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, EFI_MEMRESERVE_TABLE_GUID},
- EFIManager,
- };
- /// 所有的要解析的表格的解析器
- static TABLE_PARSERS: &'static [&'static TableMatcher] = &[
- &TableMatcher::new(&MatchTableDragonStubPayloadEFI),
- &TableMatcher::new(&MatchTableMemoryAttributes),
- &TableMatcher::new(&MatchTableMemReserve),
- ];
- impl EFIManager {
- /// 显示EFI系统表头的信息
- ///
- /// ## 参数
- ///
- /// - header: system table表头
- /// - firmware_vendor: firmware vendor字符串的物理地址
- #[inline(never)]
- pub fn report_systable_header(
- &self,
- header: &uefi_raw::table::Header,
- firmware_vendor: PhysAddr,
- ) {
- const TMPBUF_SIZE: usize = 100;
- let mut tmp_buf = [0u8; TMPBUF_SIZE];
- let fw_ptr =
- EarlyIoRemap::map_not_aligned(firmware_vendor, TMPBUF_SIZE * size_of::<u16>(), true);
- if let Ok(fw_ptr) = fw_ptr {
- let slice =
- unsafe { core::slice::from_raw_parts(fw_ptr.data() as *const u16, TMPBUF_SIZE) };
- for i in 0..(TMPBUF_SIZE - 1) {
- let val = slice[i];
- if (val & 0xff) == 0 {
- break;
- }
- tmp_buf[i] = (val & 0xff) as u8;
- }
- EarlyIoRemap::unmap(fw_ptr).map_err(|e|{
- kerror!("report systable header: failed to unmap systable header, fw_ptr: {fw_ptr:?}, err: {e:?}");
- e
- }).ok();
- } else {
- kwarn!("report systable header: failed to map systable header, err: {fw_ptr:?}");
- }
- let s = CStr::from_bytes_with_nul(&tmp_buf)
- .unwrap_or_else(|_| CStr::from_bytes_with_nul(b"Unknown\0").unwrap());
- kinfo!("EFI version: {:?}, vendor: {:?}", header.revision, s);
- }
- /// 解析EFI config table
- pub fn parse_config_tables(&self, tables: &[ConfigurationTable]) -> Result<(), SystemError> {
- for table in tables {
- let mut flag = false;
- 'parser_loop: for parser in TABLE_PARSERS {
- if let Some(r) = parser.match_table(table) {
- // 有匹配结果
- if let Err(e) = r {
- kwarn!(
- "Failed to parse cfg table: '{}', err: {e:?}",
- parser.table.name()
- );
- }
- flag = true;
- break 'parser_loop;
- }
- }
- if !flag {
- kwarn!("Cannot find parser for guid: {:?}", table.vendor_guid);
- }
- }
- // 如果存在mem reserve table
- if let Some(mem_reserve) = efi_manager().inner.read().memreserve_table_paddr {
- let mut prev_paddr = mem_reserve;
- while !prev_paddr.is_null() {
- let vaddr = EarlyIoRemap::map_not_aligned(prev_paddr, MMArch::PAGE_SIZE, true)
- .map_err(|e| {
- kerror!(
- "Failed to map UEFI memreserve table, paddr: {prev_paddr:?}, err: {e:?}"
- );
- SystemError::ENOMEM
- })?;
- let p = unsafe {
- (vaddr.data() as *const LinuxEFIMemReserveTable)
- .as_ref()
- .unwrap()
- };
- // reserve the entry itself
- let psize: usize = p.size.try_into().unwrap();
- mem_block_manager()
- .reserve_block(
- prev_paddr,
- size_of::<LinuxEFIMemReserveTable>()
- + size_of::<LinuxEFIMemReserveEntry>() * psize,
- )
- .map_err(|e| {
- kerror!("Failed to reserve block, paddr: {prev_paddr:?}, err: {e:?}");
- EarlyIoRemap::unmap(vaddr).unwrap();
- e
- })?;
- let entries = unsafe {
- core::slice::from_raw_parts(
- (vaddr.data() as *const LinuxEFIMemReserveTable).add(1)
- as *const LinuxEFIMemReserveEntry,
- p.count as usize,
- )
- };
- // reserve the entries
- for entry in entries {
- mem_block_manager()
- .reserve_block(PhysAddr::new(entry.base), entry.size)
- .map_err(|e| {
- kerror!("Failed to reserve block, paddr: {prev_paddr:?}, err: {e:?}");
- EarlyIoRemap::unmap(vaddr).unwrap();
- e
- })?;
- }
- prev_paddr = p.next_paddr;
- EarlyIoRemap::unmap(vaddr).unwrap();
- }
- }
- return Ok(());
- }
- }
- /// A structure describing a region of memory.
- #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
- #[repr(C)]
- pub struct MemoryDescriptor {
- /// Type of memory occupying this range.
- pub ty: MemoryType,
- /// Starting physical address.
- pub phys_start: uefi_raw::PhysicalAddress,
- /// Starting virtual address.
- pub virt_start: uefi_raw::VirtualAddress,
- /// Number of 4 KiB pages contained in this range.
- pub page_count: u64,
- /// The capability attributes of this memory range.
- pub att: MemoryAttribute,
- }
- #[allow(dead_code)]
- impl MemoryDescriptor {
- /// Memory descriptor version number.
- pub const VERSION: u32 = 1;
- /// 当前内存描述符是否表示真实的内存
- #[inline]
- pub fn is_memory(&self) -> bool {
- if self.att.contains(MemoryAttribute::WRITE_BACK)
- || self.att.contains(MemoryAttribute::WRITE_THROUGH)
- || self.att.contains(MemoryAttribute::WRITE_COMBINE)
- {
- return true;
- }
- return false;
- }
- /// 判断当前内存描述符所表示的区域是否能被作为系统内存使用
- ///
- /// ## 返回
- ///
- /// - `true` - 可以
- /// - `false` - 不可以
- pub fn is_usable_memory(&self) -> bool {
- match self.ty {
- MemoryType::LOADER_CODE
- | MemoryType::LOADER_DATA
- | MemoryType::ACPI_RECLAIM
- | MemoryType::BOOT_SERVICES_CODE
- | MemoryType::BOOT_SERVICES_DATA
- | MemoryType::CONVENTIONAL
- | MemoryType::PERSISTENT_MEMORY => {
- // SPECIAL_PURPOSE的内存是“软保留”的,这意味着它最初被留出,
- // 但在启动后可以通过热插拔再次使用,或者分配给dax驱动程序。
- if self.att.contains(MemoryAttribute::SPECIAL_PURPOSE) {
- return false;
- }
- // 根据规范,在调用ExitBootServices()之后,这些区域就不再被保留了。
- // 然而,只有当它们可以被映射为WRITE_BACK缓存时,我们才能将它们用作系统内存
- return self.att.contains(MemoryAttribute::WRITE_BACK);
- }
- _ => {
- return false;
- }
- }
- }
- }
- impl Default for MemoryDescriptor {
- fn default() -> MemoryDescriptor {
- MemoryDescriptor {
- ty: MemoryType::RESERVED,
- phys_start: 0,
- virt_start: 0,
- page_count: 0,
- att: MemoryAttribute::empty(),
- }
- }
- }
- trait MatchTable: Send + Sync {
- /// 配置表名(仅用于日志显示)
- fn name(&self) -> &'static str;
- /// 当前table的guid
- fn guid(&self) -> &'static uefi_raw::Guid;
- /// 匹配阶段时,匹配器要映射vendor_table的大小。
- ///
- /// 如果为0,则不映射
- fn map_size(&self) -> usize;
- /// 当表格被映射后,调用这个函数
- ///
- /// ## 锁
- ///
- /// 进入该函数前,不得持有efi_manager().inner的任何锁
- fn post_process(
- &self,
- vendor_table_vaddr: Option<VirtAddr>,
- table_raw: &ConfigurationTable,
- ) -> Result<(), SystemError>;
- }
- /// `DRAGONSTUB_EFI_PAYLOAD_EFI_GUID` 的匹配器
- struct MatchTableDragonStubPayloadEFI;
- impl MatchTable for MatchTableDragonStubPayloadEFI {
- fn name(&self) -> &'static str {
- "DragonStub Payload"
- }
- fn guid(&self) -> &'static uefi_raw::Guid {
- &DRAGONSTUB_EFI_PAYLOAD_EFI_GUID
- }
- fn map_size(&self) -> usize {
- core::mem::size_of::<DragonStubPayloadEFI>()
- }
- fn post_process(
- &self,
- vendor_table_vaddr: Option<VirtAddr>,
- _table_raw: &ConfigurationTable,
- ) -> Result<(), SystemError> {
- let vendor_table_vaddr = vendor_table_vaddr.unwrap();
- let data = unsafe { *(vendor_table_vaddr.data() as *const DragonStubPayloadEFI) };
- efi_manager().inner.write().dragonstub_load_info = Some(data);
- return Ok(());
- }
- }
- struct MatchTableMemoryAttributes;
- impl MatchTable for MatchTableMemoryAttributes {
- fn name(&self) -> &'static str {
- "MemAttr"
- }
- fn guid(&self) -> &'static uefi_raw::Guid {
- &EFI_MEMORY_ATTRIBUTES_TABLE_GUID
- }
- fn map_size(&self) -> usize {
- // 不映射
- 0
- }
- fn post_process(
- &self,
- _vendor_table_vaddr: Option<VirtAddr>,
- table_raw: &ConfigurationTable,
- ) -> Result<(), SystemError> {
- efi_manager()
- .inner
- .write_irqsave()
- .memory_attribute_table_paddr = Some(PhysAddr::new(table_raw.vendor_table as usize));
- return Ok(());
- }
- }
- struct MatchTableMemReserve;
- impl MatchTable for MatchTableMemReserve {
- fn name(&self) -> &'static str {
- "MemReserve"
- }
- fn guid(&self) -> &'static uefi_raw::Guid {
- &EFI_MEMRESERVE_TABLE_GUID
- }
- fn map_size(&self) -> usize {
- // 不映射
- 0
- }
- fn post_process(
- &self,
- _vendor_table_vaddr: Option<VirtAddr>,
- table_raw: &ConfigurationTable,
- ) -> Result<(), SystemError> {
- efi_manager().inner.write_irqsave().memreserve_table_paddr =
- Some(PhysAddr::new(table_raw.vendor_table as usize));
- kdebug!(
- "memreserve_table_paddr: {:#x}",
- table_raw.vendor_table as usize
- );
- return Ok(());
- }
- }
- /// 用于匹配配置表的匹配器
- struct TableMatcher {
- table: &'static dyn MatchTable,
- }
- impl TableMatcher {
- const fn new(table: &'static dyn MatchTable) -> Self {
- Self { table }
- }
- /// 判断配置表与当前匹配器是否匹配
- #[inline(never)]
- fn match_table(&self, table: &ConfigurationTable) -> Option<Result<(), SystemError>> {
- if table.vendor_guid.equivalent(self.table.guid()) == false {
- return None;
- }
- let table_map_size = self.table.map_size();
- let vendor_table_vaddr: Option<VirtAddr>;
- if table_map_size > 0 {
- let table_paddr: PhysAddr = PhysAddr::new(table.vendor_table as usize);
- let vaddr = EarlyIoRemap::map_not_aligned(table_paddr, table_map_size, true);
- if let Err(e) = vaddr {
- return Some(Err(e));
- }
- vendor_table_vaddr = Some(vaddr.unwrap());
- } else {
- vendor_table_vaddr = None;
- }
- let r = self.table.post_process(vendor_table_vaddr, table);
- if let Some(vaddr) = vendor_table_vaddr {
- EarlyIoRemap::unmap(vaddr).unwrap();
- }
- return Some(r);
- }
- }
- #[repr(C)]
- #[derive(Debug)]
- struct LinuxEFIMemReserveTable {
- /// allocated size of the array
- size: i32,
- /// number of entries used
- count: i32,
- /// pa of next struct instance
- next_paddr: PhysAddr,
- entry: [LinuxEFIMemReserveEntry; 0],
- }
- #[repr(C)]
- #[derive(Debug)]
- struct LinuxEFIMemReserveEntry {
- base: usize,
- size: usize,
- }
|