use crate::TagType;
use core::marker::PhantomData;
#[derive(Debug)]
#[repr(C)]
pub struct MemoryMapTag {
typ: TagType,
size: u32,
entry_size: u32,
entry_version: u32,
first_area: MemoryArea,
}
impl MemoryMapTag {
pub fn memory_areas(&self) -> impl Iterator<Item = &MemoryArea> {
self.all_memory_areas()
.filter(|entry| matches!(entry.typ, MemoryAreaType::Available))
}
pub fn all_memory_areas(&self) -> impl Iterator<Item = &MemoryArea> {
let self_ptr = self as *const MemoryMapTag;
let start_area = (&self.first_area) as *const MemoryArea;
MemoryAreaIter {
current_area: start_area as u64,
last_area: (self_ptr as u64 + (self.size - self.entry_size) as u64),
entry_size: self.entry_size,
phantom: PhantomData,
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct MemoryArea {
base_addr: u64,
length: u64,
typ: MemoryAreaType,
_reserved: u32,
}
impl MemoryArea {
pub fn start_address(&self) -> u64 {
self.base_addr
}
pub fn end_address(&self) -> u64 {
self.base_addr + self.length
}
pub fn size(&self) -> u64 {
self.length
}
pub fn typ(&self) -> MemoryAreaType {
self.typ
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[repr(u32)]
pub enum MemoryAreaType {
Available = 1,
Reserved = 2,
AcpiAvailable = 3,
ReservedHibernate = 4,
Defective = 5,
}
#[derive(Clone, Debug)]
pub struct MemoryAreaIter<'a> {
current_area: u64,
last_area: u64,
entry_size: u32,
phantom: PhantomData<&'a MemoryArea>,
}
impl<'a> Iterator for MemoryAreaIter<'a> {
type Item = &'a MemoryArea;
fn next(&mut self) -> Option<&'a MemoryArea> {
if self.current_area > self.last_area {
None
} else {
let area = unsafe { &*(self.current_area as *const MemoryArea) };
self.current_area += self.entry_size as u64;
Some(area)
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct EFIMemoryMapTag {
typ: TagType,
size: u32,
desc_size: u32,
desc_version: u32,
first_desc: EFIMemoryDesc,
}
impl EFIMemoryMapTag {
pub fn memory_areas(&self) -> EFIMemoryAreaIter {
let self_ptr = self as *const EFIMemoryMapTag;
let start_area = (&self.first_desc) as *const EFIMemoryDesc;
EFIMemoryAreaIter {
current_area: start_area as u64,
last_area: (self_ptr as u64 + self.size as u64),
entry_size: self.desc_size,
phantom: PhantomData,
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct EFIMemoryDesc {
typ: u32,
_padding: u32,
phys_addr: u64,
virt_addr: u64,
num_pages: u64,
attr: u64,
}
#[derive(Debug, PartialEq, Eq)]
pub enum EFIMemoryAreaType {
EfiReservedMemoryType,
EfiLoaderCode,
EfiLoaderData,
EfiBootServicesCode,
EfiBootServicesData,
EfiRuntimeServicesCode,
EfiRuntimeServicesData,
EfiConventionalMemory,
EfiUnusableMemory,
EfiACPIReclaimMemory,
EfiACPIMemoryNVS,
EfiMemoryMappedIO,
EfiMemoryMappedIOPortSpace,
EfiPalCode,
EfiPersistentMemory,
EfiUnknown,
}
impl EFIMemoryDesc {
pub fn physical_address(&self) -> u64 {
self.phys_addr
}
pub fn virtual_address(&self) -> u64 {
self.virt_addr
}
pub fn size(&self) -> u64 {
self.num_pages * 4096
}
pub fn typ(&self) -> EFIMemoryAreaType {
match self.typ {
0 => EFIMemoryAreaType::EfiReservedMemoryType,
1 => EFIMemoryAreaType::EfiLoaderCode,
2 => EFIMemoryAreaType::EfiLoaderData,
3 => EFIMemoryAreaType::EfiBootServicesCode,
4 => EFIMemoryAreaType::EfiBootServicesData,
5 => EFIMemoryAreaType::EfiRuntimeServicesCode,
6 => EFIMemoryAreaType::EfiRuntimeServicesData,
7 => EFIMemoryAreaType::EfiConventionalMemory,
8 => EFIMemoryAreaType::EfiUnusableMemory,
9 => EFIMemoryAreaType::EfiACPIReclaimMemory,
10 => EFIMemoryAreaType::EfiACPIMemoryNVS,
11 => EFIMemoryAreaType::EfiMemoryMappedIO,
12 => EFIMemoryAreaType::EfiMemoryMappedIOPortSpace,
13 => EFIMemoryAreaType::EfiPalCode,
14 => EFIMemoryAreaType::EfiPersistentMemory,
_ => EFIMemoryAreaType::EfiUnknown,
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct EFIBootServicesNotExited {
typ: u32,
size: u32,
}
#[derive(Clone, Debug)]
pub struct EFIMemoryAreaIter<'a> {
current_area: u64,
last_area: u64,
entry_size: u32,
phantom: PhantomData<&'a EFIMemoryDesc>,
}
impl<'a> Iterator for EFIMemoryAreaIter<'a> {
type Item = &'a EFIMemoryDesc;
fn next(&mut self) -> Option<&'a EFIMemoryDesc> {
if self.current_area > self.last_area {
None
} else {
let area = unsafe { &*(self.current_area as *const EFIMemoryDesc) };
self.current_area += self.entry_size as u64;
Some(area)
}
}
}