use crate::pi::BootMode;
use core::{
ffi::c_void,
marker::PhantomData,
mem::{self, size_of},
slice,
};
#[cfg(any(test, feature = "alloc"))]
pub mod hob_list;
#[cfg(any(test, feature = "alloc"))]
pub use hob_list::HobList;
#[cfg(target_arch = "x86_64")]
pub type EfiPhysicalAddress = u64;
#[cfg(target_arch = "aarch64")]
pub type EfiPhysicalAddress = u64;
#[cfg(target_arch = "x86")]
pub type EfiPhysicalAddress = u32;
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))]
compile_error!("This crate only (currently) supports x86, x86_64, and aarch64 architectures");
pub const HANDOFF: u16 = 0x0001;
pub const MEMORY_ALLOCATION: u16 = 0x0002;
pub const RESOURCE_DESCRIPTOR: u16 = 0x0003;
pub const GUID_EXTENSION: u16 = 0x0004;
pub const FV: u16 = 0x0005;
pub const CPU: u16 = 0x0006;
pub const MEMORY_POOL: u16 = 0x0007;
pub const FV2: u16 = 0x0009;
pub const LOAD_PEIM_UNUSED: u16 = 0x000A;
pub const UEFI_CAPSULE: u16 = 0x000B;
pub const FV3: u16 = 0x000C;
pub const RESOURCE_DESCRIPTOR2: u16 = 0x000D;
pub const UNUSED: u16 = 0xFFFE;
pub const END_OF_HOB_LIST: u16 = 0xFFFF;
pub mod header {
use crate::pi::hob::EfiPhysicalAddress;
use r_efi::system::MemoryType;
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Hob {
pub r#type: u16,
pub length: u16,
pub reserved: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MemoryAllocation {
pub name: crate::BinaryGuid,
pub memory_base_address: EfiPhysicalAddress,
pub memory_length: u64,
pub memory_type: MemoryType,
pub reserved: [u8; 4],
}
}
pub type MemoryPool = header::Hob;
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct PhaseHandoffInformationTable {
pub header: header::Hob,
pub version: u32,
pub boot_mode: BootMode,
pub memory_top: EfiPhysicalAddress,
pub memory_bottom: EfiPhysicalAddress,
pub free_memory_top: EfiPhysicalAddress,
pub free_memory_bottom: EfiPhysicalAddress,
pub end_of_hob_list: EfiPhysicalAddress,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct MemoryAllocation {
pub header: header::Hob,
pub alloc_descriptor: header::MemoryAllocation,
}
pub type MemoryAllocationStack = MemoryAllocation;
pub type MemoryAllocationBspStore = MemoryAllocation;
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MemoryAllocationModule {
pub header: header::Hob,
pub alloc_descriptor: header::MemoryAllocation,
pub module_name: crate::BinaryGuid,
pub entry_point: u64, }
pub const EFI_RESOURCE_SYSTEM_MEMORY: u32 = 0x00000000;
pub const EFI_RESOURCE_MEMORY_MAPPED_IO: u32 = 0x00000001;
pub const EFI_RESOURCE_IO: u32 = 0x00000002;
pub const EFI_RESOURCE_FIRMWARE_DEVICE: u32 = 0x00000003;
pub const EFI_RESOURCE_MEMORY_MAPPED_IO_PORT: u32 = 0x00000004;
pub const EFI_RESOURCE_MEMORY_RESERVED: u32 = 0x00000005;
pub const EFI_RESOURCE_IO_RESERVED: u32 = 0x00000006;
pub const EFI_RESOURCE_MAX_MEMORY_TYPE: u32 = 0x00000007;
pub const EFI_RESOURCE_ATTRIBUTE_PRESENT: u32 = 0x00000001;
pub const EFI_RESOURCE_ATTRIBUTE_INITIALIZED: u32 = 0x00000002;
pub const EFI_RESOURCE_ATTRIBUTE_TESTED: u32 = 0x00000004;
pub const EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED: u32 = 0x00000080;
pub const EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED: u32 = 0x00000100;
pub const EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED: u32 = 0x00000200;
pub const EFI_RESOURCE_ATTRIBUTE_PERSISTENT: u32 = 0x00800000;
pub const EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE: u32 = 0x02000000;
pub const EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC: u32 = 0x00000008;
pub const EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC: u32 = 0x00000010;
pub const EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1: u32 = 0x00000020;
pub const EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2: u32 = 0x00000040;
pub const EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE: u32 = 0x00000400;
pub const EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE: u32 = 0x00000800;
pub const EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE: u32 = 0x00001000;
pub const EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE: u32 = 0x00002000;
pub const EFI_RESOURCE_ATTRIBUTE_16_BIT_IO: u32 = 0x00004000;
pub const EFI_RESOURCE_ATTRIBUTE_32_BIT_IO: u32 = 0x00008000;
pub const EFI_RESOURCE_ATTRIBUTE_64_BIT_IO: u32 = 0x00010000;
pub const EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED: u32 = 0x00020000;
pub const EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE: u32 = 0x00100000;
pub const EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE: u32 = 0x00200000;
pub const EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE: u32 = 0x00400000;
pub const EFI_RESOURCE_ATTRIBUTE_PERSISTABLE: u32 = 0x01000000;
pub const EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED: u32 = 0x00040000;
pub const EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE: u32 = 0x00080000;
pub const MEMORY_ATTRIBUTE_MASK: u32 = EFI_RESOURCE_ATTRIBUTE_PRESENT
| EFI_RESOURCE_ATTRIBUTE_INITIALIZED
| EFI_RESOURCE_ATTRIBUTE_TESTED
| EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED
| EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED
| EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
| EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED
| EFI_RESOURCE_ATTRIBUTE_16_BIT_IO
| EFI_RESOURCE_ATTRIBUTE_32_BIT_IO
| EFI_RESOURCE_ATTRIBUTE_64_BIT_IO
| EFI_RESOURCE_ATTRIBUTE_PERSISTENT;
pub const TESTED_MEMORY_ATTRIBUTES: u32 =
EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED;
pub const INITIALIZED_MEMORY_ATTRIBUTES: u32 = EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED;
pub const PRESENT_MEMORY_ATTRIBUTES: u32 = EFI_RESOURCE_ATTRIBUTE_PRESENT;
pub const EFI_MEMORY_PRESENT: u64 = 0x0100_0000_0000_0000;
pub const EFI_MEMORY_INITIALIZED: u64 = 0x0200_0000_0000_0000;
pub const EFI_MEMORY_TESTED: u64 = 0x0400_0000_0000_0000;
pub const EFI_MEMORY_NV: u64 = 0x0000_0000_0000_8000;
pub const EFI_MEMORY_MORE_RELIABLE: u64 = 0x0000_0000_0001_0000;
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ResourceDescriptor {
pub header: header::Hob,
pub owner: crate::BinaryGuid,
pub resource_type: u32,
pub resource_attribute: u32,
pub physical_start: EfiPhysicalAddress,
pub resource_length: u64,
}
impl ResourceDescriptor {
pub fn attributes_valid(&self) -> bool {
(self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED == 0
|| self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE != 0)
&& (self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED == 0
|| self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE != 0)
&& (self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED == 0
|| self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE != 0)
&& (self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED == 0
|| self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE != 0)
&& (self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT == 0
|| self.resource_attribute & EFI_RESOURCE_ATTRIBUTE_PERSISTABLE != 0)
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ResourceDescriptorV2 {
pub v1: ResourceDescriptor,
pub attributes: u64,
}
impl From<ResourceDescriptor> for ResourceDescriptorV2 {
fn from(mut v1: ResourceDescriptor) -> Self {
v1.header.r#type = RESOURCE_DESCRIPTOR2;
ResourceDescriptorV2 { v1, attributes: 0 }
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct GuidHob {
pub header: header::Hob,
pub name: crate::BinaryGuid,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FirmwareVolume {
pub header: header::Hob,
pub base_address: EfiPhysicalAddress,
pub length: u64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FirmwareVolume2 {
pub header: header::Hob,
pub base_address: EfiPhysicalAddress,
pub length: u64,
pub fv_name: crate::BinaryGuid,
pub file_name: crate::BinaryGuid,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FirmwareVolume3 {
pub header: header::Hob,
pub base_address: EfiPhysicalAddress,
pub length: u64,
pub authentication_status: u32,
pub extracted_fv: r_efi::efi::Boolean,
pub fv_name: crate::BinaryGuid,
pub file_name: crate::BinaryGuid,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Cpu {
pub header: header::Hob,
pub size_of_memory_space: u8,
pub size_of_io_space: u8,
pub reserved: [u8; 6],
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Capsule {
pub header: header::Hob,
pub base_address: EfiPhysicalAddress,
pub length: u64,
}
#[derive(Clone, Debug)]
pub enum Hob<'a> {
Handoff(&'a PhaseHandoffInformationTable),
MemoryAllocation(&'a MemoryAllocation),
MemoryAllocationModule(&'a MemoryAllocationModule),
Capsule(&'a Capsule),
ResourceDescriptor(&'a ResourceDescriptor),
GuidHob(&'a GuidHob, &'a [u8]),
FirmwareVolume(&'a FirmwareVolume),
FirmwareVolume2(&'a FirmwareVolume2),
FirmwareVolume3(&'a FirmwareVolume3),
Cpu(&'a Cpu),
ResourceDescriptorV2(&'a ResourceDescriptorV2),
Misc(u16),
}
pub trait HobTrait {
fn size(&self) -> usize;
fn as_ptr<T>(&self) -> *const T;
}
impl HobTrait for Hob<'_> {
fn size(&self) -> usize {
match self {
Hob::Handoff(_) => size_of::<PhaseHandoffInformationTable>(),
Hob::MemoryAllocation(_) => size_of::<MemoryAllocation>(),
Hob::MemoryAllocationModule(_) => size_of::<MemoryAllocationModule>(),
Hob::Capsule(_) => size_of::<Capsule>(),
Hob::ResourceDescriptor(_) => size_of::<ResourceDescriptor>(),
Hob::GuidHob(hob, _) => hob.header.length as usize,
Hob::FirmwareVolume(_) => size_of::<FirmwareVolume>(),
Hob::FirmwareVolume2(_) => size_of::<FirmwareVolume2>(),
Hob::FirmwareVolume3(_) => size_of::<FirmwareVolume3>(),
Hob::Cpu(_) => size_of::<Cpu>(),
Hob::ResourceDescriptorV2(_) => size_of::<ResourceDescriptorV2>(),
Hob::Misc(_) => size_of::<u16>(),
}
}
fn as_ptr<T>(&self) -> *const T {
match self {
Hob::Handoff(hob) => *hob as *const PhaseHandoffInformationTable as *const _,
Hob::MemoryAllocation(hob) => *hob as *const MemoryAllocation as *const _,
Hob::MemoryAllocationModule(hob) => *hob as *const MemoryAllocationModule as *const _,
Hob::Capsule(hob) => *hob as *const Capsule as *const _,
Hob::ResourceDescriptor(hob) => *hob as *const ResourceDescriptor as *const _,
Hob::GuidHob(hob, _) => *hob as *const GuidHob as *const _,
Hob::FirmwareVolume(hob) => *hob as *const FirmwareVolume as *const _,
Hob::FirmwareVolume2(hob) => *hob as *const FirmwareVolume2 as *const _,
Hob::FirmwareVolume3(hob) => *hob as *const FirmwareVolume3 as *const _,
Hob::Cpu(hob) => *hob as *const Cpu as *const _,
Hob::ResourceDescriptorV2(hob) => *hob as *const ResourceDescriptorV2 as *const _,
Hob::Misc(hob) => *hob as *const u16 as *const _,
}
}
}
pub unsafe fn get_pi_hob_list_size(hob_list: *const c_void) -> usize {
let mut hob_header: *const header::Hob = hob_list as *const header::Hob;
let mut hob_list_len = 0;
loop {
let current_header = unsafe { hob_header.cast::<header::Hob>().as_ref().expect("Could not get hob list len") };
hob_list_len += current_header.length as usize;
if current_header.r#type == END_OF_HOB_LIST {
break;
}
let next_hob = hob_header as usize + current_header.length as usize;
hob_header = next_hob as *const header::Hob;
}
hob_list_len
}
impl Hob<'_> {
pub fn header(&self) -> header::Hob {
match self {
Hob::Handoff(hob) => hob.header,
Hob::MemoryAllocation(hob) => hob.header,
Hob::MemoryAllocationModule(hob) => hob.header,
Hob::Capsule(hob) => hob.header,
Hob::ResourceDescriptor(hob) => hob.header,
Hob::GuidHob(hob, _) => hob.header,
Hob::FirmwareVolume(hob) => hob.header,
Hob::FirmwareVolume2(hob) => hob.header,
Hob::FirmwareVolume3(hob) => hob.header,
Hob::Cpu(hob) => hob.header,
Hob::ResourceDescriptorV2(hob) => hob.v1.header,
Hob::Misc(hob_type) => {
header::Hob { r#type: *hob_type, length: mem::size_of::<header::Hob>() as u16, reserved: 0 }
}
}
}
}
pub struct HobIter<'a> {
hob_ptr: *const header::Hob,
_a: PhantomData<&'a ()>,
}
impl<'a> IntoIterator for &Hob<'a> {
type Item = Hob<'a>;
type IntoIter = HobIter<'a>;
fn into_iter(self) -> Self::IntoIter {
HobIter { hob_ptr: self.as_ptr(), _a: PhantomData }
}
}
impl<'a> Iterator for HobIter<'a> {
type Item = Hob<'a>;
fn next(&mut self) -> Option<Self::Item> {
const NOT_NULL: &str = "Ptr should not be NULL";
let hob_header = unsafe { *(self.hob_ptr) };
let hob = unsafe {
match hob_header.r#type {
HANDOFF => {
Hob::Handoff((self.hob_ptr as *const PhaseHandoffInformationTable).as_ref().expect(NOT_NULL))
}
MEMORY_ALLOCATION if hob_header.length as usize == mem::size_of::<MemoryAllocationModule>() => {
Hob::MemoryAllocationModule(
(self.hob_ptr as *const MemoryAllocationModule).as_ref().expect(NOT_NULL),
)
}
MEMORY_ALLOCATION => {
Hob::MemoryAllocation((self.hob_ptr as *const MemoryAllocation).as_ref().expect(NOT_NULL))
}
RESOURCE_DESCRIPTOR => {
Hob::ResourceDescriptor((self.hob_ptr as *const ResourceDescriptor).as_ref().expect(NOT_NULL))
}
GUID_EXTENSION => {
let hob = (self.hob_ptr as *const GuidHob).as_ref().expect(NOT_NULL);
let data_ptr = self.hob_ptr.byte_add(mem::size_of::<GuidHob>()) as *const u8;
let data_len = hob.header.length as usize - mem::size_of::<GuidHob>();
Hob::GuidHob(hob, slice::from_raw_parts(data_ptr, data_len))
}
FV => Hob::FirmwareVolume((self.hob_ptr as *const FirmwareVolume).as_ref().expect(NOT_NULL)),
FV2 => Hob::FirmwareVolume2((self.hob_ptr as *const FirmwareVolume2).as_ref().expect(NOT_NULL)),
FV3 => Hob::FirmwareVolume3((self.hob_ptr as *const FirmwareVolume3).as_ref().expect(NOT_NULL)),
CPU => Hob::Cpu((self.hob_ptr as *const Cpu).as_ref().expect(NOT_NULL)),
UEFI_CAPSULE => Hob::Capsule((self.hob_ptr as *const Capsule).as_ref().expect(NOT_NULL)),
RESOURCE_DESCRIPTOR2 => {
Hob::ResourceDescriptorV2((self.hob_ptr as *const ResourceDescriptorV2).as_ref().expect(NOT_NULL))
}
END_OF_HOB_LIST => return None,
hob_type => Hob::Misc(hob_type),
}
};
self.hob_ptr = (self.hob_ptr as usize + hob_header.length as usize) as *const header::Hob;
Some(hob)
}
}
pub const MEMORY_TYPE_INFO_HOB_GUID: crate::BinaryGuid =
crate::BinaryGuid::from_string("4C19049F-4137-4DD3-9C10-8B97A83FFDFA");
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct EFiMemoryTypeInformation {
pub memory_type: r_efi::efi::MemoryType,
pub number_of_pages: u32,
}
#[cfg(test)]
pub(crate) mod tests {
use crate::pi::{
BootMode, hob,
hob::{
Capsule, Cpu, FirmwareVolume, MemoryAllocation, PhaseHandoffInformationTable, ResourceDescriptor,
get_pi_hob_list_size,
},
};
use core::{mem::size_of, slice::from_raw_parts};
use std::vec::Vec;
pub(crate) fn gen_firmware_volume() -> hob::FirmwareVolume {
let header = hob::header::Hob { r#type: hob::FV, length: size_of::<hob::FirmwareVolume>() as u16, reserved: 0 };
hob::FirmwareVolume { header, base_address: 0, length: 0x0123456789abcdef }
}
pub(crate) fn gen_firmware_volume2() -> hob::FirmwareVolume2 {
let header =
hob::header::Hob { r#type: hob::FV2, length: size_of::<hob::FirmwareVolume2>() as u16, reserved: 0 };
hob::FirmwareVolume2 {
header,
base_address: 0,
length: 0x0123456789abcdef,
fv_name: crate::BinaryGuid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
file_name: crate::BinaryGuid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
}
}
pub(crate) fn gen_firmware_volume3() -> hob::FirmwareVolume3 {
let header =
hob::header::Hob { r#type: hob::FV3, length: size_of::<hob::FirmwareVolume3>() as u16, reserved: 0 };
hob::FirmwareVolume3 {
header,
base_address: 0,
length: 0x0123456789abcdef,
authentication_status: 0,
extracted_fv: false.into(),
fv_name: crate::BinaryGuid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
file_name: crate::BinaryGuid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
}
}
pub(crate) fn gen_resource_descriptor() -> hob::ResourceDescriptor {
let header = hob::header::Hob {
r#type: hob::RESOURCE_DESCRIPTOR,
length: size_of::<hob::ResourceDescriptor>() as u16,
reserved: 0,
};
hob::ResourceDescriptor {
header,
owner: crate::BinaryGuid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
resource_type: hob::EFI_RESOURCE_SYSTEM_MEMORY,
resource_attribute: hob::EFI_RESOURCE_ATTRIBUTE_PRESENT,
physical_start: 0,
resource_length: 0x0123456789abcdef,
}
}
pub(crate) fn gen_resource_descriptor_v2() -> hob::ResourceDescriptorV2 {
let mut v1 = gen_resource_descriptor();
v1.header.r#type = hob::RESOURCE_DESCRIPTOR2;
v1.header.length = size_of::<hob::ResourceDescriptorV2>() as u16;
hob::ResourceDescriptorV2 { v1, attributes: 8 }
}
pub(crate) fn gen_memory_allocation() -> hob::MemoryAllocation {
let header = hob::header::Hob {
r#type: hob::MEMORY_ALLOCATION,
length: size_of::<hob::MemoryAllocation>() as u16,
reserved: 0,
};
let alloc_descriptor = hob::header::MemoryAllocation {
name: crate::BinaryGuid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
memory_base_address: 0,
memory_length: 0x0123456789abcdef,
memory_type: 0,
reserved: [0; 4],
};
hob::MemoryAllocation { header, alloc_descriptor }
}
pub(crate) fn gen_memory_allocation_module() -> hob::MemoryAllocationModule {
let header = hob::header::Hob {
r#type: hob::MEMORY_ALLOCATION,
length: size_of::<hob::MemoryAllocationModule>() as u16,
reserved: 0,
};
let alloc_descriptor = hob::header::MemoryAllocation {
name: crate::BinaryGuid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
memory_base_address: 0,
memory_length: 0x0123456789abcdef,
memory_type: 0,
reserved: [0; 4],
};
hob::MemoryAllocationModule {
header,
alloc_descriptor,
module_name: crate::BinaryGuid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
entry_point: 0,
}
}
pub(crate) fn gen_capsule() -> hob::Capsule {
let header =
hob::header::Hob { r#type: hob::UEFI_CAPSULE, length: size_of::<hob::Capsule>() as u16, reserved: 0 };
hob::Capsule { header, base_address: 0, length: 0x12 }
}
pub(crate) fn gen_guid_hob() -> Vec<u8> {
let data: &[u8] = &[1_u8, 2, 3, 4, 5, 6, 7, 8];
let hob = hob::GuidHob {
header: hob::header::Hob {
r#type: hob::GUID_EXTENSION,
length: (size_of::<hob::GuidHob>() + data.len()) as u16,
reserved: 0,
},
name: crate::BinaryGuid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
};
let mut buf = Vec::with_capacity(size_of::<hob::GuidHob>() + data.len());
let hob_bytes = unsafe { from_raw_parts(&hob as *const hob::GuidHob as *const u8, size_of::<hob::GuidHob>()) };
buf.extend_from_slice(hob_bytes);
buf.extend_from_slice(data);
buf
}
pub(crate) fn guid_hob_refs(buf: &[u8]) -> (&hob::GuidHob, &[u8]) {
assert!(buf.len() >= size_of::<hob::GuidHob>(), "Buffer too small for GuidHob");
let guid_hob = unsafe { &*(buf.as_ptr() as *const hob::GuidHob) };
let data = &buf[size_of::<hob::GuidHob>()..];
(guid_hob, data)
}
pub(crate) fn gen_phase_handoff_information_table() -> hob::PhaseHandoffInformationTable {
let header = hob::header::Hob {
r#type: hob::HANDOFF,
length: size_of::<hob::PhaseHandoffInformationTable>() as u16,
reserved: 0,
};
hob::PhaseHandoffInformationTable {
header,
version: 0x00010000,
boot_mode: BootMode::BootWithFullConfiguration,
memory_top: 0xdeadbeef,
memory_bottom: 0xdeadc0de,
free_memory_top: 104,
free_memory_bottom: 255,
end_of_hob_list: 0xdeaddeadc0dec0de,
}
}
pub(crate) fn gen_end_of_hoblist() -> hob::PhaseHandoffInformationTable {
let header = hob::header::Hob {
r#type: hob::END_OF_HOB_LIST,
length: size_of::<hob::PhaseHandoffInformationTable>() as u16,
reserved: 0,
};
hob::PhaseHandoffInformationTable {
header,
version: 0x00010000,
boot_mode: BootMode::BootWithFullConfiguration,
memory_top: 0xdeadbeef,
memory_bottom: 0xdeadc0de,
free_memory_top: 104,
free_memory_bottom: 255,
end_of_hob_list: 0xdeaddeadc0dec0de,
}
}
pub(crate) fn gen_cpu() -> hob::Cpu {
let header = hob::header::Hob { r#type: hob::CPU, length: size_of::<hob::Cpu>() as u16, reserved: 0 };
hob::Cpu { header, size_of_memory_space: 0, size_of_io_space: 0, reserved: [0; 6] }
}
#[test]
fn test_get_pi_hob_list_size_single_hob() {
use core::ffi::c_void;
let end_of_list = gen_end_of_hoblist();
let size = unsafe { get_pi_hob_list_size(&end_of_list as *const _ as *const c_void) };
assert_eq!(size, size_of::<PhaseHandoffInformationTable>());
}
#[test]
fn test_get_pi_hob_list_size_multiple_hobs() {
use core::ffi::c_void;
let capsule = gen_capsule();
let firmware_volume = gen_firmware_volume();
let end_of_list = gen_end_of_hoblist();
let expected_size =
size_of::<Capsule>() + size_of::<FirmwareVolume>() + size_of::<PhaseHandoffInformationTable>();
let mut buffer = Vec::new();
let capsule_bytes =
unsafe { core::slice::from_raw_parts(&capsule as *const Capsule as *const u8, size_of::<Capsule>()) };
buffer.extend_from_slice(capsule_bytes);
let fv_bytes = unsafe {
core::slice::from_raw_parts(
&firmware_volume as *const FirmwareVolume as *const u8,
size_of::<FirmwareVolume>(),
)
};
buffer.extend_from_slice(fv_bytes);
let end_bytes = unsafe {
core::slice::from_raw_parts(
&end_of_list as *const PhaseHandoffInformationTable as *const u8,
size_of::<PhaseHandoffInformationTable>(),
)
};
buffer.extend_from_slice(end_bytes);
let size = unsafe { get_pi_hob_list_size(buffer.as_ptr() as *const c_void) };
assert_eq!(size, expected_size);
}
#[test]
fn test_get_pi_hob_list_size_varied_hob_types() {
use core::ffi::c_void;
let cpu = gen_cpu();
let resource = gen_resource_descriptor();
let memory_alloc = gen_memory_allocation();
let end_of_list = gen_end_of_hoblist();
let expected_size = size_of::<Cpu>()
+ size_of::<ResourceDescriptor>()
+ size_of::<MemoryAllocation>()
+ size_of::<PhaseHandoffInformationTable>();
let mut buffer = Vec::new();
buffer.extend_from_slice(unsafe {
core::slice::from_raw_parts(&cpu as *const Cpu as *const u8, size_of::<Cpu>())
});
buffer.extend_from_slice(unsafe {
core::slice::from_raw_parts(
&resource as *const ResourceDescriptor as *const u8,
size_of::<ResourceDescriptor>(),
)
});
buffer.extend_from_slice(unsafe {
core::slice::from_raw_parts(
&memory_alloc as *const MemoryAllocation as *const u8,
size_of::<MemoryAllocation>(),
)
});
buffer.extend_from_slice(unsafe {
core::slice::from_raw_parts(
&end_of_list as *const PhaseHandoffInformationTable as *const u8,
size_of::<PhaseHandoffInformationTable>(),
)
});
let size = unsafe { get_pi_hob_list_size(buffer.as_ptr() as *const c_void) };
assert_eq!(size, expected_size);
}
}