我正在编写一个小型 UEFI x86_64 操作系统。获取内存映射并退出引导服务后,我打印内存映射并注意到所有条目都将某个物理地址映射到虚拟地址 0。以下是内存映射中第一个条目的屏幕截图: 这是我用于内存描述符的结构:
#[repr(C)]
#[derive(Clone, Copy)]
pub struct MemoryDescriptor {
pub t: MemoryType,
pub physical_start: *const c_void,
pub virtual_start: *const c_void,
pub number_of_pages: u64,
pub attribute: u64,
}
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum MemoryType {
ReservedMemoryType = 0,
LoaderCode,
LoaderData,
BootServicesCode,
BootServicesData,
RuntimeServicesCode,
RuntimeServicesData,
ConventionalMemory,
UnusableMemory,
ACPIReclaimMemory,
ACPIMemoryNVS,
MemoryMappedIO,
MemoryMappedIOPortSpace,
PalCode,
PersistentMemory,
UnacceptedMemoryType,
MaxMemoryType,
}
我检查了我是否正确地迭代了内存映射(通过 GetMemoryMap 函数提供的描述符大小而不是描述符结构的大小来增加内存映射指针),但仍然无法理解它。 UEFI 规范表示它标识映射所有内存,但这是否意味着我应该看到所有物理地址都等于内存映射中的虚拟地址?或者我错过了什么?这似乎在 QEMU 和真实硬件(Surface pro 8)上都会发生。我还尝试查看页表(通过 CR3 中的地址),尽管我认为我做错了什么(或者页面没有正确映射),因为只有 4 级表的第一个条目似乎是存在并且它指向没有当前条目的 3 级页面。
显然,退出引导服务之前获得的内存映射中的虚拟地址只是占位符。您必须手动将它们设置为身份映射,然后调用 SetMemoryMap 函数才能更新它们(退出引导服务后)。这为我解决了这个问题