|
@@ -1,11 +1,16 @@
|
|
|
use core::{intrinsics::unlikely, mem::size_of};
|
|
|
|
|
|
use system_error::SystemError;
|
|
|
+use uefi_raw::table::boot::{MemoryAttribute, MemoryType};
|
|
|
|
|
|
use crate::{
|
|
|
- driver::firmware::efi::EFIInitFlags,
|
|
|
- libs::align::page_align_down,
|
|
|
- mm::{early_ioremap::EarlyIoRemap, PhysAddr, VirtAddr},
|
|
|
+ arch::MMArch,
|
|
|
+ driver::{firmware::efi::EFIInitFlags, open_firmware::fdt::open_firmware_fdt_driver},
|
|
|
+ libs::align::{page_align_down, page_align_up},
|
|
|
+ mm::{
|
|
|
+ allocator::page_frame::PhysPageFrame, early_ioremap::EarlyIoRemap,
|
|
|
+ memblock::mem_block_manager, MemoryManagementArch, PhysAddr, VirtAddr,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
use super::efi_manager;
|
|
@@ -13,6 +18,7 @@ use super::efi_manager;
|
|
|
#[allow(dead_code)]
|
|
|
#[inline(never)]
|
|
|
pub fn efi_init() {
|
|
|
+ kinfo!("Initializing efi...");
|
|
|
let data_from_fdt = efi_manager()
|
|
|
.get_fdt_params()
|
|
|
.expect("Failed to get fdt params");
|
|
@@ -22,7 +28,7 @@ pub fn efi_init() {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- kdebug!("to map memory table");
|
|
|
+ // kdebug!("to map memory table");
|
|
|
|
|
|
// 映射mmap table
|
|
|
if efi_manager().memmap_init_early(&data_from_fdt).is_err() {
|
|
@@ -42,15 +48,36 @@ pub fn efi_init() {
|
|
|
kwarn!("Unexpected EFI memory map version: {}", desc_version);
|
|
|
}
|
|
|
|
|
|
- // todo: 映射table,初始化runtime services
|
|
|
-
|
|
|
let r = uefi_init(PhysAddr::new(data_from_fdt.systable.unwrap() as usize));
|
|
|
-
|
|
|
- if let Err(r) = r {
|
|
|
- kerror!("Failed to initialize UEFI: {:?}", r);
|
|
|
+ if let Err(e) = r {
|
|
|
+ kerror!("Failed to initialize UEFI: {:?}", e);
|
|
|
+ efi_manager().efi_memmap_unmap();
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- loop {}
|
|
|
+ reserve_memory_regions();
|
|
|
+ // todo: 由于上面的`uefi_init`里面,按照UEFI的数据,初始化了内存块,
|
|
|
+ // 但是UEFI给的数据可能不全,这里Linux会再次从设备树检测可用内存,从而填补完全相应的内存信息
|
|
|
+
|
|
|
+ // 并且,Linux还对EFI BootService提供的Mokvar表进行了检测以及空间保留。
|
|
|
+
|
|
|
+ // todo: 模仿Linux的行为,做好接下来的几步工作:
|
|
|
+ // 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/firmware/efi/efi-init.c#217
|
|
|
+
|
|
|
+ // 保留mmap table的内存
|
|
|
+ let base = page_align_down(data_from_fdt.mmap_base.unwrap() as usize);
|
|
|
+ let offset = data_from_fdt.mmap_base.unwrap() as usize - base;
|
|
|
+
|
|
|
+ mem_block_manager()
|
|
|
+ .reserve_block(
|
|
|
+ PhysAddr::new(base),
|
|
|
+ data_from_fdt.mmap_size.unwrap() as usize + offset,
|
|
|
+ )
|
|
|
+ .expect("Failed to reserve memory for EFI mmap table");
|
|
|
+
|
|
|
+ // todo: Initialize screen info
|
|
|
+
|
|
|
+ kinfo!("UEFI init done!");
|
|
|
}
|
|
|
|
|
|
#[inline(never)]
|
|
@@ -69,18 +96,11 @@ fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> {
|
|
|
// 映射system table
|
|
|
|
|
|
let st_size = size_of::<uefi_raw::table::system::SystemTable>();
|
|
|
- kdebug!("system table: {system_table:?}, size: {st_size}");
|
|
|
- let st_map_phy_base = PhysAddr::new(page_align_down(system_table.data()));
|
|
|
-
|
|
|
- let st_map_offset = system_table.data() - st_map_phy_base.data();
|
|
|
- let st_map_size = st_size + st_map_offset;
|
|
|
- let (st_vaddr, _st_map_size) =
|
|
|
- EarlyIoRemap::map(st_map_phy_base, st_map_size, true).map_err(|e| {
|
|
|
- kwarn!("Unable to map EFI system table, e:{e:?}");
|
|
|
- e
|
|
|
- })?;
|
|
|
|
|
|
- let st_vaddr = st_vaddr + st_map_offset;
|
|
|
+ let st_vaddr = EarlyIoRemap::map_not_aligned(system_table, st_size, true).map_err(|e| {
|
|
|
+ kwarn!("Unable to map EFI system table, e:{e:?}");
|
|
|
+ e
|
|
|
+ })?;
|
|
|
|
|
|
efi_manager()
|
|
|
.inner
|
|
@@ -94,8 +114,6 @@ fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> {
|
|
|
.init_flags
|
|
|
.set(EFIInitFlags::EFI_64BIT, true);
|
|
|
|
|
|
- kdebug!("to parse EFI system table: p: {st_vaddr:?}");
|
|
|
-
|
|
|
if st_vaddr.is_null() {
|
|
|
return Err(SystemError::EINVAL);
|
|
|
}
|
|
@@ -109,21 +127,113 @@ fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> {
|
|
|
e
|
|
|
})?;
|
|
|
|
|
|
- kdebug!("parse ok!");
|
|
|
- let mut inner_write_guard = efi_manager().inner.write();
|
|
|
let st_ref = unsafe { st_ptr.as_ref().unwrap() };
|
|
|
- inner_write_guard.runtime_paddr = Some(PhysAddr::new(st_ref.runtime_services as usize));
|
|
|
+
|
|
|
+ let runtime_service_paddr = efi_vaddr_2_paddr(st_ref.runtime_services as usize);
|
|
|
+ let mut inner_write_guard = efi_manager().inner.write();
|
|
|
+ inner_write_guard.runtime_paddr = Some(runtime_service_paddr);
|
|
|
inner_write_guard.runtime_service_version = Some(st_ref.header.revision);
|
|
|
|
|
|
- kdebug!(
|
|
|
- "runtime service paddr: {:?}",
|
|
|
- inner_write_guard.runtime_paddr.unwrap()
|
|
|
- );
|
|
|
- kdebug!(
|
|
|
- "runtime service version: {}",
|
|
|
- inner_write_guard.runtime_service_version.unwrap()
|
|
|
+ drop(inner_write_guard);
|
|
|
+ efi_manager().report_systable_header(
|
|
|
+ &st_ref.header,
|
|
|
+ efi_vaddr_2_paddr(st_ref.firmware_vendor as usize),
|
|
|
);
|
|
|
|
|
|
- unimplemented!("report header");
|
|
|
- // return Ok(());
|
|
|
+ {
|
|
|
+ // 映射configuration table
|
|
|
+ let table_size = st_ref.number_of_configuration_table_entries
|
|
|
+ * size_of::<uefi_raw::table::configuration::ConfigurationTable>();
|
|
|
+ let config_table_vaddr = EarlyIoRemap::map_not_aligned(
|
|
|
+ efi_vaddr_2_paddr(st_ref.configuration_table as usize),
|
|
|
+ table_size,
|
|
|
+ true,
|
|
|
+ )
|
|
|
+ .map_err(|e| {
|
|
|
+ kwarn!("Unable to map EFI configuration table, e:{e:?}");
|
|
|
+ err_unmap_systable(st_vaddr);
|
|
|
+ e
|
|
|
+ })?;
|
|
|
+ let cfg_tables = unsafe {
|
|
|
+ core::slice::from_raw_parts(
|
|
|
+ config_table_vaddr.data()
|
|
|
+ as *const uefi_raw::table::configuration::ConfigurationTable,
|
|
|
+ st_ref.number_of_configuration_table_entries,
|
|
|
+ )
|
|
|
+ };
|
|
|
+ // 解析configuration table
|
|
|
+ let r = efi_manager().parse_config_tables(cfg_tables);
|
|
|
+
|
|
|
+ EarlyIoRemap::unmap(config_table_vaddr).expect("Failed to unmap EFI config table");
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// 把EFI固件提供的虚拟地址转换为物理地址。
|
|
|
+///
|
|
|
+/// 因为在调用SetVirtualAddressMap()之后,`EFI SystemTable` 的一些数据成员会被虚拟重映射
|
|
|
+///
|
|
|
+/// ## 锁
|
|
|
+///
|
|
|
+/// 在进入该函数前,请不要持有`efi_manager().inner`的写锁
|
|
|
+fn efi_vaddr_2_paddr(efi_vaddr: usize) -> PhysAddr {
|
|
|
+ let guard = efi_manager().inner.read();
|
|
|
+ let mmap = &guard.mmap;
|
|
|
+
|
|
|
+ let efi_vaddr: u64 = efi_vaddr as u64;
|
|
|
+ for md in mmap.iter() {
|
|
|
+ if !md.att.contains(MemoryAttribute::RUNTIME) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if md.virt_start == 0 {
|
|
|
+ // no virtual mapping has been installed by the DragonStub
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if md.virt_start <= efi_vaddr
|
|
|
+ && ((efi_vaddr - md.virt_start) < (md.page_count << (MMArch::PAGE_SHIFT as u64)))
|
|
|
+ {
|
|
|
+ return PhysAddr::new((md.phys_start + (efi_vaddr - md.virt_start)) as usize);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return PhysAddr::new(efi_vaddr as usize);
|
|
|
+}
|
|
|
+
|
|
|
+/// 根据UEFI提供的内存描述符的信息,填写内存区域信息
|
|
|
+fn reserve_memory_regions() {
|
|
|
+ // 忽略之前已经发现的任何内存块。因为之前发现的内存块来自平坦设备树,
|
|
|
+ // 但是UEFI有自己的内存映射表,我们以UEFI提供的为准
|
|
|
+ mem_block_manager()
|
|
|
+ .remove_block(PhysAddr::new(0), PhysAddr::MAX.data())
|
|
|
+ .expect("Failed to remove all memblocks!");
|
|
|
+
|
|
|
+ let inner_guard = efi_manager().inner.read_irqsave();
|
|
|
+ for md in inner_guard.mmap.iter() {
|
|
|
+ let page_count = (PhysPageFrame::new(PhysAddr::new(page_align_up(
|
|
|
+ (md.phys_start + md.page_count << (MMArch::PAGE_SHIFT as u64)) as usize,
|
|
|
+ )))
|
|
|
+ .ppn()
|
|
|
+ - PhysPageFrame::new(PhysAddr::new(page_align_down(md.phys_start as usize))).ppn())
|
|
|
+ as u64;
|
|
|
+ let phys_start = page_align_down(md.phys_start as usize);
|
|
|
+ let size = (page_count << (MMArch::PAGE_SHIFT as u64)) as usize;
|
|
|
+
|
|
|
+ if md.is_memory() {
|
|
|
+ open_firmware_fdt_driver().early_init_dt_add_memory(phys_start as u64, size as u64);
|
|
|
+ if !md.is_usable_memory() {
|
|
|
+ mem_block_manager()
|
|
|
+ .mark_nomap(PhysAddr::new(phys_start), size)
|
|
|
+ .unwrap();
|
|
|
+ }
|
|
|
+
|
|
|
+ // keep ACPI reclaim memory intact for kexec etc.
|
|
|
+ if md.ty == MemoryType::ACPI_RECLAIM {
|
|
|
+ mem_block_manager()
|
|
|
+ .reserve_block(PhysAddr::new(phys_start), size)
|
|
|
+ .unwrap();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|