use core::mem::size_of;
use log::debug;
use uguid::{guid, Guid};
use zerocopy::{Immutable, IntoBytes};
use igvm_defs::PAGE_SIZE_4K;
pub const EFI_IGVM_DATA_HOB_GUID: Guid = guid!("3dd177ff-b632-4e25-bef3-065063d55fc4");
#[repr(u32)]
#[derive(Debug, IntoBytes, Immutable)]
pub enum EfiIgvmDataType {
Pk = 0x100,
Kek = 0x101,
Db = 0x102,
Dbx = 0x103,
Shim = 0x200,
Kernel = 0x201,
}
#[repr(C)]
#[derive(Debug, IntoBytes, Immutable)]
pub struct EfiIgvmDataHob {
hob_type: u16,
hob_length: u16,
_reserved: u32,
guid_ext: [u8; 16],
address: u64,
length: u64,
data_type: EfiIgvmDataType,
data_flags: u32,
}
impl EfiIgvmDataHob {
pub fn new(address: usize, length: usize, data_type: EfiIgvmDataType) -> Self {
Self {
hob_type: 0x0004, hob_length: size_of::<EfiIgvmDataHob>() as u16,
_reserved: 0,
guid_ext: EFI_IGVM_DATA_HOB_GUID.to_bytes(),
address: address as u64,
length: length as u64,
data_type,
data_flags: 0,
}
}
}
pub struct EfiIgvmData<'b> {
hob: EfiIgvmDataHob,
addr: usize,
blob: &'b [u8],
measured: bool,
}
pub struct EfiIgvmDataList<'b> {
base: usize,
data: Vec<EfiIgvmData<'b>>,
}
impl<'b> EfiIgvmDataList<'b> {
pub fn new(base: usize) -> Self {
Self {
base,
data: Vec::new(),
}
}
pub fn add(&mut self, blob: &'b [u8], data_type: EfiIgvmDataType, measured: bool) {
debug!(
"add {data_type:?}, 0x{:x} bytes, at 0x{:x}{}",
blob.len(),
self.base,
if measured { "" } else { ", unmeasured" },
);
let hob = EfiIgvmDataHob::new(self.base, blob.len(), data_type);
let addr = self.base;
let data = EfiIgvmData {
hob,
addr,
blob,
measured,
};
self.data.push(data);
self.base += blob.len().next_multiple_of(PAGE_SIZE_4K as usize);
}
pub fn hobs(&self) -> Vec<u8> {
let mut blob = Vec::new();
for d in &self.data {
blob.extend_from_slice(d.hob.as_bytes());
}
blob.extend_from_slice(&[0xff, 0xff]);
blob
}
pub fn blobs(&self, measured: bool) -> Vec<(usize, &'b [u8])> {
self.data
.iter()
.filter(|d| d.measured == measured)
.map(|d| (d.addr, d.blob))
.collect()
}
}