use core::marker::PhantomData; /// This Tag provides an initial host memory map. /// /// The map provided is guaranteed to list all standard RAM that should be /// available for normal use. This type however includes the regions occupied /// by kernel, mbi, segments and modules. Kernel must take care not to /// overwrite these regions. /// /// This tag may not be provided by some boot loaders on EFI platforms if EFI /// boot services are enabled and available for the loaded image (The EFI boot /// services tag may exist in the Multiboot2 boot information structure). #[derive(Debug)] #[repr(C)] pub struct MemoryMapTag { typ: u32, size: u32, entry_size: u32, entry_version: u32, first_area: MemoryArea, } impl MemoryMapTag { /// Return an iterator over all AVAILABLE marked memory areas. pub fn memory_areas(&self) -> MemoryAreaIter { 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, } } } /// A memory area entry descriptor. #[derive(Debug)] #[repr(C)] pub struct MemoryArea { base_addr: u64, length: u64, typ: u32, _reserved: u32, } impl MemoryArea { /// The start address of the memory region. pub fn start_address(&self) -> u64 { self.base_addr } /// The end address of the memory region. pub fn end_address(&self) -> u64 { self.base_addr + self.length } /// The size, in bytes, of the memory region. pub fn size(&self) -> u64 { self.length } /// The type of the memory region. pub fn typ(&self) -> MemoryAreaType { match self.typ { 1 => MemoryAreaType::Available, 3 => MemoryAreaType::AcpiAvailable, 4 => MemoryAreaType::ReservedHibernate, 5 => MemoryAreaType::Defective, _ => MemoryAreaType::Reserved, } } } /// An enum of possible reported region types. #[derive(Debug, PartialEq, Eq)] pub enum MemoryAreaType { /// A reserved area that must not be used. Reserved, /// Available memory free to be used by the OS. Available, /// Usable memory holding ACPI information. AcpiAvailable, /// Reserved memory which needs to be preserved on hibernation. ReservedHibernate, /// Memory which is occupied by defective RAM modules. Defective, } /// An iterator over Available memory areas. #[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.current_area + (self.entry_size as u64); if area.typ == 1 { Some(area) } else {self.next()} } } } /// EFI memory map as per EFI specification. #[derive(Debug)] #[repr(C)] pub struct EFIMemoryMapTag { typ: u32, size: u32, desc_size: u32, desc_version: u32, first_desc: EFIMemoryDesc, } impl EFIMemoryMapTag { /// Return an iterator over ALL marked memory areas. /// /// This differs from `MemoryMapTag` as for UEFI, the OS needs some non- /// available memory areas for tables and such. 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, } } } /// EFI Boot Memory Map Descriptor #[derive(Debug)] #[repr(C)] pub struct EFIMemoryDesc { typ: u32, _padding: u32, phys_addr: u64, virt_addr: u64, num_pages: u64, attr: u64, } /// An enum of possible reported region types. #[derive(Debug, PartialEq, Eq)] pub enum EFIMemoryAreaType { /// Unusable. EfiReservedMemoryType, /// Code area of a UEFI application. EfiLoaderCode, /// Data area of a UEFI application. EfiLoaderData, /// Code area of a UEFI Boot Service Driver. EfiBootServicesCode, /// Data area of a UEFI Boot Service Driver. EfiBootServicesData, /// Code area of a UEFI Runtime Driver. /// /// Must be preserved in working and ACPI S1-S3 states. EfiRuntimeServicesCode, /// Data area of a UEFI Runtime Driver. /// /// Must be preserved in working and ACPI S1-S3 states. EfiRuntimeServicesData, /// Available memory. EfiConventionalMemory, /// Memory with errors, treat as unusable. EfiUnusableMemory, /// Memory containing the ACPI tables. /// /// Must be preserved in working and ACPI S1-S3 states. EfiACPIReclaimMemory, /// Memory reserved by firmware. /// /// Must be preserved in working and ACPI S1-S3 states. EfiACPIMemoryNVS, /// Memory used by firmware for requesting memory mapping of IO. /// /// Should not be used by the OS. Use the ACPI tables for memory mapped IO /// information. EfiMemoryMappedIO, /// Memory used to translate memory cycles to IO cycles. /// /// Should not be used by the OS. Use the ACPI tables for memory mapped IO /// information. EfiMemoryMappedIOPortSpace, /// Memory used by the processor. /// /// Must be preserved in working and ACPI S1-S4 states. Processor defined /// otherwise. EfiPalCode, /// Available memory supporting byte-addressable non-volatility. EfiPersistentMemory, /// Unknown region type, treat as unusable. EfiUnknown, } impl EFIMemoryDesc { /// The physical address of the memory region. pub fn physical_address(&self) -> u64 { self.phys_addr } /// The virtual address of the memory region. pub fn virtual_address(&self) -> u64 { self.virt_addr } /// The size in bytes of the memory region. pub fn size(&self, page_size: u64) -> usize { (self.num_pages * page_size) as usize } /// The type of the memory region. 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, } } } /// EFI ExitBootServices was not called #[derive(Debug)] #[repr(C)] pub struct EFIBootServicesNotExited { typ: u32, size: u32, } /// Contains pointer to boot loader image handle. #[derive(Debug)] #[repr(C)] pub struct EFIImageHandle32 { typ: u32, size: u32, pointer: u32, } /// Contains pointer to boot loader image handle. #[derive(Debug)] #[repr(C)] pub struct EFIImageHandle64 { typ: u32, size: u32, pointer: u64, } /// If the image has relocatable header tag, this tag contains the image's /// base physical address. #[derive(Debug)] #[repr(C)] pub struct ImageLoadPhysAddr { typ: u32, size: u32, load_base_addr: u32, } /// An iterator over All EFI memory areas. #[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.current_area + (self.entry_size as u64); if area.typ() == EFIMemoryAreaType::EfiConventionalMemory { Some(area) } else {self.next()} } } }