use core::{
cmp::{max, min},
default::Default,
ffi::c_void,
ops::Range,
};
use r_efi::{
efi::{Guid, Handle, PhysicalAddress, Status},
system::TableHeader,
};
pub const DXE_SERVICES_TABLE_GUID: crate::BinaryGuid =
crate::BinaryGuid::from_string("05AD34BA-6F02-4214-952E-4DA0398E2BB9");
pub type AddMemorySpace = extern "efiapi" fn(GcdMemoryType, PhysicalAddress, u64, u64) -> Status;
pub type AllocateMemorySpace =
extern "efiapi" fn(GcdAllocateType, GcdMemoryType, usize, u64, *mut PhysicalAddress, Handle, Handle) -> Status;
pub type FreeMemorySpace = extern "efiapi" fn(PhysicalAddress, u64) -> Status;
pub type RemoveMemorySpace = extern "efiapi" fn(PhysicalAddress, u64) -> Status;
pub type GetMemorySpaceDescriptor = extern "efiapi" fn(PhysicalAddress, *mut MemorySpaceDescriptor) -> Status;
pub type SetMemorySpaceAttributes = extern "efiapi" fn(PhysicalAddress, u64, u64) -> Status;
pub type SetMemorySpaceCapabilities = extern "efiapi" fn(PhysicalAddress, u64, u64) -> Status;
pub type GetMemorySpaceMap = extern "efiapi" fn(*mut usize, *mut *mut MemorySpaceDescriptor) -> Status;
pub type AddIoSpace = extern "efiapi" fn(GcdIoType, PhysicalAddress, u64) -> Status;
pub type AllocateIoSpace =
extern "efiapi" fn(GcdAllocateType, GcdIoType, usize, u64, *mut PhysicalAddress, Handle, Handle) -> Status;
pub type FreeIoSpace = extern "efiapi" fn(PhysicalAddress, u64) -> Status;
pub type RemoveIoSpace = extern "efiapi" fn(PhysicalAddress, u64) -> Status;
pub type GetIoSpaceDescriptor = extern "efiapi" fn(PhysicalAddress, *mut IoSpaceDescriptor) -> Status;
pub type GetIoSpaceMap = extern "efiapi" fn(*mut usize, *mut *mut IoSpaceDescriptor) -> Status;
pub type Dispatch = extern "efiapi" fn() -> Status;
pub type Schedule = extern "efiapi" fn(Handle, *const Guid) -> Status;
pub type Trust = extern "efiapi" fn(Handle, *const Guid) -> Status;
pub type ProcessFirmwareVolume = extern "efiapi" fn(*const c_void, usize, *mut Handle) -> Status;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum GcdMemoryType {
#[default]
NonExistent = 0,
Reserved,
SystemMemory,
MemoryMappedIo,
Persistent,
MoreReliable,
Unaccepted,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub enum GcdAllocateType {
#[default]
AnySearchBottomUp,
MaxAddressSearchBottomUp,
Address,
AnySearchTopDown,
MaxAddressSearchTopDown,
MaxAllocateType,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MemorySpaceDescriptor {
pub base_address: PhysicalAddress,
pub length: u64,
pub capabilities: u64,
pub attributes: u64,
pub memory_type: GcdMemoryType,
pub image_handle: Handle,
pub device_handle: Handle,
}
impl MemorySpaceDescriptor {
pub fn get_range_overlap_with_desc(&self, range: &Range<PhysicalAddress>) -> Range<PhysicalAddress> {
let desc_end = self.base_address.saturating_add(self.length);
if self.base_address >= range.end || desc_end <= range.start {
return 0..0;
}
let overlap_start = max(self.base_address, range.start);
let overlap_end = min(desc_end, range.end);
overlap_start..overlap_end
}
pub fn is_efi_memory_map_descriptor(&self) -> Option<r_efi::efi::MemoryType> {
use crate::base::{UEFI_PAGE_MASK, UEFI_PAGE_SIZE};
let number_of_pages = ((self.length as usize + UEFI_PAGE_MASK) / UEFI_PAGE_SIZE) as u64;
if number_of_pages == 0 {
debug_assert!(false, "GCD returned a memory descriptor smaller than a page.");
return None; }
if !self.base_address.is_multiple_of(UEFI_PAGE_SIZE as u64) {
debug_assert!(false, "GCD returned a non-page-aligned memory descriptor.");
return None; }
match self.memory_type {
GcdMemoryType::SystemMemory => Some(r_efi::efi::CONVENTIONAL_MEMORY),
GcdMemoryType::MemoryMappedIo => {
if self.attributes & r_efi::efi::MEMORY_RUNTIME == 0 {
None
} else {
Some(r_efi::efi::MEMORY_MAPPED_IO)
}
}
GcdMemoryType::Persistent => Some(r_efi::efi::PERSISTENT_MEMORY),
GcdMemoryType::Unaccepted => Some(r_efi::efi::UNACCEPTED_MEMORY_TYPE),
GcdMemoryType::Reserved => Some(r_efi::efi::RESERVED_MEMORY_TYPE),
_ => None,
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum GcdIoType {
#[default]
NonExistent = 0,
Reserved,
Io,
Maximum,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct IoSpaceDescriptor {
pub base_address: PhysicalAddress,
pub length: u64,
pub io_type: GcdIoType,
pub image_handle: Handle,
pub device_handle: Handle,
}
#[repr(C)]
pub struct DxeServicesTable {
pub header: TableHeader,
pub add_memory_space: AddMemorySpace,
pub allocate_memory_space: AllocateMemorySpace,
pub free_memory_space: FreeMemorySpace,
pub remove_memory_space: RemoveMemorySpace,
pub get_memory_space_descriptor: GetMemorySpaceDescriptor,
pub set_memory_space_attributes: SetMemorySpaceAttributes,
pub get_memory_space_map: GetMemorySpaceMap,
pub add_io_space: AddIoSpace,
pub allocate_io_space: AllocateIoSpace,
pub free_io_space: FreeIoSpace,
pub remove_io_space: RemoveIoSpace,
pub get_io_space_descriptor: GetIoSpaceDescriptor,
pub get_io_space_map: GetIoSpaceMap,
pub dispatch: Dispatch,
pub schedule: Schedule,
pub trust: Trust,
pub process_firmware_volume: ProcessFirmwareVolume,
pub set_memory_space_capabilities: SetMemorySpaceCapabilities,
}
impl Default for MemorySpaceDescriptor {
fn default() -> Self {
Self {
base_address: Default::default(),
length: Default::default(),
capabilities: Default::default(),
attributes: Default::default(),
memory_type: Default::default(),
image_handle: 0 as Handle,
device_handle: 0 as Handle,
}
}
}
impl Default for IoSpaceDescriptor {
fn default() -> Self {
Self {
base_address: Default::default(),
length: Default::default(),
io_type: Default::default(),
image_handle: 0 as Handle,
device_handle: 0 as Handle,
}
}
}
#[cfg(test)]
#[coverage(off)]
mod tests {
use super::*;
#[test]
fn test_get_range_overlap_with_desc() {
let desc = MemorySpaceDescriptor { base_address: 0x10000, length: 0x5000, ..Default::default() };
let range = 0x0000..0x0FFF;
let overlap = desc.get_range_overlap_with_desc(&range);
assert_eq!(overlap, 0..0);
let range = 0x20000..0x2FFFF;
let overlap = desc.get_range_overlap_with_desc(&range);
assert_eq!(overlap, 0..0);
let range = 0x9000..0x13000;
let overlap = desc.get_range_overlap_with_desc(&range);
assert_eq!(overlap, 0x10000..0x13000);
let range = 0x11000..0x25000;
let overlap = desc.get_range_overlap_with_desc(&range);
assert_eq!(overlap, 0x11000..0x15000);
let range = 0x10000..0x20000;
let overlap = desc.get_range_overlap_with_desc(&range);
assert_eq!(overlap, 0x10000..0x15000);
let range = 0x11000..0x12000;
let overlap = desc.get_range_overlap_with_desc(&range);
assert_eq!(overlap, 0x11000..0x12000);
let range = 0x10000..0x15000;
let overlap = desc.get_range_overlap_with_desc(&range);
assert_eq!(overlap, 0x10000..0x15000);
}
}