use crate::{Tag, TagTrait, TagType, TagTypeId};
use core::convert::TryInto;
use core::fmt::Debug;
use core::marker::PhantomData;
use core::mem;
pub use uefi_raw::table::boot::MemoryDescriptor as EFIMemoryDesc;
pub use uefi_raw::table::boot::MemoryType as EFIMemoryAreaType;
#[cfg(feature = "builder")]
use {crate::builder::traits::StructAsBytes, crate::builder::BoxedDst};
const METADATA_SIZE: usize = mem::size_of::<TagTypeId>() + 3 * mem::size_of::<u32>();
#[derive(ptr_meta::Pointee, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct MemoryMapTag {
typ: TagTypeId,
size: u32,
entry_size: u32,
entry_version: u32,
areas: [MemoryArea],
}
impl MemoryMapTag {
#[cfg(feature = "builder")]
pub fn new(areas: &[MemoryArea]) -> BoxedDst<Self> {
let entry_size: u32 = mem::size_of::<MemoryArea>().try_into().unwrap();
let entry_version: u32 = 0;
let mut bytes = [entry_size.to_le_bytes(), entry_version.to_le_bytes()].concat();
for area in areas {
bytes.extend(area.struct_as_bytes());
}
BoxedDst::new(TagType::Mmap, bytes.as_slice())
}
pub fn entry_size(&self) -> u32 {
self.entry_size
}
pub fn entry_version(&self) -> u32 {
self.entry_version
}
pub fn memory_areas(&self) -> &[MemoryArea] {
assert_eq!(self.entry_size as usize, mem::size_of::<MemoryArea>());
&self.areas
}
}
impl TagTrait for MemoryMapTag {
fn dst_size(base_tag: &Tag) -> usize {
assert!(base_tag.size as usize >= METADATA_SIZE);
let size = base_tag.size as usize - METADATA_SIZE;
assert_eq!(size % mem::size_of::<MemoryArea>(), 0);
size / mem::size_of::<MemoryArea>()
}
}
#[cfg(feature = "builder")]
impl StructAsBytes for MemoryMapTag {
fn byte_size(&self) -> usize {
self.size.try_into().unwrap()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct MemoryArea {
base_addr: u64,
length: u64,
typ: MemoryAreaType,
_reserved: u32,
}
impl MemoryArea {
pub fn new(base_addr: u64, length: u64, typ: MemoryAreaType) -> Self {
Self {
base_addr,
length,
typ,
_reserved: 0,
}
}
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
}
}
#[cfg(feature = "builder")]
impl StructAsBytes for MemoryArea {
fn byte_size(&self) -> usize {
mem::size_of::<Self>()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u32)]
pub enum MemoryAreaType {
Available = 1,
Reserved = 2,
AcpiAvailable = 3,
ReservedHibernate = 4,
Defective = 5,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct BasicMemoryInfoTag {
typ: TagTypeId,
size: u32,
memory_lower: u32,
memory_upper: u32,
}
impl BasicMemoryInfoTag {
pub fn new(memory_lower: u32, memory_upper: u32) -> Self {
Self {
typ: TagType::BasicMeminfo.into(),
size: mem::size_of::<BasicMemoryInfoTag>().try_into().unwrap(),
memory_lower,
memory_upper,
}
}
pub fn memory_lower(&self) -> u32 {
self.memory_lower
}
pub fn memory_upper(&self) -> u32 {
self.memory_upper
}
}
#[cfg(feature = "builder")]
impl StructAsBytes for BasicMemoryInfoTag {
fn byte_size(&self) -> usize {
mem::size_of::<Self>()
}
}
const EFI_METADATA_SIZE: usize = mem::size_of::<TagTypeId>() + 3 * mem::size_of::<u32>();
#[derive(ptr_meta::Pointee, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct EFIMemoryMapTag {
typ: TagTypeId,
size: u32,
desc_size: u32,
desc_version: u32,
descs: [EFIMemoryDesc],
}
impl EFIMemoryMapTag {
#[cfg(feature = "builder")]
pub fn new(descs: &[EFIMemoryDesc]) -> BoxedDst<Self> {
const MEMORY_DESCRIPTOR_VERSION: u32 = 1;
let mut bytes = [
(mem::size_of::<EFIMemoryDesc>() as u32).to_le_bytes(),
MEMORY_DESCRIPTOR_VERSION.to_le_bytes(),
]
.concat();
for desc in descs {
bytes.extend(desc.struct_as_bytes());
}
BoxedDst::new(TagType::EfiMmap, bytes.as_slice())
}
pub fn memory_areas(&self) -> EFIMemoryAreaIter {
let self_ptr = self as *const EFIMemoryMapTag;
let start_area = (&self.descs[0]) as *const EFIMemoryDesc;
EFIMemoryAreaIter {
current_area: start_area as u64,
last_area: (self_ptr as *const () as u64 + self.size as u64),
entry_size: self.desc_size,
phantom: PhantomData,
}
}
}
impl TagTrait for EFIMemoryMapTag {
fn dst_size(base_tag: &Tag) -> usize {
assert!(base_tag.size as usize >= EFI_METADATA_SIZE);
let size = base_tag.size as usize - EFI_METADATA_SIZE;
assert_eq!(size % mem::size_of::<EFIMemoryDesc>(), 0);
size / mem::size_of::<EFIMemoryDesc>()
}
}
#[cfg(feature = "builder")]
impl StructAsBytes for EFIMemoryMapTag {
fn byte_size(&self) -> usize {
self.size.try_into().unwrap()
}
}
#[cfg(feature = "builder")]
impl StructAsBytes for EFIMemoryDesc {
fn byte_size(&self) -> usize {
mem::size_of::<Self>()
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
pub struct EFIBootServicesNotExitedTag {
typ: TagTypeId,
size: u32,
}
impl EFIBootServicesNotExitedTag {
#[cfg(feature = "builder")]
pub fn new() -> Self {
Self::default()
}
}
#[cfg(feature = "builder")]
impl Default for EFIBootServicesNotExitedTag {
fn default() -> Self {
Self {
typ: TagType::EfiBs.into(),
size: mem::size_of::<Self>().try_into().unwrap(),
}
}
}
#[cfg(feature = "builder")]
impl StructAsBytes for EFIBootServicesNotExitedTag {
fn byte_size(&self) -> usize {
mem::size_of::<Self>()
}
}
#[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)
}
}
}