use crate::{
BootMode,
address_helper::{align_down, align_up},
};
use core::{
ffi::c_void,
fmt,
marker::PhantomData,
mem::{self, size_of},
slice,
};
use indoc::indoc;
extern crate alloc;
use alloc::boxed::Box;
use alloc::vec::Vec;
#[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::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: r_efi::base::Guid,
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: r_efi::base::Guid,
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: r_efi::base::Guid,
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: r_efi::base::Guid,
}
#[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: r_efi::base::Guid,
pub file_name: r_efi::base::Guid,
}
#[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: r_efi::base::Guid,
pub file_name: r_efi::base::Guid,
}
#[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,
}
pub struct HobList<'a>(Vec<Hob<'a>>);
impl Default for HobList<'_> {
fn default() -> Self {
HobList::new()
}
}
#[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_c_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<'a> HobList<'a> {
pub const fn new() -> Self {
HobList(Vec::new())
}
pub fn iter(&self) -> impl Iterator<Item = &Hob<'_>> {
self.0.iter()
}
pub fn as_mut_ptr<T>(&mut self) -> *mut T {
self.0.as_mut_ptr() as *mut T
}
pub fn size(&self) -> usize {
let mut size_of_hobs = 0;
for hob in self.iter() {
size_of_hobs += hob.size()
}
size_of_hobs
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn push(&mut self, hob: Hob<'a>) {
let cloned_hob = hob.clone();
self.0.push(cloned_hob);
}
pub fn discover_hobs(&mut self, hob_list: *const c_void) {
const NOT_NULL: &str = "Ptr should not be NULL";
fn assert_hob_size<T>(hob: &header::Hob) {
let hob_len = hob.length as usize;
let hob_size = mem::size_of::<T>();
assert_eq!(
hob_len, hob_size,
"Trying to cast hob of length {hob_len} into a pointer of size {hob_size}. Hob type: {:?}",
hob.r#type
);
}
let mut hob_header: *const header::Hob = hob_list as *const header::Hob;
loop {
let current_header = unsafe { hob_header.cast::<header::Hob>().as_ref().expect(NOT_NULL) };
match current_header.r#type {
HANDOFF => {
assert_hob_size::<PhaseHandoffInformationTable>(current_header);
let phit_hob =
unsafe { hob_header.cast::<PhaseHandoffInformationTable>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::Handoff(phit_hob));
}
MEMORY_ALLOCATION => {
if current_header.length == mem::size_of::<MemoryAllocationModule>() as u16 {
let mem_alloc_hob =
unsafe { hob_header.cast::<MemoryAllocationModule>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::MemoryAllocationModule(mem_alloc_hob));
} else {
assert_hob_size::<MemoryAllocation>(current_header);
let mem_alloc_hob = unsafe { hob_header.cast::<MemoryAllocation>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::MemoryAllocation(mem_alloc_hob));
}
}
RESOURCE_DESCRIPTOR => {
assert_hob_size::<ResourceDescriptor>(current_header);
let resource_desc_hob =
unsafe { hob_header.cast::<ResourceDescriptor>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::ResourceDescriptor(resource_desc_hob));
}
GUID_EXTENSION => {
let (guid_hob, data) = unsafe {
let hob = hob_header.cast::<GuidHob>().as_ref().expect(NOT_NULL);
let data_ptr = hob_header.byte_add(mem::size_of::<GuidHob>()) as *mut u8;
let data_len = hob.header.length as usize - mem::size_of::<GuidHob>();
(hob, slice::from_raw_parts(data_ptr, data_len))
};
self.0.push(Hob::GuidHob(guid_hob, data));
}
FV => {
assert_hob_size::<FirmwareVolume>(current_header);
let fv_hob = unsafe { hob_header.cast::<FirmwareVolume>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::FirmwareVolume(fv_hob));
}
FV2 => {
assert_hob_size::<FirmwareVolume2>(current_header);
let fv2_hob = unsafe { hob_header.cast::<FirmwareVolume2>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::FirmwareVolume2(fv2_hob));
}
FV3 => {
assert_hob_size::<FirmwareVolume3>(current_header);
let fv3_hob = unsafe { hob_header.cast::<FirmwareVolume3>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::FirmwareVolume3(fv3_hob));
}
CPU => {
assert_hob_size::<Cpu>(current_header);
let cpu_hob = unsafe { hob_header.cast::<Cpu>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::Cpu(cpu_hob));
}
UEFI_CAPSULE => {
assert_hob_size::<Capsule>(current_header);
let capsule_hob = unsafe { hob_header.cast::<Capsule>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::Capsule(capsule_hob));
}
RESOURCE_DESCRIPTOR2 => {
assert_hob_size::<ResourceDescriptorV2>(current_header);
let resource_desc_hob =
unsafe { hob_header.cast::<ResourceDescriptorV2>().as_ref().expect(NOT_NULL) };
self.0.push(Hob::ResourceDescriptorV2(resource_desc_hob));
}
END_OF_HOB_LIST => {
break;
}
_ => {
self.0.push(Hob::Misc(current_header.r#type));
}
}
let next_hob = hob_header as usize + current_header.length as usize;
hob_header = next_hob as *const header::Hob;
}
}
pub fn relocate_hobs(&mut self) {
for hob in self.0.iter_mut() {
match hob {
Hob::Handoff(hob) => *hob = Box::leak(Box::new(PhaseHandoffInformationTable::clone(hob))),
Hob::MemoryAllocation(hob) => *hob = Box::leak(Box::new(MemoryAllocation::clone(hob))),
Hob::MemoryAllocationModule(hob) => *hob = Box::leak(Box::new(MemoryAllocationModule::clone(hob))),
Hob::Capsule(hob) => *hob = Box::leak(Box::new(Capsule::clone(hob))),
Hob::ResourceDescriptor(hob) => *hob = Box::leak(Box::new(ResourceDescriptor::clone(hob))),
Hob::GuidHob(hob, data) => {
*hob = Box::leak(Box::new(GuidHob::clone(hob)));
*data = Box::leak(data.to_vec().into_boxed_slice());
}
Hob::FirmwareVolume(hob) => *hob = Box::leak(Box::new(FirmwareVolume::clone(hob))),
Hob::FirmwareVolume2(hob) => *hob = Box::leak(Box::new(FirmwareVolume2::clone(hob))),
Hob::FirmwareVolume3(hob) => *hob = Box::leak(Box::new(FirmwareVolume3::clone(hob))),
Hob::Cpu(hob) => *hob = Box::leak(Box::new(Cpu::clone(hob))),
Hob::ResourceDescriptorV2(hob) => *hob = Box::leak(Box::new(ResourceDescriptorV2::clone(hob))),
Hob::Misc(_) => (), };
}
}
}
impl<'a> IntoIterator for HobList<'a> {
type Item = Hob<'a>;
type IntoIter = <Vec<Hob<'a>> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a> IntoIterator for &'a HobList<'a> {
type Item = &'a Hob<'a>;
type IntoIter = core::slice::Iter<'a, Hob<'a>>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl fmt::Debug for HobList<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for hob in self.0.clone().into_iter() {
match hob {
Hob::Handoff(hob) => {
write!(
f,
indoc! {"
PHASE HANDOFF INFORMATION TABLE (PHIT) HOB
HOB Length: 0x{:x}
Version: 0x{:x}
Boot Mode: {}
Memory Bottom: 0x{:x}
Memory Top: 0x{:x}
Free Memory Bottom: 0x{:x}
Free Memory Top: 0x{:x}
End of HOB List: 0x{:x}\n"},
hob.header.length,
hob.version,
hob.boot_mode,
align_up(hob.memory_bottom, 0x1000),
align_down(hob.memory_top, 0x1000),
align_up(hob.free_memory_bottom, 0x1000),
align_down(hob.free_memory_top, 0x1000),
hob.end_of_hob_list
)?;
}
Hob::MemoryAllocation(hob) => {
write!(
f,
indoc! {"
MEMORY ALLOCATION HOB
HOB Length: 0x{:x}
Memory Base Address: 0x{:x}
Memory Length: 0x{:x}
Memory Type: {:?}\n"},
hob.header.length,
hob.alloc_descriptor.memory_base_address,
hob.alloc_descriptor.memory_length,
hob.alloc_descriptor.memory_type
)?;
}
Hob::ResourceDescriptor(hob) => {
write!(
f,
indoc! {"
RESOURCE DESCRIPTOR HOB
HOB Length: 0x{:x}
Resource Type: 0x{:x}
Resource Attribute Type: 0x{:x}
Resource Start Address: 0x{:x}
Resource Length: 0x{:x}\n"},
hob.header.length,
hob.resource_type,
hob.resource_attribute,
hob.physical_start,
hob.resource_length
)?;
}
Hob::GuidHob(hob, _data) => {
let (f0, f1, f2, f3, f4, &[f5, f6, f7, f8, f9, f10]) = hob.name.as_fields();
write!(
f,
indoc! {"
GUID HOB
Type: {:#x}
Length: {:#x},
GUID: {{{:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}}}\n"},
hob.header.r#type, hob.header.length, f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10,
)?;
}
Hob::FirmwareVolume(hob) => {
write!(
f,
indoc! {"
FIRMWARE VOLUME (FV) HOB
HOB Length: 0x{:x}
Base Address: 0x{:x}
Length: 0x{:x}\n"},
hob.header.length, hob.base_address, hob.length
)?;
}
Hob::FirmwareVolume2(hob) => {
write!(
f,
indoc! {"
FIRMWARE VOLUME 2 (FV2) HOB
Base Address: 0x{:x}
Length: 0x{:x}\n"},
hob.base_address, hob.length
)?;
}
Hob::FirmwareVolume3(hob) => {
write!(
f,
indoc! {"
FIRMWARE VOLUME 3 (FV3) HOB
Base Address: 0x{:x}
Length: 0x{:x}\n"},
hob.base_address, hob.length
)?;
}
Hob::Cpu(hob) => {
write!(
f,
indoc! {"
CPU HOB
Memory Space Size: 0x{:x}
IO Space Size: 0x{:x}\n"},
hob.size_of_memory_space, hob.size_of_io_space
)?;
}
Hob::Capsule(hob) => {
write!(
f,
indoc! {"
CAPSULE HOB
Base Address: 0x{:x}
Length: 0x{:x}\n"},
hob.base_address, hob.length
)?;
}
Hob::ResourceDescriptorV2(hob) => {
write!(
f,
indoc! {"
RESOURCE DESCRIPTOR 2 HOB
HOB Length: 0x{:x}
Resource Type: 0x{:x}
Resource Attribute Type: 0x{:x}
Resource Start Address: 0x{:x}
Resource Length: 0x{:x}
Attributes: 0x{:x}\n"},
hob.v1.header.length,
hob.v1.resource_type,
hob.v1.resource_attribute,
hob.v1.physical_start,
hob.v1.resource_length,
hob.attributes
)?;
}
_ => (),
}
}
write!(f, "Parsed HOBs")
}
}
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: r_efi::efi::Guid =
r_efi::efi::Guid::from_fields(0x4c19049f, 0x4137, 0x4dd3, 0x9c, 0x10, &[0x8b, 0x97, 0xa8, 0x3f, 0xfd, 0xfa]);
#[derive(Debug)]
#[repr(C)]
pub struct EFiMemoryTypeInformation {
pub memory_type: r_efi::efi::MemoryType,
pub number_of_pages: u32,
}
#[cfg(test)]
mod tests {
use crate::{
BootMode, hob,
hob::{Hob, HobList, HobTrait},
};
use core::{
ffi::c_void,
mem::{drop, forget, size_of},
ptr,
slice::from_raw_parts,
};
extern crate alloc;
use alloc::vec::Vec;
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 }
}
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: r_efi::efi::Guid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
file_name: r_efi::efi::Guid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
}
}
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: r_efi::efi::Guid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
file_name: r_efi::efi::Guid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
}
}
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: r_efi::efi::Guid::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,
}
}
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 }
}
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: r_efi::efi::Guid::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 }
}
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: r_efi::efi::Guid::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: r_efi::efi::Guid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
entry_point: 0,
}
}
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 }
}
fn gen_guid_hob() -> (hob::GuidHob, Box<[u8]>) {
let data = Box::new([1_u8, 2, 3, 4, 5, 6, 7, 8]);
(
hob::GuidHob {
header: hob::header::Hob {
r#type: hob::GUID_EXTENSION,
length: (size_of::<hob::GuidHob>() + data.len()) as u16,
reserved: 0,
},
name: r_efi::efi::Guid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]),
},
data,
)
}
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,
}
}
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,
}
}
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] }
}
pub fn to_c_array(hob_list: &hob::HobList) -> (*const c_void, usize) {
let size = hob_list.size();
let mut c_array: Vec<u8> = Vec::with_capacity(size);
for hob in hob_list.iter() {
let slice = unsafe { from_raw_parts(hob.as_ptr(), hob.size()) };
c_array.extend_from_slice(slice);
}
let void_ptr = c_array.as_ptr() as *const c_void;
forget(c_array);
(void_ptr, size)
}
pub fn manually_free_c_array(c_array_ptr: *const c_void, len: usize) {
let ptr = c_array_ptr as *mut u8;
unsafe {
drop(Vec::from_raw_parts(ptr, len, len));
}
}
#[test]
fn test_hoblist_empty() {
let hoblist = HobList::new();
assert_eq!(hoblist.len(), 0);
assert!(hoblist.is_empty());
}
#[test]
fn test_hoblist_push() {
let mut hoblist = HobList::new();
let resource = gen_resource_descriptor();
hoblist.push(Hob::ResourceDescriptor(&resource));
assert_eq!(hoblist.len(), 1);
let firmware_volume = gen_firmware_volume();
hoblist.push(Hob::FirmwareVolume(&firmware_volume));
assert_eq!(hoblist.len(), 2);
let resource_v2 = gen_resource_descriptor_v2();
hoblist.push(Hob::ResourceDescriptorV2(&resource_v2));
assert_eq!(hoblist.len(), 3);
}
#[test]
fn test_hoblist_iterate() {
let mut hoblist = HobList::default();
let resource = gen_resource_descriptor();
let firmware_volume = gen_firmware_volume();
let firmware_volume2 = gen_firmware_volume2();
let firmware_volume3 = gen_firmware_volume3();
let end_of_hob_list = gen_end_of_hoblist();
let capsule = gen_capsule();
let (guid_hob, guid_hob_data) = gen_guid_hob();
let memory_allocation = gen_memory_allocation();
let memory_allocation_module = gen_memory_allocation_module();
hoblist.push(Hob::ResourceDescriptor(&resource));
hoblist.push(Hob::FirmwareVolume(&firmware_volume));
hoblist.push(Hob::FirmwareVolume2(&firmware_volume2));
hoblist.push(Hob::FirmwareVolume3(&firmware_volume3));
hoblist.push(Hob::Capsule(&capsule));
hoblist.push(Hob::GuidHob(&guid_hob, guid_hob_data.as_ref()));
hoblist.push(Hob::MemoryAllocation(&memory_allocation));
hoblist.push(Hob::MemoryAllocationModule(&memory_allocation_module));
hoblist.push(Hob::Handoff(&end_of_hob_list));
let mut count = 0;
hoblist.iter().for_each(|hob| {
match hob {
Hob::ResourceDescriptor(resource) => {
assert_eq!(resource.resource_type, hob::EFI_RESOURCE_SYSTEM_MEMORY);
}
Hob::MemoryAllocation(memory_allocation) => {
assert_eq!(memory_allocation.alloc_descriptor.memory_length, 0x0123456789abcdef);
}
Hob::MemoryAllocationModule(memory_allocation_module) => {
assert_eq!(memory_allocation_module.alloc_descriptor.memory_length, 0x0123456789abcdef);
}
Hob::Capsule(capsule) => {
assert_eq!(capsule.base_address, 0);
}
Hob::GuidHob(guid_hob, data) => {
assert_eq!(guid_hob.name, r_efi::efi::Guid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]));
assert_eq!(*data, &[1_u8, 2, 3, 4, 5, 6, 7, 8]);
}
Hob::FirmwareVolume(firmware_volume) => {
assert_eq!(firmware_volume.length, 0x0123456789abcdef);
}
Hob::FirmwareVolume2(firmware_volume) => {
assert_eq!(firmware_volume.length, 0x0123456789abcdef);
}
Hob::FirmwareVolume3(firmware_volume) => {
assert_eq!(firmware_volume.length, 0x0123456789abcdef);
}
Hob::Handoff(handoff) => {
assert_eq!(handoff.memory_top, 0xdeadbeef);
}
_ => {
panic!("Unexpected hob type");
}
}
count += 1;
});
assert_eq!(count, 9);
}
#[test]
fn test_hoblist_discover() {
let resource = gen_resource_descriptor();
let handoff = gen_phase_handoff_information_table();
let firmware_volume = gen_firmware_volume();
let firmware_volume2 = gen_firmware_volume2();
let firmware_volume3 = gen_firmware_volume3();
let capsule = gen_capsule();
let (guid_hob, guid_hob_data) = gen_guid_hob();
let memory_allocation = gen_memory_allocation();
let memory_allocation_module = gen_memory_allocation_module();
let cpu = gen_cpu();
let resource_v2 = gen_resource_descriptor_v2();
let end_of_hob_list = gen_end_of_hoblist();
let mut hoblist = HobList::new();
hoblist.push(Hob::ResourceDescriptor(&resource));
hoblist.push(Hob::Handoff(&handoff));
hoblist.push(Hob::FirmwareVolume(&firmware_volume));
hoblist.push(Hob::FirmwareVolume2(&firmware_volume2));
hoblist.push(Hob::FirmwareVolume3(&firmware_volume3));
hoblist.push(Hob::Capsule(&capsule));
hoblist.push(Hob::GuidHob(&guid_hob, guid_hob_data.as_ref()));
hoblist.push(Hob::MemoryAllocation(&memory_allocation));
hoblist.push(Hob::MemoryAllocationModule(&memory_allocation_module));
hoblist.push(Hob::Cpu(&cpu));
hoblist.push(Hob::ResourceDescriptorV2(&resource_v2));
hoblist.push(Hob::Handoff(&end_of_hob_list));
let mut count = 0;
hoblist.iter().for_each(|hob| {
match hob {
Hob::ResourceDescriptor(resource) => {
assert_eq!(resource.resource_type, hob::EFI_RESOURCE_SYSTEM_MEMORY);
}
Hob::MemoryAllocation(memory_allocation) => {
assert_eq!(memory_allocation.alloc_descriptor.memory_length, 0x0123456789abcdef);
}
Hob::MemoryAllocationModule(memory_allocation_module) => {
assert_eq!(memory_allocation_module.alloc_descriptor.memory_length, 0x0123456789abcdef);
}
Hob::Capsule(capsule) => {
assert_eq!(capsule.base_address, 0);
}
Hob::GuidHob(guid_hob, data) => {
assert_eq!(guid_hob.name, r_efi::efi::Guid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]));
assert_eq!(&data[..], &guid_hob_data[..]);
}
Hob::FirmwareVolume(firmware_volume) => {
assert_eq!(firmware_volume.length, 0x0123456789abcdef);
}
Hob::FirmwareVolume2(firmware_volume) => {
assert_eq!(firmware_volume.length, 0x0123456789abcdef);
}
Hob::FirmwareVolume3(firmware_volume) => {
assert_eq!(firmware_volume.length, 0x0123456789abcdef);
}
Hob::Handoff(handoff) => {
assert_eq!(handoff.memory_top, 0xdeadbeef);
}
Hob::Cpu(cpu) => {
assert_eq!(cpu.size_of_memory_space, 0);
}
Hob::ResourceDescriptorV2(resource) => {
assert_eq!(resource.v1.header.r#type, hob::RESOURCE_DESCRIPTOR2);
assert_eq!(resource.v1.resource_type, hob::EFI_RESOURCE_SYSTEM_MEMORY);
}
_ => {
panic!("Unexpected hob type");
}
}
count += 1;
});
assert_eq!(count, 12);
let (c_array_hoblist, length) = to_c_array(&hoblist);
let mut cloned_hoblist = HobList::new();
cloned_hoblist.discover_hobs(c_array_hoblist);
count = 0;
hoblist.into_iter().for_each(|hob| {
match hob {
Hob::ResourceDescriptor(resource) => {
assert_eq!(resource.resource_type, hob::EFI_RESOURCE_SYSTEM_MEMORY);
}
Hob::MemoryAllocation(memory_allocation) => {
assert_eq!(memory_allocation.alloc_descriptor.memory_length, 0x0123456789abcdef);
}
Hob::MemoryAllocationModule(memory_allocation_module) => {
assert_eq!(memory_allocation_module.alloc_descriptor.memory_length, 0x0123456789abcdef);
}
Hob::Capsule(capsule) => {
assert_eq!(capsule.base_address, 0);
}
Hob::GuidHob(guid_hob, data) => {
assert_eq!(guid_hob.name, r_efi::efi::Guid::from_fields(1, 2, 3, 4, 5, &[6, 7, 8, 9, 10, 11]));
assert_eq!(data, &[1_u8, 2, 3, 4, 5, 6, 7, 8]);
}
Hob::FirmwareVolume(firmware_volume) => {
assert_eq!(firmware_volume.length, 0x0123456789abcdef);
}
Hob::FirmwareVolume2(firmware_volume) => {
assert_eq!(firmware_volume.length, 0x0123456789abcdef);
}
Hob::FirmwareVolume3(firmware_volume) => {
assert_eq!(firmware_volume.length, 0x0123456789abcdef);
}
Hob::Handoff(handoff) => {
assert_eq!(handoff.memory_top, 0xdeadbeef);
}
Hob::ResourceDescriptorV2(resource) => {
assert_eq!(resource.v1.header.r#type, hob::RESOURCE_DESCRIPTOR2);
assert_eq!(resource.v1.resource_type, hob::EFI_RESOURCE_SYSTEM_MEMORY);
}
Hob::Cpu(cpu) => {
assert_eq!(cpu.size_of_memory_space, 0);
}
_ => {
panic!("Unexpected hob type");
}
}
count += 1;
});
assert_eq!(count, 12);
manually_free_c_array(c_array_hoblist, length);
}
#[test]
fn test_hob_iterator() {
let resource = gen_resource_descriptor();
let handoff = gen_phase_handoff_information_table();
let firmware_volume = gen_firmware_volume();
let firmware_volume2 = gen_firmware_volume2();
let firmware_volume3 = gen_firmware_volume3();
let capsule = gen_capsule();
let (guid_hob, guid_hob_data) = gen_guid_hob();
let memory_allocation = gen_memory_allocation();
let memory_allocation_module = gen_memory_allocation_module();
let cpu = gen_cpu();
let end_of_hob_list = gen_end_of_hoblist();
let mut hoblist = HobList::new();
hoblist.push(Hob::ResourceDescriptor(&resource));
hoblist.push(Hob::Handoff(&handoff));
hoblist.push(Hob::FirmwareVolume(&firmware_volume));
hoblist.push(Hob::FirmwareVolume2(&firmware_volume2));
hoblist.push(Hob::FirmwareVolume3(&firmware_volume3));
hoblist.push(Hob::Capsule(&capsule));
hoblist.push(Hob::GuidHob(&guid_hob, guid_hob_data.as_ref()));
hoblist.push(Hob::MemoryAllocation(&memory_allocation));
hoblist.push(Hob::MemoryAllocationModule(&memory_allocation_module));
hoblist.push(Hob::Cpu(&cpu));
hoblist.push(Hob::Handoff(&end_of_hob_list));
let (c_array_hoblist, length) = to_c_array(&hoblist);
let hob = Hob::ResourceDescriptor(unsafe {
(c_array_hoblist as *const hob::ResourceDescriptor).as_ref::<'static>().unwrap()
});
for h in &hob {
println!("{:?}", h.header());
}
manually_free_c_array(c_array_hoblist, length);
}
#[test]
fn test_hob_iterator2() {
let resource = gen_resource_descriptor();
let handoff = gen_phase_handoff_information_table();
let firmware_volume = gen_firmware_volume();
let firmware_volume2 = gen_firmware_volume2();
let firmware_volume3 = gen_firmware_volume3();
let capsule = gen_capsule();
let (guid_hob, guid_hob_data) = gen_guid_hob();
let memory_allocation = gen_memory_allocation();
let memory_allocation_module = gen_memory_allocation_module();
let cpu = gen_cpu();
let resource_v2 = gen_resource_descriptor_v2();
let end_of_hob_list = gen_end_of_hoblist();
let mut hoblist = HobList::new();
hoblist.push(Hob::ResourceDescriptor(&resource));
hoblist.push(Hob::Handoff(&handoff));
hoblist.push(Hob::FirmwareVolume(&firmware_volume));
hoblist.push(Hob::FirmwareVolume2(&firmware_volume2));
hoblist.push(Hob::FirmwareVolume3(&firmware_volume3));
hoblist.push(Hob::Capsule(&capsule));
hoblist.push(Hob::GuidHob(&guid_hob, guid_hob_data.as_ref()));
hoblist.push(Hob::MemoryAllocation(&memory_allocation));
hoblist.push(Hob::MemoryAllocationModule(&memory_allocation_module));
hoblist.push(Hob::Cpu(&cpu));
hoblist.push(Hob::ResourceDescriptorV2(&resource_v2));
hoblist.push(Hob::Handoff(&end_of_hob_list));
for hob in &hoblist {
println!("{:?}", hob.header());
}
for hob in hoblist {
println!("{:?}", hob.header());
}
}
#[test]
fn test_relocate_hobs() {
let resource = gen_resource_descriptor();
let handoff = gen_phase_handoff_information_table();
let firmware_volume = gen_firmware_volume();
let firmware_volume2 = gen_firmware_volume2();
let firmware_volume3 = gen_firmware_volume3();
let capsule = gen_capsule();
let (guid_hob, guid_hob_data) = gen_guid_hob();
let memory_allocation = gen_memory_allocation();
let memory_allocation_module = gen_memory_allocation_module();
let cpu = gen_cpu();
let resource_v2 = gen_resource_descriptor_v2();
let end_of_hob_list = gen_end_of_hoblist();
let mut hoblist = HobList::new();
hoblist.push(Hob::ResourceDescriptor(&resource));
hoblist.push(Hob::Handoff(&handoff));
hoblist.push(Hob::FirmwareVolume(&firmware_volume));
hoblist.push(Hob::FirmwareVolume2(&firmware_volume2));
hoblist.push(Hob::FirmwareVolume3(&firmware_volume3));
hoblist.push(Hob::Capsule(&capsule));
hoblist.push(Hob::GuidHob(&guid_hob, guid_hob_data.as_ref()));
hoblist.push(Hob::MemoryAllocation(&memory_allocation));
hoblist.push(Hob::MemoryAllocationModule(&memory_allocation_module));
hoblist.push(Hob::Cpu(&cpu));
hoblist.push(Hob::Misc(12345));
hoblist.push(Hob::ResourceDescriptorV2(&resource_v2));
hoblist.push(Hob::Handoff(&end_of_hob_list));
let hoblist_address = hoblist.as_mut_ptr::<()>() as usize;
let hoblist_len = hoblist.len();
hoblist.relocate_hobs();
assert_eq!(
hoblist_address,
hoblist.as_mut_ptr::<()>() as usize,
"Only hobs need to be relocated, not the vector."
);
assert_eq!(hoblist_len, hoblist.len());
for (i, hob) in hoblist.into_iter().enumerate() {
match hob {
Hob::ResourceDescriptor(hob) if i == 0 => {
assert_ne!(ptr::addr_of!(resource), hob);
assert_eq!(resource, *hob);
}
Hob::Handoff(hob) if i == 1 => {
assert_ne!(ptr::addr_of!(handoff), hob);
assert_eq!(handoff, *hob);
}
Hob::FirmwareVolume(hob) if i == 2 => {
assert_ne!(ptr::addr_of!(firmware_volume), hob);
assert_eq!(firmware_volume, *hob);
}
Hob::FirmwareVolume2(hob) if i == 3 => {
assert_ne!(ptr::addr_of!(firmware_volume2), hob);
assert_eq!(firmware_volume2, *hob);
}
Hob::FirmwareVolume3(hob) if i == 4 => {
assert_ne!(ptr::addr_of!(firmware_volume3), hob);
assert_eq!(firmware_volume3, *hob);
}
Hob::Capsule(hob) if i == 5 => {
assert_ne!(ptr::addr_of!(capsule), hob);
assert_eq!(capsule, *hob);
}
Hob::GuidHob(hob, hob_data) if i == 6 => {
assert_ne!(ptr::addr_of!(guid_hob), hob);
assert_ne!(guid_hob_data.as_ptr(), hob_data.as_ptr());
assert_eq!(guid_hob.header, hob.header);
assert_eq!(guid_hob.name, hob.name);
assert_eq!(&guid_hob_data[..], hob_data);
}
Hob::MemoryAllocation(hob) if i == 7 => {
assert_ne!(ptr::addr_of!(memory_allocation), hob);
assert_eq!(memory_allocation.header, hob.header);
assert_eq!(memory_allocation.alloc_descriptor, hob.alloc_descriptor);
}
Hob::MemoryAllocationModule(hob) if i == 8 => {
assert_ne!(ptr::addr_of!(memory_allocation_module), hob);
assert_eq!(memory_allocation_module, *hob);
}
Hob::Cpu(hob) if i == 9 => {
assert_ne!(ptr::addr_of!(cpu), hob);
assert_eq!(cpu, *hob);
}
Hob::Misc(hob) if i == 10 => {
assert_eq!(12345, hob);
}
Hob::ResourceDescriptorV2(hob) if i == 11 => {
assert_ne!(ptr::addr_of!(resource_v2), hob);
assert_eq!(resource_v2, *hob);
}
Hob::Handoff(hob) if i == 12 => {
assert_ne!(ptr::addr_of!(end_of_hob_list), hob);
assert_eq!(end_of_hob_list, *hob);
}
_ => panic!("Hob at index: {i}."),
}
}
}
}