#[cfg(guest_arch = "aarch64")]
pub use Aarch64Register as Register;
#[cfg(guest_arch = "x86_64")]
pub use X86Register as Register;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum BootPageAcceptance {
Exclusive,
ExclusiveUnmeasured,
VpContext,
ErrorPage,
SecretsPage,
CpuidPage,
CpuidExtendedStatePage,
Shared,
}
#[derive(Debug, PartialEq, Eq)]
pub enum IsolationType {
None,
Vbs,
Snp,
Tdx,
}
#[derive(Debug, PartialEq, Eq)]
pub enum StartupMemoryType {
Ram,
Vtl2ProtectableRam,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TableRegister {
pub base: u64,
pub limit: u16,
}
impl From<igvm::registers::TableRegister> for TableRegister {
fn from(value: igvm::registers::TableRegister) -> Self {
Self {
base: value.base,
limit: value.limit,
}
}
}
impl From<TableRegister> for igvm::registers::TableRegister {
fn from(value: TableRegister) -> Self {
Self {
base: value.base,
limit: value.limit,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SegmentRegister {
pub base: u64,
pub limit: u32,
pub selector: u16,
pub attributes: u16,
}
impl From<igvm::registers::SegmentRegister> for SegmentRegister {
fn from(value: igvm::registers::SegmentRegister) -> Self {
Self {
base: value.base,
limit: value.limit,
selector: value.selector,
attributes: value.attributes,
}
}
}
impl From<SegmentRegister> for igvm::registers::SegmentRegister {
fn from(value: SegmentRegister) -> Self {
Self {
base: value.base,
limit: value.limit,
selector: value.selector,
attributes: value.attributes,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86Register {
Gdtr(TableRegister),
Idtr(TableRegister),
Ds(SegmentRegister),
Es(SegmentRegister),
Fs(SegmentRegister),
Gs(SegmentRegister),
Ss(SegmentRegister),
Cs(SegmentRegister),
Tr(SegmentRegister),
Cr0(u64),
Cr3(u64),
Cr4(u64),
Efer(u64),
Pat(u64),
Rbp(u64),
Rip(u64),
Rsi(u64),
Rsp(u64),
R8(u64),
R9(u64),
R10(u64),
R11(u64),
R12(u64),
Rflags(u64),
MtrrDefType(u64),
MtrrPhysBase0(u64),
MtrrPhysMask0(u64),
MtrrPhysBase1(u64),
MtrrPhysMask1(u64),
MtrrPhysBase2(u64),
MtrrPhysMask2(u64),
MtrrPhysBase3(u64),
MtrrPhysMask3(u64),
MtrrPhysBase4(u64),
MtrrPhysMask4(u64),
MtrrFix64k00000(u64),
MtrrFix16k80000(u64),
MtrrFix4kE0000(u64),
MtrrFix4kE8000(u64),
MtrrFix4kF0000(u64),
MtrrFix4kF8000(u64),
}
impl From<igvm::registers::X86Register> for X86Register {
fn from(value: igvm::registers::X86Register) -> Self {
use igvm::registers::X86Register as igvm_reg;
match value {
igvm_reg::Gdtr(v) => X86Register::Gdtr(v.into()),
igvm_reg::Idtr(v) => X86Register::Idtr(v.into()),
igvm_reg::Ds(v) => X86Register::Ds(v.into()),
igvm_reg::Es(v) => X86Register::Es(v.into()),
igvm_reg::Fs(v) => X86Register::Fs(v.into()),
igvm_reg::Gs(v) => X86Register::Gs(v.into()),
igvm_reg::Ss(v) => X86Register::Ss(v.into()),
igvm_reg::Cs(v) => X86Register::Cs(v.into()),
igvm_reg::Tr(v) => X86Register::Tr(v.into()),
igvm_reg::Cr0(v) => X86Register::Cr0(v),
igvm_reg::Cr3(v) => X86Register::Cr3(v),
igvm_reg::Cr4(v) => X86Register::Cr4(v),
igvm_reg::Efer(v) => X86Register::Efer(v),
igvm_reg::Pat(v) => X86Register::Pat(v),
igvm_reg::Rbp(v) => X86Register::Rbp(v),
igvm_reg::Rip(v) => X86Register::Rip(v),
igvm_reg::Rsi(v) => X86Register::Rsi(v),
igvm_reg::Rsp(v) => X86Register::Rsp(v),
igvm_reg::R8(v) => X86Register::R8(v),
igvm_reg::R9(v) => X86Register::R9(v),
igvm_reg::R10(v) => X86Register::R10(v),
igvm_reg::R11(v) => X86Register::R11(v),
igvm_reg::R12(v) => X86Register::R12(v),
igvm_reg::Rflags(v) => X86Register::Rflags(v),
igvm_reg::MtrrDefType(v) => X86Register::MtrrDefType(v),
igvm_reg::MtrrPhysBase0(v) => X86Register::MtrrPhysBase0(v),
igvm_reg::MtrrPhysMask0(v) => X86Register::MtrrPhysMask0(v),
igvm_reg::MtrrPhysBase1(v) => X86Register::MtrrPhysBase1(v),
igvm_reg::MtrrPhysMask1(v) => X86Register::MtrrPhysMask1(v),
igvm_reg::MtrrPhysBase2(v) => X86Register::MtrrPhysBase2(v),
igvm_reg::MtrrPhysMask2(v) => X86Register::MtrrPhysMask2(v),
igvm_reg::MtrrPhysBase3(v) => X86Register::MtrrPhysBase3(v),
igvm_reg::MtrrPhysMask3(v) => X86Register::MtrrPhysMask3(v),
igvm_reg::MtrrPhysBase4(v) => X86Register::MtrrPhysBase4(v),
igvm_reg::MtrrPhysMask4(v) => X86Register::MtrrPhysMask4(v),
igvm_reg::MtrrFix64k00000(v) => X86Register::MtrrFix64k00000(v),
igvm_reg::MtrrFix16k80000(v) => X86Register::MtrrFix16k80000(v),
igvm_reg::MtrrFix4kE0000(v) => X86Register::MtrrFix4kE0000(v),
igvm_reg::MtrrFix4kE8000(v) => X86Register::MtrrFix4kE8000(v),
igvm_reg::MtrrFix4kF0000(v) => X86Register::MtrrFix4kF0000(v),
igvm_reg::MtrrFix4kF8000(v) => X86Register::MtrrFix4kF8000(v),
}
}
}
impl From<X86Register> for igvm::registers::X86Register {
fn from(value: X86Register) -> Self {
use igvm::registers::X86Register as igvm_reg;
match value {
X86Register::Gdtr(v) => igvm_reg::Gdtr(v.into()),
X86Register::Idtr(v) => igvm_reg::Idtr(v.into()),
X86Register::Ds(v) => igvm_reg::Ds(v.into()),
X86Register::Es(v) => igvm_reg::Es(v.into()),
X86Register::Fs(v) => igvm_reg::Fs(v.into()),
X86Register::Gs(v) => igvm_reg::Gs(v.into()),
X86Register::Ss(v) => igvm_reg::Ss(v.into()),
X86Register::Cs(v) => igvm_reg::Cs(v.into()),
X86Register::Tr(v) => igvm_reg::Tr(v.into()),
X86Register::Cr0(v) => igvm_reg::Cr0(v),
X86Register::Cr3(v) => igvm_reg::Cr3(v),
X86Register::Cr4(v) => igvm_reg::Cr4(v),
X86Register::Efer(v) => igvm_reg::Efer(v),
X86Register::Pat(v) => igvm_reg::Pat(v),
X86Register::Rbp(v) => igvm_reg::Rbp(v),
X86Register::Rip(v) => igvm_reg::Rip(v),
X86Register::Rsi(v) => igvm_reg::Rsi(v),
X86Register::Rsp(v) => igvm_reg::Rsp(v),
X86Register::R8(v) => igvm_reg::R8(v),
X86Register::R9(v) => igvm_reg::R9(v),
X86Register::R10(v) => igvm_reg::R10(v),
X86Register::R11(v) => igvm_reg::R11(v),
X86Register::R12(v) => igvm_reg::R12(v),
X86Register::Rflags(v) => igvm_reg::Rflags(v),
X86Register::MtrrDefType(v) => igvm_reg::MtrrDefType(v),
X86Register::MtrrPhysBase0(v) => igvm_reg::MtrrPhysBase0(v),
X86Register::MtrrPhysMask0(v) => igvm_reg::MtrrPhysMask0(v),
X86Register::MtrrPhysBase1(v) => igvm_reg::MtrrPhysBase1(v),
X86Register::MtrrPhysMask1(v) => igvm_reg::MtrrPhysMask1(v),
X86Register::MtrrPhysBase2(v) => igvm_reg::MtrrPhysBase2(v),
X86Register::MtrrPhysMask2(v) => igvm_reg::MtrrPhysMask2(v),
X86Register::MtrrPhysBase3(v) => igvm_reg::MtrrPhysBase3(v),
X86Register::MtrrPhysMask3(v) => igvm_reg::MtrrPhysMask3(v),
X86Register::MtrrPhysBase4(v) => igvm_reg::MtrrPhysBase4(v),
X86Register::MtrrPhysMask4(v) => igvm_reg::MtrrPhysMask4(v),
X86Register::MtrrFix64k00000(v) => igvm_reg::MtrrFix64k00000(v),
X86Register::MtrrFix16k80000(v) => igvm_reg::MtrrFix16k80000(v),
X86Register::MtrrFix4kE0000(v) => igvm_reg::MtrrFix4kE0000(v),
X86Register::MtrrFix4kE8000(v) => igvm_reg::MtrrFix4kE8000(v),
X86Register::MtrrFix4kF0000(v) => igvm_reg::MtrrFix4kF0000(v),
X86Register::MtrrFix4kF8000(v) => igvm_reg::MtrrFix4kF8000(v),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Aarch64Register {
Pc(u64),
X0(u64),
X1(u64),
Cpsr(u64),
VbarEl1(u64),
Ttbr0El1(u64),
Ttbr1El1(u64),
MairEl1(u64),
SctlrEl1(u64),
TcrEl1(u64),
}
impl From<igvm::registers::AArch64Register> for Aarch64Register {
fn from(value: igvm::registers::AArch64Register) -> Self {
use igvm::registers::AArch64Register as igvm_reg;
match value {
igvm_reg::Pc(v) => Aarch64Register::Pc(v),
igvm_reg::X0(v) => Aarch64Register::X0(v),
igvm_reg::X1(v) => Aarch64Register::X1(v),
igvm_reg::Cpsr(v) => Aarch64Register::Cpsr(v),
igvm_reg::SctlrEl1(v) => Aarch64Register::SctlrEl1(v),
igvm_reg::TcrEl1(v) => Aarch64Register::TcrEl1(v),
igvm_reg::MairEl1(v) => Aarch64Register::MairEl1(v),
igvm_reg::VbarEl1(v) => Aarch64Register::VbarEl1(v),
igvm_reg::Ttbr0El1(v) => Aarch64Register::Ttbr0El1(v),
igvm_reg::Ttbr1El1(v) => Aarch64Register::Ttbr1El1(v),
}
}
}
impl From<Aarch64Register> for igvm::registers::AArch64Register {
fn from(value: Aarch64Register) -> Self {
use igvm::registers::AArch64Register as igvm_reg;
match value {
Aarch64Register::Pc(v) => igvm_reg::Pc(v),
Aarch64Register::X0(v) => igvm_reg::X0(v),
Aarch64Register::X1(v) => igvm_reg::X1(v),
Aarch64Register::Cpsr(v) => igvm_reg::Cpsr(v),
Aarch64Register::SctlrEl1(v) => igvm_reg::SctlrEl1(v),
Aarch64Register::TcrEl1(v) => igvm_reg::TcrEl1(v),
Aarch64Register::MairEl1(v) => igvm_reg::MairEl1(v),
Aarch64Register::VbarEl1(v) => igvm_reg::VbarEl1(v),
Aarch64Register::Ttbr0El1(v) => igvm_reg::Ttbr0El1(v),
Aarch64Register::Ttbr1El1(v) => igvm_reg::Ttbr1El1(v),
}
}
}
#[derive(Debug)]
pub struct IsolationConfig {
pub paravisor_present: bool,
pub isolation_type: IsolationType,
pub shared_gpa_boundary_bits: Option<u8>,
}
#[derive(Debug, Default)]
pub struct CpuidResult {
pub eax: u32,
pub ebx: u32,
pub ecx: u32,
pub edx: u32,
}
impl IsolationConfig {
pub fn get_cpuid(&self) -> CpuidResult {
let eax = if self.paravisor_present { 1 } else { 0 };
let mut ebx = 0;
match self.isolation_type {
IsolationType::None => {}
IsolationType::Vbs => ebx = hvdef::HvPartitionIsolationType::VBS.0 as _,
IsolationType::Snp => ebx = hvdef::HvPartitionIsolationType::SNP.0 as _,
IsolationType::Tdx => ebx = hvdef::HvPartitionIsolationType::TDX.0 as _,
}
match self.shared_gpa_boundary_bits {
None => {}
Some(bits) => {
ebx |= 1 << 5;
ebx |= ((bits & 0x3F) as u32) << 6;
}
}
CpuidResult {
eax,
ebx,
ecx: 0,
edx: 0,
}
}
}
#[derive(Debug)]
pub struct ImportRegion {
pub page_base: u64,
pub page_count: u64,
pub acceptance: BootPageAcceptance,
}
#[derive(Debug, PartialEq, Eq)]
pub struct PageRegion {
pub page_base: u64,
pub page_count: u64,
}
#[derive(Debug)]
pub enum IgvmParameterType {
VpCount,
Srat,
Madt,
MmioRanges,
MemoryMap,
CommandLine,
Slit,
Pptt,
DeviceTree,
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
pub struct ParameterAreaIndex(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GuestArchKind {
X86_64,
Aarch64,
}
pub trait GuestArch {
fn arch() -> GuestArchKind;
}
impl GuestArch for X86Register {
fn arch() -> GuestArchKind {
GuestArchKind::X86_64
}
}
impl GuestArch for Aarch64Register {
fn arch() -> GuestArchKind {
GuestArchKind::Aarch64
}
}
pub trait ImageLoad<R>
where
R: GuestArch,
{
fn isolation_config(&self) -> IsolationConfig;
fn create_parameter_area(
&mut self,
page_base: u64,
page_count: u32,
debug_tag: &str,
) -> anyhow::Result<ParameterAreaIndex>;
fn create_parameter_area_with_data(
&mut self,
page_base: u64,
page_count: u32,
debug_tag: &str,
initial_data: &[u8],
) -> anyhow::Result<ParameterAreaIndex>;
fn import_parameter(
&mut self,
parameter_area: ParameterAreaIndex,
byte_offset: u32,
parameter_type: IgvmParameterType,
) -> anyhow::Result<()>;
fn import_pages(
&mut self,
page_base: u64,
page_count: u64,
debug_tag: &str,
acceptance: BootPageAcceptance,
data: &[u8],
) -> anyhow::Result<()>;
fn import_vp_register(&mut self, register: R) -> anyhow::Result<()>;
fn verify_startup_memory_available(
&mut self,
page_base: u64,
page_count: u64,
memory_type: StartupMemoryType,
) -> anyhow::Result<()>;
fn set_vp_context_page(&mut self, page_base: u64) -> anyhow::Result<()>;
fn relocation_region(
&mut self,
gpa: u64,
size_bytes: u64,
relocation_alignment: u64,
minimum_relocation_gpa: u64,
maximum_relocation_gpa: u64,
apply_rip_offset: bool,
apply_gdtr_offset: bool,
vp_index: u16,
) -> anyhow::Result<()>;
fn page_table_relocation(
&mut self,
page_table_gpa: u64,
size_pages: u64,
used_pages: u64,
vp_index: u16,
) -> anyhow::Result<()>;
fn set_imported_regions_config_page(&mut self, page_base: u64);
}