mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-18 20:36:31 +00:00
riscv: 完成UEFI初始化,能正确设置memblock的信息 (#501)
* riscv: 完成UEFI初始化,能正确设置memblock的信息 * sbi增加reset功能 * 把虚拟CPU修改为sifive-u54,使qemu能更正确地模拟硬件行为 * 修复内存页面映射未设置“DIRTY”、”ACCESSED“、”GLOBAL“位,导致真机page fault的问题
This commit is contained in:
35
kernel/src/driver/firmware/efi/guid.rs
Normal file
35
kernel/src/driver/firmware/efi/guid.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use core::{fmt, mem};
|
||||
|
||||
use uefi_raw::Guid;
|
||||
|
||||
/// 由DragonStub设置的,用于描述内核被放置在的地址的GUID
|
||||
pub static DRAGONSTUB_EFI_PAYLOAD_EFI_GUID: Guid = Guid::new(
|
||||
unsafe { mem::transmute_copy(&0xddf1d47cu32) },
|
||||
unsafe { mem::transmute_copy(&0x102cu32) },
|
||||
unsafe { mem::transmute_copy(&0xaaf9u32) },
|
||||
0xce,
|
||||
0x34,
|
||||
[0xbc, 0xef, 0x98, 0x12, 0x00, 0x31],
|
||||
);
|
||||
|
||||
/// 表示内核被加载到的地址的信息。
|
||||
///
|
||||
/// 对应 `DRAGONSTUB_EFI_PAYLOAD_EFI_GUID`
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct DragonStubPayloadEFI {
|
||||
/// 内核文件被加载到的物理地址
|
||||
pub paddr: u64,
|
||||
|
||||
/// 占用的空间的大小
|
||||
pub size: u64,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DragonStubPayloadEFI {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("DragonStubPayloadEFI")
|
||||
.field("paddr", &format_args!("0x{:x}", self.paddr))
|
||||
.field("size", &self.size)
|
||||
.finish()
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use core::{intrinsics::unlikely, mem::size_of};
|
||||
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
@ -6,7 +8,7 @@ use crate::{
|
||||
mm::{early_ioremap::EarlyIoRemap, PhysAddr, VirtAddr},
|
||||
};
|
||||
|
||||
use super::{fdt::EFIFdtParams, EFIManager};
|
||||
use super::{fdt::EFIFdtParams, tables::MemoryDescriptor, EFIManager};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EFIMemoryMapInfo {
|
||||
@ -22,6 +24,11 @@ pub struct EFIMemoryMapInfo {
|
||||
pub(super) desc_size: usize,
|
||||
/// EFI Memory Map的描述信息的版本
|
||||
pub(super) desc_version: usize,
|
||||
/// 当前是否在内存管理已经完成初始化后,对该结构体进行操作
|
||||
///
|
||||
/// true: 内存管理已经完成初始化
|
||||
/// false: 内存管理还未完成初始化
|
||||
pub(super) late: bool,
|
||||
}
|
||||
|
||||
impl EFIMemoryMapInfo {
|
||||
@ -32,6 +39,7 @@ impl EFIMemoryMapInfo {
|
||||
nr_map: 0,
|
||||
desc_size: 0,
|
||||
desc_version: 0,
|
||||
late: false,
|
||||
};
|
||||
|
||||
/// 获取EFI Memory Map的虚拟的结束地址
|
||||
@ -39,6 +47,43 @@ impl EFIMemoryMapInfo {
|
||||
pub fn map_end_vaddr(&self) -> Option<VirtAddr> {
|
||||
return self.vaddr.map(|v| v + self.size);
|
||||
}
|
||||
|
||||
/// 迭代所有的内存描述符
|
||||
pub fn iter(&self) -> EFIMemoryDescIter {
|
||||
EFIMemoryDescIter::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// UEFI 内存描述符的迭代器
|
||||
pub struct EFIMemoryDescIter<'a> {
|
||||
inner: &'a EFIMemoryMapInfo,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'a> EFIMemoryDescIter<'a> {
|
||||
fn new(inner: &'a EFIMemoryMapInfo) -> Self {
|
||||
Self { inner, offset: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for EFIMemoryDescIter<'a> {
|
||||
type Item = MemoryDescriptor;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.offset + size_of::<Self::Item>() > self.inner.size {
|
||||
return None;
|
||||
}
|
||||
|
||||
// 如果是空指针,返回None
|
||||
if unlikely(self.inner.vaddr.unwrap_or(VirtAddr::new(0)).is_null()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let vaddr = self.inner.vaddr? + self.offset;
|
||||
self.offset += size_of::<Self::Item>();
|
||||
let res = unsafe { *(vaddr.data() as *const Self::Item) };
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
|
||||
impl EFIManager {
|
||||
@ -59,13 +104,14 @@ impl EFIManager {
|
||||
fn do_efi_memmap_init(&self, data: &EFIFdtParams, early: bool) -> Result<(), SystemError> {
|
||||
let paddr = data.mmap_base.expect("mmap_base is not set");
|
||||
let paddr = PhysAddr::new(paddr as usize);
|
||||
kdebug!("do_efi_memmap_init: paddr={paddr:?}");
|
||||
|
||||
let mut inner_guard = self.inner.write();
|
||||
if early {
|
||||
let offset = paddr.data() - page_align_down(paddr.data());
|
||||
let map_size = data.mmap_size.unwrap() as usize + offset;
|
||||
|
||||
kdebug!("do_efi_memmap_init: map_size={map_size:#x}");
|
||||
// kdebug!("do_efi_memmap_init: map_size={map_size:#x}");
|
||||
|
||||
// 映射内存
|
||||
let mut vaddr = EarlyIoRemap::map(
|
||||
PhysAddr::new(page_align_down(paddr.data())),
|
||||
@ -77,7 +123,9 @@ impl EFIManager {
|
||||
vaddr += offset;
|
||||
|
||||
inner_guard.mmap.vaddr = Some(vaddr);
|
||||
inner_guard.mmap.late = false;
|
||||
} else {
|
||||
inner_guard.mmap.late = true;
|
||||
unimplemented!("efi_memmap_init_late")
|
||||
}
|
||||
|
||||
@ -97,4 +145,21 @@ impl EFIManager {
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 清除EFI Memory Table在内存中的映射
|
||||
pub fn efi_memmap_unmap(&self) {
|
||||
let mut inner_guard = self.inner.write_irqsave();
|
||||
|
||||
// 没有启用memmap
|
||||
if !inner_guard.init_flags.contains(EFIInitFlags::MEMMAP) {
|
||||
return;
|
||||
}
|
||||
|
||||
if !inner_guard.mmap.late {
|
||||
EarlyIoRemap::unmap(inner_guard.mmap.vaddr.take().unwrap()).unwrap();
|
||||
} else {
|
||||
unimplemented!("efi_memmap_unmap");
|
||||
}
|
||||
inner_guard.init_flags.set(EFIInitFlags::MEMMAP, false);
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,13 @@ use system_error::SystemError;
|
||||
|
||||
use crate::{libs::rwlock::RwLock, mm::PhysAddr};
|
||||
|
||||
use self::memmap::EFIMemoryMapInfo;
|
||||
use self::{guid::DragonStubPayloadEFI, memmap::EFIMemoryMapInfo};
|
||||
|
||||
mod fdt;
|
||||
pub mod guid;
|
||||
pub mod init;
|
||||
pub mod memmap;
|
||||
pub mod tables;
|
||||
|
||||
static EFI_MANAGER: EFIManager = EFIManager::new();
|
||||
|
||||
@ -32,6 +34,7 @@ struct InnerEFIManager {
|
||||
pub runtime_paddr: Option<PhysAddr>,
|
||||
/// runtime services的版本号
|
||||
pub runtime_service_version: Option<uefi_raw::table::Revision>,
|
||||
pub dragonstub_load_info: Option<DragonStubPayloadEFI>,
|
||||
}
|
||||
|
||||
impl EFIManager {
|
||||
@ -42,6 +45,7 @@ impl EFIManager {
|
||||
init_flags: EFIInitFlags::empty(),
|
||||
runtime_paddr: None,
|
||||
runtime_service_version: None,
|
||||
dragonstub_load_info: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
167
kernel/src/driver/firmware/efi/tables.rs
Normal file
167
kernel/src/driver/firmware/efi/tables.rs
Normal file
@ -0,0 +1,167 @@
|
||||
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::{
|
||||
driver::firmware::efi::{
|
||||
efi_manager,
|
||||
guid::{DragonStubPayloadEFI, DRAGONSTUB_EFI_PAYLOAD_EFI_GUID},
|
||||
},
|
||||
mm::{early_ioremap::EarlyIoRemap, PhysAddr},
|
||||
};
|
||||
|
||||
use super::EFIManager;
|
||||
|
||||
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 {
|
||||
if table
|
||||
.vendor_guid
|
||||
.equivalent(&DRAGONSTUB_EFI_PAYLOAD_EFI_GUID)
|
||||
{
|
||||
let table_paddr: PhysAddr = PhysAddr::new(table.vendor_table as usize);
|
||||
let vaddr = EarlyIoRemap::map_not_aligned(
|
||||
table_paddr,
|
||||
size_of::<DragonStubPayloadEFI>(),
|
||||
true,
|
||||
)?;
|
||||
|
||||
let data = unsafe { *(vaddr.data() as *const DragonStubPayloadEFI) };
|
||||
|
||||
efi_manager().inner.write().dragonstub_load_info = Some(data);
|
||||
|
||||
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
|
||||
| MemoryAttribute::WRITE_THROUGH
|
||||
| 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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -4,15 +4,7 @@ use fdt::{
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
init::boot_params,
|
||||
libs::{align::page_align_down, rwlock::RwLock},
|
||||
mm::{
|
||||
memblock::{mem_block_manager, MemBlockManager},
|
||||
MemoryManagementArch, PhysAddr,
|
||||
},
|
||||
};
|
||||
use crate::{init::boot_params, libs::rwlock::RwLock};
|
||||
|
||||
#[inline(always)]
|
||||
pub fn open_firmware_fdt_driver() -> &'static OpenFirmwareFdtDriver {
|
||||
@ -45,6 +37,7 @@ impl FdtGlobalData {
|
||||
pub struct OpenFirmwareFdtDriver;
|
||||
|
||||
impl OpenFirmwareFdtDriver {
|
||||
#[allow(dead_code)]
|
||||
pub fn early_scan_device_tree(&self) -> Result<(), SystemError> {
|
||||
let fdt_vaddr = boot_params().read().fdt().unwrap();
|
||||
let fdt = unsafe {
|
||||
@ -207,7 +200,22 @@ impl OpenFirmwareFdtDriver {
|
||||
return found_memory;
|
||||
}
|
||||
|
||||
fn early_init_dt_add_memory(&self, base: u64, size: u64) {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn early_init_dt_add_memory(&self, _base: u64, _size: u64) {
|
||||
kBUG!("x86_64 should not call early_init_dt_add_memory");
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
pub fn early_init_dt_add_memory(&self, base: u64, size: u64) {
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
libs::align::page_align_down,
|
||||
mm::{
|
||||
memblock::{mem_block_manager, MemBlockManager},
|
||||
MemoryManagementArch, PhysAddr,
|
||||
},
|
||||
};
|
||||
|
||||
let mut base = base as usize;
|
||||
let mut size = size as usize;
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
// #[cfg(target_arch = "riscv64")]
|
||||
pub mod fdt;
|
||||
|
Reference in New Issue
Block a user