#![no_std]
use bitfield_struct::bitfield;
use core::fmt::Debug;
use core::mem::size_of;
use open_enum::open_enum;
use static_assertions::const_assert;
use zerocopy::AsBytes;
use zerocopy::FromBytes;
use zerocopy::FromZeroes;
pub const HV_PAGE_SIZE: u64 = 4096;
pub const HV_PAGE_SIZE_USIZE: usize = 4096;
pub const HV_PAGE_SHIFT: u64 = 12;
pub const HV_PARTITION_ID_SELF: u64 = u64::MAX;
pub const HV_VP_INDEX_SELF: u32 = 0xfffffffe;
pub const HV_CPUID_FUNCTION_VERSION_AND_FEATURES: u32 = 0x00000001;
pub const HV_CPUID_FUNCTION_HV_VENDOR_AND_MAX_FUNCTION: u32 = 0x40000000;
pub const HV_CPUID_FUNCTION_HV_INTERFACE: u32 = 0x40000001;
pub const HV_CPUID_FUNCTION_MS_HV_VERSION: u32 = 0x40000002;
pub const HV_CPUID_FUNCTION_MS_HV_FEATURES: u32 = 0x40000003;
pub const HV_CPUID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION: u32 = 0x40000004;
pub const HV_CPUID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS: u32 = 0x40000005;
pub const HV_CPUID_FUNCTION_MS_HV_HARDWARE_FEATURES: u32 = 0x40000006;
pub const HV_CPUID_FUNCTION_MS_HV_ISOLATION_CONFIGURATION: u32 = 0x4000000C;
pub const VIRTUALIZATION_STACK_CPUID_VENDOR: u32 = 0x40000080;
pub const VIRTUALIZATION_STACK_CPUID_INTERFACE: u32 = 0x40000081;
pub const VIRTUALIZATION_STACK_CPUID_PROPERTIES: u32 = 0x40000082;
pub const VS1_PARTITION_PROPERTIES_EAX_IS_PORTABLE: u32 = 0x000000001;
pub const VS1_PARTITION_PROPERTIES_EAX_DEBUG_DEVICE_PRESENT: u32 = 0x000000002;
pub const VS1_PARTITION_PROPERTIES_EAX_EXTENDED_IOAPIC_RTE: u32 = 0x000000004;
#[bitfield(u64)]
pub struct HvPartitionPrivilege {
pub access_vp_runtime_msr: bool,
pub access_partition_reference_counter: bool,
pub access_synic_msrs: bool,
pub access_synthetic_timer_msrs: bool,
pub access_apic_msrs: bool,
pub access_hypercall_msrs: bool,
pub access_vp_index: bool,
pub access_reset_msr: bool,
pub access_stats_msr: bool,
pub access_partition_reference_tsc: bool,
pub access_guest_idle_msr: bool,
pub access_frequency_msrs: bool,
pub access_debug_msrs: bool,
pub access_reenlightenment_ctrls: bool,
pub access_root_scheduler_msr: bool,
pub access_tsc_invariant_controls: bool,
_reserved1: u16,
pub create_partitions: bool,
pub access_partition_id: bool,
pub access_memory_pool: bool,
pub adjust_message_buffers: bool,
pub post_messages: bool,
pub signal_events: bool,
pub create_port: bool,
pub connect_port: bool,
pub access_stats: bool,
#[bits(2)]
_reserved2: u64,
pub debugging: bool,
pub cpu_management: bool,
pub configure_profiler: bool,
pub access_vp_exit_tracing: bool,
pub enable_extended_gva_ranges_flush_va_list: bool,
pub access_vsm: bool,
pub access_vp_registers: bool,
_unused_bit: bool,
pub fast_hypercall_output: bool,
pub enable_extended_hypercalls: bool,
pub start_virtual_processor: bool,
pub isolation: bool,
#[bits(9)]
_reserved3: u64,
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvPartitionIsolationType: u8 {
NONE = 0,
VBS = 1,
SNP = 2,
TDX = 3,
}
}
#[bitfield(u128)]
pub struct HvFeatures {
pub privileges: u64, #[bits(4)]
pub max_supported_cstate: u32,
pub hpet_needed_for_c3_power_state_deprecated: bool,
pub invariant_mperf_available: bool,
pub supervisor_shadow_stack_available: bool,
pub arch_pmu_available: bool,
pub exception_trap_intercept_available: bool,
#[bits(23)]
reserved: u32,
pub mwait_available_deprecated: bool,
pub guest_debugging_available: bool,
pub performance_monitors_available: bool,
pub cpu_dynamic_partitioning_available: bool,
pub xmm_registers_for_fast_hypercall_available: bool,
pub guest_idle_available: bool,
pub hypervisor_sleep_state_support_available: bool,
pub numa_distance_query_available: bool,
pub frequency_regs_available: bool,
pub synthetic_machine_check_available: bool,
pub guest_crash_regs_available: bool,
pub debug_regs_available: bool,
pub npiep1_available: bool,
pub disable_hypervisor_available: bool,
pub extended_gva_ranges_for_flush_virtual_address_list_available: bool,
pub fast_hypercall_output_available: bool,
pub svm_features_available: bool,
pub sint_polling_mode_available: bool,
pub hypercall_msr_lock_available: bool,
pub direct_synthetic_timers: bool,
pub register_pat_available: bool,
pub register_bndcfgs_available: bool,
pub watchdog_timer_available: bool,
pub synthetic_time_unhalted_timer_available: bool,
pub device_domains_available: bool, pub s1_device_domains_available: bool, pub lbr_available: bool,
pub ipt_available: bool,
pub cross_vtl_flush_available: bool,
pub idle_spec_ctrl_available: bool,
pub translate_gva_flags_available: bool,
pub apic_eoi_intercept_available: bool,
}
#[bitfield(u128)]
pub struct HvEnlightenmentInformation {
pub use_hypercall_for_address_space_switch: bool,
pub use_hypercall_for_local_flush: bool,
pub use_hypercall_for_remote_flush_and_local_flush_entire: bool,
pub use_apic_msrs: bool,
pub use_hv_register_for_reset: bool,
pub use_relaxed_timing: bool,
pub use_dma_remapping_deprecated: bool,
pub use_interrupt_remapping_deprecated: bool,
pub use_x2_apic_msrs: bool,
pub deprecate_auto_eoi: bool,
pub use_synthetic_cluster_ipi: bool,
pub use_ex_processor_masks: bool,
pub nested: bool,
pub use_int_for_mbec_system_calls: bool,
pub use_vmcs_enlightenments: bool,
pub use_synced_timeline: bool,
pub core_scheduler_requested: bool,
pub use_direct_local_flush_entire: bool,
pub no_non_architectural_core_sharing: bool,
pub use_x2_apic: bool,
pub restore_time_on_resume: bool,
pub use_hypercall_for_mmio_access: bool,
pub use_gpa_pinning_hypercall: bool,
pub wake_vps: bool,
_reserved: u8,
pub long_spin_wait_count: u32,
#[bits(7)]
pub implemented_physical_address_bits: u32,
#[bits(25)]
_reserved1: u32,
_reserved2: u32,
}
#[bitfield(u128)]
pub struct HvHardwareFeatures {
pub apic_overlay_assist_in_use: bool,
pub msr_bitmaps_in_use: bool,
pub architectural_performance_counters_in_use: bool,
pub second_level_address_translation_in_use: bool,
pub dma_remapping_in_use: bool,
pub interrupt_remapping_in_use: bool,
pub memory_patrol_scrubber_present: bool,
pub dma_protection_in_use: bool,
pub hpet_requested: bool,
pub synthetic_timers_volatile: bool,
#[bits(4)]
pub hypervisor_level: u32,
pub physical_destination_mode_required: bool,
pub use_vmfunc_for_alias_map_switch: bool,
pub hv_register_for_memory_zeroing_supported: bool,
pub unrestricted_guest_supported: bool,
pub rdt_afeatures_supported: bool,
pub rdt_mfeatures_supported: bool,
pub child_perfmon_pmu_supported: bool,
pub child_perfmon_lbr_supported: bool,
pub child_perfmon_ipt_supported: bool,
pub apic_emulation_supported: bool,
pub child_x2_apic_recommended: bool,
pub hardware_watchdog_reserved: bool,
pub device_access_tracking_supported: bool,
pub hardware_gpa_access_tracking_supported: bool,
#[bits(4)]
_reserved: u32,
pub device_domain_input_width: u8,
#[bits(24)]
_reserved1: u32,
_reserved2: u32,
_reserved3: u32,
}
#[bitfield(u128)]
pub struct HvIsolationConfiguration {
pub paravisor_present: bool,
#[bits(31)]
pub _reserved0: u32,
#[bits(4)]
pub isolation_type: u8,
_reserved11: bool,
pub shared_gpa_boundary_active: bool,
#[bits(6)]
pub shared_gpa_boundary_bits: u8,
#[bits(20)]
_reserved12: u32,
_reserved2: u32,
_reserved3: u32,
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HypercallCode: u16 {
#![allow(non_upper_case_globals)]
HvCallSwitchVirtualAddressSpace = 0x0001,
HvCallFlushVirtualAddressSpace = 0x0002,
HvCallFlushVirtualAddressList = 0x0003,
HvCallNotifyLongSpinWait = 0x0008,
HvCallSendSyntheticClusterIpi = 0x000b,
HvCallModifyVtlProtectionMask = 0x000c,
HvCallEnablePartitionVtl = 0x000d,
HvCallEnableVpVtl = 0x000f,
HvCallVtlCall = 0x0011,
HvCallVtlReturn = 0x0012,
HvCallFlushVirtualAddressSpaceEx = 0x0013,
HvCallFlushVirtualAddressListEx = 0x0014,
HvCallSendSyntheticClusterIpiEx = 0x0015,
HvCallInstallIntercept = 0x004d,
HvCallGetVpRegisters = 0x0050,
HvCallSetVpRegisters = 0x0051,
HvCallTranslateVirtualAddress = 0x0052,
HvCallPostMessage = 0x005C,
HvCallSignalEvent = 0x005D,
HvCallOutputDebugCharacter = 0x0071,
HvCallRetargetDeviceInterrupt = 0x007e,
HvCallAssertVirtualInterrupt = 0x0094,
HvCallStartVirtualProcessor = 0x0099,
HvCallGetVpIndexFromApicId = 0x009A,
HvCallTranslateVirtualAddressEx = 0x00AC,
HvCallCheckForIoIntercept = 0x00ad,
HvCallFlushGuestPhysicalAddressSpace = 0x00AF,
HvCallFlushGuestPhysicalAddressList = 0x00B0,
HvCallSignalEventDirect = 0x00C0,
HvCallPostMessageDirect = 0x00C1,
HvCallCheckSparseGpaPageVtlAccess = 0x00D4,
HvCallAcceptGpaPages = 0x00D9,
HvCallModifySparseGpaPageHostVisibility = 0x00DB,
HvCallMemoryMappedIoRead = 0x0106,
HvCallMemoryMappedIoWrite = 0x0107,
HvCallPinGpaPageRanges = 0x0112,
HvCallUnpinGpaPageRanges = 0x0113,
HvCallQuerySparseGpaPageHostVisibility = 0x011C,
HvExtCallQueryCapabilities = 0x8001,
}
}
pub const HV_X64_MSR_GUEST_OS_ID: u32 = 0x40000000;
pub const HV_X64_MSR_HYPERCALL: u32 = 0x40000001;
pub const HV_X64_MSR_VP_INDEX: u32 = 0x40000002;
pub const HV_X64_MSR_TIME_REF_COUNT: u32 = 0x40000020;
pub const HV_X64_MSR_REFERENCE_TSC: u32 = 0x40000021;
pub const HV_X64_MSR_TSC_FREQUENCY: u32 = 0x40000022;
pub const HV_X64_MSR_APIC_FREQUENCY: u32 = 0x40000023;
pub const HV_X64_MSR_EOI: u32 = 0x40000070;
pub const HV_X64_MSR_ICR: u32 = 0x40000071;
pub const HV_X64_MSR_TPR: u32 = 0x40000072;
pub const HV_X64_MSR_VP_ASSIST_PAGE: u32 = 0x40000073;
pub const HV_X64_MSR_SCONTROL: u32 = 0x40000080;
pub const HV_X64_MSR_SVERSION: u32 = 0x40000081;
pub const HV_X64_MSR_SIEFP: u32 = 0x40000082;
pub const HV_X64_MSR_SIMP: u32 = 0x40000083;
pub const HV_X64_MSR_EOM: u32 = 0x40000084;
pub const HV_X64_MSR_SINT0: u32 = 0x40000090;
pub const HV_X64_MSR_SINT1: u32 = 0x40000091;
pub const HV_X64_MSR_SINT2: u32 = 0x40000092;
pub const HV_X64_MSR_SINT3: u32 = 0x40000093;
pub const HV_X64_MSR_SINT4: u32 = 0x40000094;
pub const HV_X64_MSR_SINT5: u32 = 0x40000095;
pub const HV_X64_MSR_SINT6: u32 = 0x40000096;
pub const HV_X64_MSR_SINT7: u32 = 0x40000097;
pub const HV_X64_MSR_SINT8: u32 = 0x40000098;
pub const HV_X64_MSR_SINT9: u32 = 0x40000099;
pub const HV_X64_MSR_SINT10: u32 = 0x4000009a;
pub const HV_X64_MSR_SINT11: u32 = 0x4000009b;
pub const HV_X64_MSR_SINT12: u32 = 0x4000009c;
pub const HV_X64_MSR_SINT13: u32 = 0x4000009d;
pub const HV_X64_MSR_SINT14: u32 = 0x4000009e;
pub const HV_X64_MSR_SINT15: u32 = 0x4000009f;
pub const HV_X64_MSR_STIMER0_CONFIG: u32 = 0x400000b0;
pub const HV_X64_MSR_STIMER0_COUNT: u32 = 0x400000b1;
pub const HV_X64_MSR_STIMER1_CONFIG: u32 = 0x400000b2;
pub const HV_X64_MSR_STIMER1_COUNT: u32 = 0x400000b3;
pub const HV_X64_MSR_STIMER2_CONFIG: u32 = 0x400000b4;
pub const HV_X64_MSR_STIMER2_COUNT: u32 = 0x400000b5;
pub const HV_X64_MSR_STIMER3_CONFIG: u32 = 0x400000b6;
pub const HV_X64_MSR_STIMER3_COUNT: u32 = 0x400000b7;
pub const HV_X64_MSR_GUEST_IDLE: u32 = 0x400000F0;
pub const HV_X64_MSR_GUEST_CRASH_P0: u32 = 0x40000100;
pub const HV_X64_MSR_GUEST_CRASH_P1: u32 = 0x40000101;
pub const HV_X64_MSR_GUEST_CRASH_P2: u32 = 0x40000102;
pub const HV_X64_MSR_GUEST_CRASH_P3: u32 = 0x40000103;
pub const HV_X64_MSR_GUEST_CRASH_P4: u32 = 0x40000104;
pub const HV_X64_MSR_GUEST_CRASH_CTL: u32 = 0x40000105;
pub const HV_X64_GUEST_CRASH_PARAMETER_MSRS: usize = 5;
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvError: u16 {
#![allow(non_upper_case_globals)]
InvalidHypercallCode = 0x0002,
InvalidHypercallInput = 0x0003,
InvalidAlignment = 0x0004,
InvalidParameter = 0x0005,
AccessDenied = 0x0006,
InvalidPartitionState = 0x0007,
OperationDenied = 0x0008,
UnknownProperty = 0x0009,
PropertyValueOutOfRange = 0x000A,
InsufficientMemory = 0x000B,
PartitionTooDeep = 0x000C,
InvalidPartitionId = 0x000D,
InvalidVpIndex = 0x000E,
NotFound = 0x0010,
InvalidPortId = 0x0011,
InvalidConnectionId = 0x0012,
InsufficientBuffers = 0x0013,
NotAcknowledged = 0x0014,
InvalidVpState = 0x0015,
Acknowledged = 0x0016,
InvalidSaveRestoreState = 0x0017,
InvalidSynicState = 0x0018,
ObjectInUse = 0x0019,
InvalidProximityDomainInfo = 0x001A,
NoData = 0x001B,
Inactive = 0x001C,
NoResources = 0x001D,
FeatureUnavailable = 0x001E,
PartialPacket = 0x001F,
ProcessorFeatureNotSupported = 0x0020,
ProcessorCacheLineFlushSizeIncompatible = 0x0030,
InsufficientBuffer = 0x0033,
IncompatibleProcessor = 0x0037,
InsufficientDeviceDomains = 0x0038,
CpuidFeatureValidationError = 0x003C,
CpuidXsaveFeatureValidationError = 0x003D,
ProcessorStartupTimeout = 0x003E,
SmxEnabled = 0x003F,
InvalidLpIndex = 0x0041,
InvalidRegisterValue = 0x0050,
InvalidVtlState = 0x0051,
NxNotDetected = 0x0055,
InvalidDeviceId = 0x0057,
InvalidDeviceState = 0x0058,
PendingPageRequests = 0x0059,
PageRequestInvalid = 0x0060,
KeyAlreadyExists = 0x0065,
DeviceAlreadyInDomain = 0x0066,
InvalidCpuGroupId = 0x006F,
InvalidCpuGroupState = 0x0070,
OperationFailed = 0x0071,
NotAllowedWithNestedVirtActive = 0x0072,
InsufficientRootMemory = 0x0073,
EventBufferAlreadyFreed = 0x0074,
Timeout = 0x0078,
VtlAlreadyEnabled = 0x0086,
UnknownRegisterName = 0x0087,
}
}
impl core::fmt::Display for HvError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let error_str = match *self {
HvError::InvalidHypercallCode => "Invalid hypercall code",
HvError::InvalidHypercallInput => "Invalid hypercall input",
HvError::InvalidAlignment => "Invalid alignment",
HvError::InvalidParameter => "Invalid parameter",
HvError::AccessDenied => "Access denied",
HvError::InvalidPartitionState => "Invalid partition state",
HvError::OperationDenied => "Operation denied",
HvError::UnknownProperty => "Unknown property",
HvError::PropertyValueOutOfRange => "Property value out of range",
HvError::InsufficientMemory => "Insufficient memory",
HvError::PartitionTooDeep => "Partition too deep",
HvError::InvalidPartitionId => "Invalid partition ID",
HvError::InvalidVpIndex => "Invalid VP index",
HvError::NotFound => "Not found",
HvError::InvalidPortId => "Invalid port ID",
HvError::InvalidConnectionId => "Invalid connection ID",
HvError::InsufficientBuffers => "Insufficient buffers",
HvError::NotAcknowledged => "Not acknowledged",
HvError::InvalidVpState => "Invalid VP state",
HvError::Acknowledged => "Acknowledged",
HvError::InvalidSaveRestoreState => "Invalid save restore state",
HvError::InvalidSynicState => "Invalid SynIC state",
HvError::ObjectInUse => "Object in use",
HvError::InvalidProximityDomainInfo => "Invalid proximity domain info",
HvError::NoData => "No data",
HvError::Inactive => "Inactive",
HvError::NoResources => "No resources",
HvError::FeatureUnavailable => "Feature unavailable",
HvError::PartialPacket => "Partial packet",
HvError::ProcessorFeatureNotSupported => "Processor feature not supported",
HvError::ProcessorCacheLineFlushSizeIncompatible => {
"Processor cache line flush size incompatible"
}
HvError::InsufficientBuffer => "Insufficient buffer",
HvError::IncompatibleProcessor => "Incompatible processor",
HvError::InsufficientDeviceDomains => "Insufficient device domains",
HvError::CpuidFeatureValidationError => "CPUID feature validation error",
HvError::CpuidXsaveFeatureValidationError => "CPUID XSAVE feature validation error",
HvError::ProcessorStartupTimeout => "Processor startup timeout",
HvError::SmxEnabled => "SMX enabled",
HvError::InvalidLpIndex => "Invalid LP index",
HvError::InvalidRegisterValue => "Invalid register value",
HvError::InvalidVtlState => "Invalid VTL state",
HvError::NxNotDetected => "NX not detected",
HvError::InvalidDeviceId => "Invalid device ID",
HvError::InvalidDeviceState => "Invalid device state",
HvError::PendingPageRequests => "Pending page requests",
HvError::PageRequestInvalid => "Page request invalid",
HvError::KeyAlreadyExists => "Key already exists",
HvError::DeviceAlreadyInDomain => "Device already in domain",
HvError::InvalidCpuGroupId => "Invalid CPU group ID",
HvError::InvalidCpuGroupState => "Invalid CPU group state",
HvError::OperationFailed => "Operation failed",
HvError::NotAllowedWithNestedVirtActive => {
"Not allowed with nested virtualization active"
}
HvError::InsufficientRootMemory => "Insufficient root memory",
HvError::EventBufferAlreadyFreed => "Event buffer already freed",
HvError::Timeout => "The specified timeout expired before the operation completed.",
HvError::VtlAlreadyEnabled => {
"The VTL specified for the operation is already in an enabled state."
}
other => return write!(f, "Hypervisor error {:#06x}", other.0),
};
f.write_str(error_str)
}
}
impl core::error::Error for HvError {}
pub type HvResult<T> = Result<T, HvError>;
pub type HvRepResult = Result<(), (HvError, usize)>;
#[repr(u8)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Vtl {
Vtl0 = 0,
Vtl1 = 1,
Vtl2 = 2,
}
impl TryFrom<u8> for Vtl {
type Error = HvError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value {
0 => Self::Vtl0,
1 => Self::Vtl1,
2 => Self::Vtl2,
_ => return Err(HvError::InvalidParameter),
})
}
}
impl From<Vtl> for u8 {
fn from(value: Vtl) -> Self {
value as u8
}
}
#[bitfield(u64)]
pub struct GuestCrashCtl {
#[bits(58)]
_reserved: u64,
#[bits(3)]
pub pre_os_id: u8,
#[bits(1)]
pub no_crash_dump: bool,
#[bits(1)]
pub crash_message: bool,
#[bits(1)]
pub crash_notify: bool,
}
#[repr(C, align(16))]
#[derive(Copy, Clone, PartialEq, Eq, AsBytes, FromBytes, FromZeroes)]
pub struct AlignedU128([u8; 16]);
impl AlignedU128 {
pub fn as_ne_bytes(&self) -> [u8; 16] {
self.0
}
pub fn from_ne_bytes(val: [u8; 16]) -> Self {
Self(val)
}
}
impl Debug for AlignedU128 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Debug::fmt(&u128::from_ne_bytes(self.0), f)
}
}
impl From<u128> for AlignedU128 {
fn from(v: u128) -> Self {
Self(v.to_ne_bytes())
}
}
impl From<u64> for AlignedU128 {
fn from(v: u64) -> Self {
(v as u128).into()
}
}
impl From<u32> for AlignedU128 {
fn from(v: u32) -> Self {
(v as u128).into()
}
}
impl From<u16> for AlignedU128 {
fn from(v: u16) -> Self {
(v as u128).into()
}
}
impl From<u8> for AlignedU128 {
fn from(v: u8) -> Self {
(v as u128).into()
}
}
impl From<AlignedU128> for u128 {
fn from(v: AlignedU128) -> Self {
u128::from_ne_bytes(v.0)
}
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvMessageType: u32 {
#![allow(non_upper_case_globals)]
HvMessageTypeNone = 0x00000000,
HvMessageTypeUnmappedGpa = 0x80000000,
HvMessageTypeGpaIntercept = 0x80000001,
HvMessageTypeUnacceptedGpa = 0x80000003,
HvMessageTypeGpaAttributeIntercept = 0x80000004,
HvMessageTypeEnablePartitionVtlIntercept = 0x80000005,
HvMessageTypeTimerExpired = 0x80000010,
HvMessageTypeInvalidVpRegisterValue = 0x80000020,
HvMessageTypeUnrecoverableException = 0x80000021,
HvMessageTypeUnsupportedFeature = 0x80000022,
HvMessageTypeTlbPageSizeMismatch = 0x80000023,
HvMessageTypeIommuFault = 0x80000024,
HvMessageTypeEventLogBufferComplete = 0x80000040,
HvMessageTypeHypercallIntercept = 0x80000050,
HvMessageTypeSynicEventIntercept = 0x80000060,
HvMessageTypeSynicSintIntercept = 0x80000061,
HvMessageTypeSynicSintDeliverable = 0x80000062,
HvMessageTypeAsyncCallCompletion = 0x80000070,
HvMessageTypeX64IoPortIntercept = 0x80010000,
HvMessageTypeMsrIntercept = 0x80010001,
HvMessageTypeX64CpuidIntercept = 0x80010002,
HvMessageTypeExceptionIntercept = 0x80010003,
HvMessageTypeX64ApicEoi = 0x80010004,
HvMessageTypeX64IommuPrq = 0x80010005,
HvMessageTypeRegisterIntercept = 0x80010006,
HvMessageTypeX64Halt = 0x80010007,
HvMessageTypeX64InterruptionDeliverable = 0x80010008,
HvMessageTypeX64SipiIntercept = 0x80010009,
HvMessageTypeX64RdtscIntercept = 0x8001000a,
HvMessageTypeX64ApicSmiIntercept = 0x8001000b,
HvMessageTypeArm64ResetIntercept = 0x8001000c,
HvMessageTypeX64ApicInitSipiIntercept = 0x8001000d,
HvMessageTypeX64ApicWriteIntercept = 0x8001000e,
HvMessageTypeX64ProxyInterruptIntercept = 0x8001000f,
HvMessageTypeX64IsolationCtrlRegIntercept = 0x80010010,
HvMessageTypeX64SnpGuestRequestIntercept = 0x80010011,
HvMessageTypeX64ExceptionTrapIntercept = 0x80010012,
HvMessageTypeX64SevVmgexitIntercept = 0x80010013,
}
}
impl Default for HvMessageType {
fn default() -> Self {
HvMessageType::HvMessageTypeNone
}
}
pub const NUM_SINTS: usize = 16;
pub const NUM_TIMERS: usize = 4;
#[repr(C)]
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct HvMessageHeader {
pub typ: HvMessageType,
pub len: u8,
pub flags: HvMessageFlags,
pub rsvd: u16,
pub id: u64,
}
#[bitfield(u8)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvMessageFlags {
pub message_pending: bool,
#[bits(7)]
_reserved: u8,
}
pub const HV_MESSAGE_SIZE: usize = size_of::<HvMessage>();
const_assert!(HV_MESSAGE_SIZE == 256);
pub const HV_MESSAGE_PAYLOAD_SIZE: usize = 240;
#[repr(C)]
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct HvMessage {
pub header: HvMessageHeader,
pub payload_buffer: [u8; HV_MESSAGE_PAYLOAD_SIZE],
}
impl Default for HvMessage {
fn default() -> Self {
Self {
header: FromZeroes::new_zeroed(),
payload_buffer: [0; 240],
}
}
}
impl HvMessage {
pub fn new(typ: HvMessageType, id: u64, payload: &[u8]) -> Self {
let mut msg = HvMessage {
header: HvMessageHeader {
typ,
len: payload.len() as u8,
flags: HvMessageFlags::new(),
rsvd: 0,
id,
},
payload_buffer: [0; 240],
};
msg.payload_buffer[..payload.len()].copy_from_slice(payload);
msg
}
pub fn payload(&self) -> &[u8] {
&self.payload_buffer[..self.header.len as usize]
}
pub fn from_bytes(b: [u8; HV_MESSAGE_SIZE]) -> Self {
let mut msg = Self::default();
msg.as_bytes_mut().copy_from_slice(&b);
msg
}
pub fn into_bytes(self) -> [u8; HV_MESSAGE_SIZE] {
let mut v = [0; HV_MESSAGE_SIZE];
v.copy_from_slice(self.as_bytes());
v
}
}
#[repr(C)]
#[derive(Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct TimerMessagePayload {
pub timer_index: u32,
pub reserved: u32,
pub expiration_time: u64,
pub delivery_time: u64,
}
pub mod hypercall {
use super::*;
use core::ops::RangeInclusive;
#[bitfield(u64)]
pub struct Control {
pub code: u16,
pub fast: bool,
#[bits(10)]
pub variable_header_size: usize,
#[bits(4)]
pub _rsvd0: usize,
pub nested: bool,
#[bits(12)]
pub rep_count: usize,
#[bits(4)]
pub _rsvd1: usize,
#[bits(12)]
pub rep_start: usize,
#[bits(4)]
pub _rsvd2: usize,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
#[must_use]
pub struct HypercallOutput {
pub call_status: u16,
pub rsvd: u16,
#[bits(12)]
pub elements_processed: u16,
#[bits(20)]
pub rsvd2: u32,
}
impl From<HvError> for HypercallOutput {
fn from(e: HvError) -> Self {
Self::new().with_call_status(e.0)
}
}
impl HypercallOutput {
pub const SUCCESS: Self = Self::new();
pub fn result(&self) -> Result<(), HvError> {
if self.call_status() == 0 {
Ok(())
} else {
Err(HvError(self.call_status()))
}
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvRegisterAssoc {
pub name: HvRegisterName,
pub pad: [u32; 3],
pub value: HvRegisterValue,
}
impl<N: Into<HvRegisterName>, T: Into<HvRegisterValue>> From<(N, T)> for HvRegisterAssoc {
fn from((name, value): (N, T)) -> Self {
Self {
name: name.into(),
pad: [0; 3],
value: value.into(),
}
}
}
impl<N: Copy + Into<HvRegisterName>, T: Copy + Into<HvRegisterValue>> From<&(N, T)>
for HvRegisterAssoc
{
fn from(&(name, value): &(N, T)) -> Self {
Self {
name: name.into(),
pad: [0; 3],
value: value.into(),
}
}
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct MsrHypercallContents {
pub enable: bool,
pub locked: bool,
#[bits(10)]
pub reserved_p: u64,
#[bits(52)]
pub gpn: u64,
}
#[repr(C, align(8))]
#[derive(Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct PostMessage {
pub connection_id: u32,
pub padding: u32,
pub message_type: u32,
pub payload_size: u32,
pub payload: [u8; 240],
}
#[repr(C, align(8))]
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct SignalEvent {
pub connection_id: u32,
pub flag_number: u16,
pub rsvd: u16,
}
#[repr(C, packed)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct PostMessageDirect {
pub partition_id: u64,
pub vp_index: u32,
pub vtl: u8,
pub padding0: [u8; 3],
pub sint: u8,
pub padding1: [u8; 3],
pub message: HvMessage,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct SignalEventDirect {
pub target_partition: u64,
pub target_vp: u32,
pub target_vtl: u8,
pub target_sint: u8,
pub flag_number: u16,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct SignalEventDirectOutput {
pub newly_signaled: u8,
pub rsvd: [u8; 7],
}
#[repr(C)]
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct InterruptEntry {
pub source: HvInterruptSource,
pub rsvd: u32,
pub data: [u32; 2],
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvInterruptSource: u32 {
MSI = 1,
IO_APIC = 2,
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct InterruptTarget {
pub vector: u32,
pub flags: HvInterruptTargetFlags,
pub mask_or_format: u64,
}
#[bitfield(u32)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvInterruptTargetFlags {
pub multicast: bool,
pub processor_set: bool,
#[bits(30)]
pub reserved: u32,
}
pub const HV_DEVICE_INTERRUPT_TARGET_MULTICAST: u32 = 1;
pub const HV_DEVICE_INTERRUPT_TARGET_PROCESSOR_SET: u32 = 2;
pub const HV_GENERIC_SET_SPARSE_4K: u64 = 0;
pub const HV_GENERIC_SET_ALL: u64 = 1;
#[repr(C)]
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct RetargetDeviceInterrupt {
pub partition_id: u64,
pub device_id: u64,
pub entry: InterruptEntry,
pub rsvd: u64,
pub target_header: InterruptTarget,
}
#[bitfield(u8)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvInputVtl {
#[bits(4)]
pub target_vtl_value: u8,
pub use_target_vtl: bool,
#[bits(3)]
pub reserved: u8,
}
impl From<Vtl> for HvInputVtl {
fn from(value: Vtl) -> Self {
Self::from(Some(value))
}
}
impl From<Option<Vtl>> for HvInputVtl {
fn from(value: Option<Vtl>) -> Self {
Self::new()
.with_use_target_vtl(value.is_some())
.with_target_vtl_value(value.map_or(0, Into::into))
}
}
impl HvInputVtl {
pub fn target_vtl(&self) -> Result<Option<Vtl>, HvError> {
if self.reserved() != 0 {
return Err(HvError::InvalidParameter);
}
if self.use_target_vtl() {
Ok(Some(self.target_vtl_value().try_into()?))
} else {
Ok(None)
}
}
pub const CURRENT_VTL: Self = Self::new();
}
#[repr(C)]
#[derive(Copy, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct GetSetVpRegisters {
pub partition_id: u64,
pub vp_index: u32,
pub target_vtl: HvInputVtl,
pub rsvd: [u8; 3],
}
open_enum::open_enum! {
#[derive(Default)]
pub enum HvGuestOsMicrosoftIds: u8 {
UNDEFINED = 0x00,
MSDOS = 0x01,
WINDOWS_3X = 0x02,
WINDOWS_9X = 0x03,
WINDOWS_NT = 0x04,
WINDOWS_CE = 0x05,
}
}
#[bitfield(u64)]
pub struct HvGuestOsMicrosoft {
#[bits(40)]
_rsvd: u64,
#[bits(8)]
pub os_id: u8,
#[bits(16)]
pub vendor_id: u16,
}
open_enum::open_enum! {
#[derive(Default)]
pub enum HvGuestOsOpenSourceType: u8 {
UNDEFINED = 0x00,
LINUX = 0x01,
FREEBSD = 0x02,
XEN = 0x03,
ILLUMOS = 0x04,
}
}
#[bitfield(u64)]
pub struct HvGuestOsOpenSource {
#[bits(16)]
pub build_no: u16,
#[bits(32)]
pub version: u32,
#[bits(8)]
pub os_id: u8,
#[bits(7)]
pub os_type: u8,
#[bits(1)]
pub is_open_source: bool,
}
#[bitfield(u64)]
pub struct HvGuestOsId {
#[bits(63)]
_rsvd: u64,
is_open_source: bool,
}
impl HvGuestOsId {
pub fn microsoft(&self) -> Option<HvGuestOsMicrosoft> {
(!self.is_open_source()).then(|| HvGuestOsMicrosoft::from(u64::from(*self)))
}
pub fn open_source(&self) -> Option<HvGuestOsOpenSource> {
(self.is_open_source()).then(|| HvGuestOsOpenSource::from(u64::from(*self)))
}
pub fn as_u64(&self) -> u64 {
self.0
}
}
pub const HV_INTERCEPT_ACCESS_MASK_NONE: u32 = 0x00;
pub const HV_INTERCEPT_ACCESS_MASK_READ: u32 = 0x01;
pub const HV_INTERCEPT_ACCESS_MASK_WRITE: u32 = 0x02;
pub const HV_INTERCEPT_ACCESS_MASK_READ_WRITE: u32 =
HV_INTERCEPT_ACCESS_MASK_READ | HV_INTERCEPT_ACCESS_MASK_WRITE;
pub const HV_INTERCEPT_ACCESS_MASK_EXECUTE: u32 = 0x04;
open_enum::open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvInterceptType: u32 {
#![allow(non_upper_case_globals)]
HvInterceptTypeX64IoPort = 0x00000000,
HvInterceptTypeX64Msr = 0x00000001,
HvInterceptTypeX64Cpuid = 0x00000002,
HvInterceptTypeException = 0x00000003,
HvInterceptTypeHypercall = 0x00000008,
HvInterceptTypeUnknownSynicConnection = 0x0000000D,
HvInterceptTypeX64ApicEoi = 0x0000000E,
HvInterceptTypeRetargetInterruptWithUnknownDeviceId = 0x0000000F,
HvInterceptTypeX64IoPortRange = 0x00000011,
}
}
#[repr(transparent)]
#[derive(Copy, Clone, AsBytes, FromBytes, FromZeroes, Debug)]
pub struct HvInterceptParameters(u64);
impl HvInterceptParameters {
pub fn new_io_port(port: u16) -> Self {
Self(port as u64)
}
pub fn new_io_port_range(ports: RangeInclusive<u16>) -> Self {
let base = *ports.start() as u64;
let end = *ports.end() as u64;
Self(base | (end << 16))
}
pub fn new_exception(vector: u16) -> Self {
Self(vector as u64)
}
pub fn io_port(&self) -> u16 {
self.0 as u16
}
pub fn io_port_range(&self) -> RangeInclusive<u16> {
let base = self.0 as u16;
let end = (self.0 >> 16) as u16;
base..=end
}
pub fn cpuid_index(&self) -> u32 {
self.0 as u32
}
pub fn exception(&self) -> u16 {
self.0 as u16
}
}
#[repr(C)]
#[derive(Copy, Clone, AsBytes, FromBytes, FromZeroes, Debug)]
pub struct InstallIntercept {
pub partition_id: u64,
pub access_type_mask: u32,
pub intercept_type: HvInterceptType,
pub intercept_parameters: HvInterceptParameters,
}
#[repr(C)]
#[derive(Copy, Clone, AsBytes, FromBytes, FromZeroes, Debug)]
pub struct AssertVirtualInterrupt {
pub partition_id: u64,
pub interrupt_control: HvInterruptControl,
pub destination_address: u64,
pub requested_vector: u32,
pub target_vtl: u8,
pub rsvd0: u8,
pub rsvd1: u16,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct StartVirtualProcessorX64 {
pub partition_id: u64,
pub vp_index: u32,
pub target_vtl: u8,
pub rsvd0: u8,
pub rsvd1: u16,
pub vp_context: InitialVpContextX64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct InitialVpContextX64 {
pub rip: u64,
pub rsp: u64,
pub rflags: u64,
pub cs: HvX64SegmentRegister,
pub ds: HvX64SegmentRegister,
pub es: HvX64SegmentRegister,
pub fs: HvX64SegmentRegister,
pub gs: HvX64SegmentRegister,
pub ss: HvX64SegmentRegister,
pub tr: HvX64SegmentRegister,
pub ldtr: HvX64SegmentRegister,
pub idtr: HvX64TableRegister,
pub gdtr: HvX64TableRegister,
pub efer: u64,
pub cr0: u64,
pub cr3: u64,
pub cr4: u64,
pub msr_cr_pat: u64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct StartVirtualProcessorArm64 {
pub partition_id: u64,
pub vp_index: u32,
pub target_vtl: u8,
pub rsvd0: u8,
pub rsvd1: u16,
pub vp_context: InitialVpContextArm64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct InitialVpContextArm64 {
pub pc: u64,
pub sp_elh: u64,
pub sctlr_el1: u64,
pub mair_el1: u64,
pub tcr_el1: u64,
pub vbar_el1: u64,
pub ttbr0_el1: u64,
pub ttbr1_el1: u64,
pub x18: u64,
}
impl InitialVpContextX64 {
pub fn as_hv_register_assocs(&self) -> impl Iterator<Item = HvRegisterAssoc> + '_ {
let regs = [
(HvX64RegisterName::Rip, HvRegisterValue::from(self.rip)).into(),
(HvX64RegisterName::Rsp, HvRegisterValue::from(self.rsp)).into(),
(
HvX64RegisterName::Rflags,
HvRegisterValue::from(self.rflags),
)
.into(),
(HvX64RegisterName::Cs, HvRegisterValue::from(self.cs)).into(),
(HvX64RegisterName::Ds, HvRegisterValue::from(self.ds)).into(),
(HvX64RegisterName::Es, HvRegisterValue::from(self.es)).into(),
(HvX64RegisterName::Fs, HvRegisterValue::from(self.fs)).into(),
(HvX64RegisterName::Gs, HvRegisterValue::from(self.gs)).into(),
(HvX64RegisterName::Ss, HvRegisterValue::from(self.ss)).into(),
(HvX64RegisterName::Tr, HvRegisterValue::from(self.tr)).into(),
(HvX64RegisterName::Ldtr, HvRegisterValue::from(self.ldtr)).into(),
(HvX64RegisterName::Idtr, HvRegisterValue::from(self.idtr)).into(),
(HvX64RegisterName::Gdtr, HvRegisterValue::from(self.gdtr)).into(),
(HvX64RegisterName::Efer, HvRegisterValue::from(self.efer)).into(),
(HvX64RegisterName::Cr0, HvRegisterValue::from(self.cr0)).into(),
(HvX64RegisterName::Cr3, HvRegisterValue::from(self.cr3)).into(),
(HvX64RegisterName::Cr4, HvRegisterValue::from(self.cr4)).into(),
(
HvX64RegisterName::Pat,
HvRegisterValue::from(self.msr_cr_pat),
)
.into(),
];
regs.into_iter()
}
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct TranslateGvaControlFlagsX64 {
pub validate_read: bool,
pub validate_write: bool,
pub validate_execute: bool,
pub privilege_exempt: bool,
pub set_page_table_bits: bool,
pub tlb_flush_inhibit: bool,
pub supervisor_access: bool,
pub user_access: bool,
pub enforce_smap: bool,
pub override_smap: bool,
pub shadow_stack: bool,
#[bits(45)]
_unused: u64,
input_vtl_value: u8,
}
impl TranslateGvaControlFlagsX64 {
pub fn input_vtl(&self) -> HvInputVtl {
self.input_vtl_value().into()
}
pub fn with_input_vtl(self, input_vtl: HvInputVtl) -> Self {
self.with_input_vtl_value(input_vtl.into())
}
pub fn set_input_vtl(&mut self, input_vtl: HvInputVtl) {
self.set_input_vtl_value(input_vtl.into())
}
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct TranslateGvaControlFlagsArm64 {
pub validate_read: bool,
pub validate_write: bool,
pub validate_execute: bool,
_reserved0: bool,
pub set_page_table_bits: bool,
pub tlb_flush_inhibit: bool,
pub supervisor_access: bool,
pub user_access: bool,
pub pan_set: bool,
pub pan_clear: bool,
#[bits(46)]
_unused: u64,
#[bits(8)]
input_vtl_value: u8,
}
impl TranslateGvaControlFlagsArm64 {
pub fn input_vtl(&self) -> HvInputVtl {
self.input_vtl_value().into()
}
pub fn with_input_vtl(self, input_vtl: HvInputVtl) -> Self {
self.with_input_vtl_value(input_vtl.into())
}
pub fn set_input_vtl(&mut self, input_vtl: HvInputVtl) {
self.set_input_vtl_value(input_vtl.into())
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct TranslateVirtualAddressX64 {
pub partition_id: u64,
pub vp_index: u32,
pub reserved: u32,
pub control_flags: TranslateGvaControlFlagsX64,
pub gva_page: u64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct TranslateVirtualAddressArm64 {
pub partition_id: u64,
pub vp_index: u32,
pub reserved: u32,
pub control_flags: TranslateGvaControlFlagsArm64,
pub gva_page: u64,
}
open_enum::open_enum! {
pub enum TranslateGvaResultCode: u32 {
SUCCESS = 0,
PAGE_NOT_PRESENT = 1,
PRIVILEGE_VIOLATION = 2,
INVALID_PAGE_TABLE_FLAGS = 3,
GPA_UNMAPPED = 4,
GPA_NO_READ_ACCESS = 5,
GPA_NO_WRITE_ACCESS = 6,
GPA_ILLEGAL_OVERLAY_ACCESS = 7,
INTERCEPT = 8,
GPA_UNACCEPTED = 9,
}
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct TranslateGvaResult {
pub result_code: u32,
pub cache_type: u8,
pub overlay_page: bool,
#[bits(23)]
pub reserved: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct TranslateVirtualAddressOutput {
pub translation_result: TranslateGvaResult,
pub gpa_page: u64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct TranslateGvaResultExX64 {
pub result: TranslateGvaResult,
pub reserved: u64,
pub event_info: HvX64PendingEvent,
}
const_assert!(size_of::<TranslateGvaResultExX64>() == 0x30);
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct TranslateGvaResultExArm64 {
pub result: TranslateGvaResult,
}
const_assert!(size_of::<TranslateGvaResultExArm64>() == 0x8);
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct TranslateVirtualAddressExOutputX64 {
pub translation_result: TranslateGvaResultExX64,
pub gpa_page: u64,
pub reserved: u64,
}
const_assert!(size_of::<TranslateVirtualAddressExOutputX64>() == 0x40);
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct TranslateVirtualAddressExOutputArm64 {
pub translation_result: TranslateGvaResultExArm64,
pub gpa_page: u64,
}
const_assert!(size_of::<TranslateVirtualAddressExOutputArm64>() == 0x10);
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct GetVpIndexFromApicId {
pub partition_id: u64,
pub target_vtl: u8,
pub reserved: [u8; 7],
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct EnableVpVtlX64 {
pub partition_id: u64,
pub vp_index: u32,
pub target_vtl: u8,
pub reserved: [u8; 3],
pub vp_vtl_context: InitialVpContextX64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct EnableVpVtlArm64 {
pub partition_id: u64,
pub vp_index: u32,
pub target_vtl: u8,
pub reserved: [u8; 3],
pub vp_vtl_context: InitialVpContextArm64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct ModifyVtlProtectionMask {
pub partition_id: u64,
pub map_flags: HvMapGpaFlags,
pub target_vtl: HvInputVtl,
pub reserved: [u8; 3],
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct CheckSparseGpaPageVtlAccess {
pub partition_id: u64,
pub target_vtl: HvInputVtl,
pub desired_access: u8,
pub reserved0: u16,
pub reserved1: u32,
}
const_assert!(size_of::<CheckSparseGpaPageVtlAccess>() == 0x10);
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct CheckSparseGpaPageVtlAccessOutput {
pub result_code: u8,
pub denied_access: u8,
#[bits(4)]
pub intercepting_vtl: u32,
#[bits(12)]
_reserved0: u32,
_reserved1: u32,
}
const_assert!(size_of::<CheckSparseGpaPageVtlAccessOutput>() == 0x8);
open_enum::open_enum! {
pub enum CheckGpaPageVtlAccessResultCode: u32 {
SUCCESS = 0,
MEMORY_INTERCEPT = 1,
}
}
pub const HV_VTL_PERMISSION_SET_SIZE: usize = 2;
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct VtlPermissionSet {
pub vtl_permission_from_1: [u16; HV_VTL_PERMISSION_SET_SIZE],
}
open_enum::open_enum! {
pub enum AcceptMemoryType: u32 {
ANY = 0,
RAM = 1,
}
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HostVisibilityType: u8 {
PRIVATE = 0,
SHARED = 3,
}
}
impl HostVisibilityType {
const fn from_bits(value: u8) -> Self {
Self(value)
}
const fn into_bits(value: Self) -> u8 {
value.0
}
}
#[bitfield(u32)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct AcceptPagesAttributes {
#[bits(6)]
pub memory_type: u32,
#[bits(2)]
pub host_visibility: HostVisibilityType,
#[bits(3)]
pub vtl_set: u32,
#[bits(21)]
_reserved: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct AcceptGpaPages {
pub partition_id: u64,
pub page_attributes: AcceptPagesAttributes,
pub vtl_permission_set: VtlPermissionSet,
pub gpa_page_base: u64,
}
const_assert!(size_of::<AcceptGpaPages>() == 0x18);
#[bitfield(u32)]
pub struct UnacceptPagesAttributes {
#[bits(3)]
pub vtl_set: u32,
#[bits(29)]
_reserved: u32,
}
#[repr(C)]
pub struct UnacceptGpaPages {
pub partition_id: u64,
pub page_attributes: UnacceptPagesAttributes,
pub vtl_permission_set: VtlPermissionSet,
pub gpa_page_base: u64,
}
const_assert!(size_of::<UnacceptGpaPages>() == 0x18);
#[bitfield(u32)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct ModifyHostVisibility {
#[bits(2)]
pub host_visibility: HostVisibilityType,
#[bits(30)]
_reserved: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct ModifySparsePageVisibility {
pub partition_id: u64,
pub host_visibility: ModifyHostVisibility,
pub reserved: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct QuerySparsePageVisibility {
pub partition_id: u64,
}
#[bitfield(u8)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct EnablePartitionVtlFlags {
pub enable_mbec: bool,
pub enable_supervisor_shadow_stack: bool,
pub enable_hardware_hvpt: bool,
#[bits(5)]
pub reserved: u8,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct EnablePartitionVtl {
pub partition_id: u64,
pub target_vtl: u8,
pub flags: EnablePartitionVtlFlags,
pub reserved_z0: u16,
pub reserved_z1: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct FlushVirtualAddressSpace {
pub address_space: u64,
pub flags: HvFlushFlags,
pub processor_mask: u64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct FlushVirtualAddressSpaceEx {
pub address_space: u64,
pub flags: HvFlushFlags,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct PinUnpinGpaPageRangesHeader {
pub reserved: u64,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvFlushFlags {
pub all_processors: bool,
pub all_virtual_address_spaces: bool,
pub non_global_mappings_only: bool,
pub use_extended_range_format: bool,
pub use_target_vtl: bool,
#[bits(3)]
_reserved: u8,
pub target_vtl0: bool,
pub target_vtl1: bool,
#[bits(54)]
_reserved2: u64,
}
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
#[repr(transparent)]
pub struct HvGvaRange(pub u64);
impl HvGvaRange {
pub fn as_simple(self) -> HvGvaRangeSimple {
HvGvaRangeSimple(self.0)
}
pub fn as_extended(self) -> HvGvaRangeExtended {
HvGvaRangeExtended(self.0)
}
pub fn as_extended_large_page(self) -> HvGvaRangeExtendedLargePage {
HvGvaRangeExtendedLargePage(self.0)
}
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvGvaRangeSimple {
#[bits(12)]
pub additional_pages: u64,
#[bits(52)]
pub gva_page_number: u64,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvGvaRangeExtended {
#[bits(11)]
pub additional_pages: u64,
pub large_page: bool,
#[bits(52)]
pub gva_page_number: u64,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvGvaRangeExtendedLargePage {
#[bits(11)]
pub additional_pages: u64,
pub large_page: bool,
pub page_size: bool,
#[bits(8)]
_reserved: u64,
#[bits(43)]
pub gva_large_page_number: u64,
}
#[derive(Debug, Copy, Clone, AsBytes, FromBytes, FromZeroes)]
#[repr(transparent)]
pub struct HvGpaRange(pub u64);
impl HvGpaRange {
pub fn as_simple(self) -> HvGpaRangeSimple {
HvGpaRangeSimple(self.0)
}
pub fn as_extended(self) -> HvGpaRangeExtended {
HvGpaRangeExtended(self.0)
}
pub fn as_extended_large_page(self) -> HvGpaRangeExtendedLargePage {
HvGpaRangeExtendedLargePage(self.0)
}
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvGpaRangeSimple {
#[bits(12)]
pub additional_pages: u64,
#[bits(52)]
pub gpa_page_number: u64,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvGpaRangeExtended {
#[bits(11)]
pub additional_pages: u64,
pub large_page: bool,
#[bits(52)]
pub gpa_page_number: u64,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvGpaRangeExtendedLargePage {
#[bits(11)]
pub additional_pages: u64,
pub large_page: bool,
pub page_size: bool,
#[bits(8)]
_reserved: u64,
#[bits(43)]
pub gpa_large_page_number: u64,
}
pub const HV_HYPERCALL_MMIO_MAX_DATA_LENGTH: usize = 64;
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct MemoryMappedIoRead {
pub gpa: u64,
pub access_width: u32,
pub reserved_z0: u32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct MemoryMappedIoReadOutput {
pub data: [u8; HV_HYPERCALL_MMIO_MAX_DATA_LENGTH],
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct MemoryMappedIoWrite {
pub gpa: u64,
pub access_width: u32,
pub reserved_z0: u32,
pub data: [u8; HV_HYPERCALL_MMIO_MAX_DATA_LENGTH],
}
}
macro_rules! registers {
($name:ident {
$(
$(#[$vattr:meta])*
$variant:ident = $value:expr
),*
$(,)?
}) => {
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum $name: u32 {
#![allow(non_upper_case_globals)]
$($variant = $value,)*
InstructionEmulationHints = 0x00000002,
InternalActivityState = 0x00000004,
GuestCrashP0 = 0x00000210,
GuestCrashP1 = 0x00000211,
GuestCrashP2 = 0x00000212,
GuestCrashP3 = 0x00000213,
GuestCrashP4 = 0x00000214,
GuestCrashCtl = 0x00000215,
PendingInterruption = 0x00010002,
InterruptState = 0x00010003,
PendingEvent0 = 0x00010004,
PendingEvent1 = 0x00010005,
DeliverabilityNotifications = 0x00010006,
GicrBaseGpa = 0x00063000,
VpRuntime = 0x00090000,
GuestOsId = 0x00090002,
VpIndex = 0x00090003,
TimeRefCount = 0x00090004,
CpuManagementVersion = 0x00090007,
VpAssistPage = 0x00090013,
VpRootSignalCount = 0x00090014,
ReferenceTsc = 0x00090017,
VpConfig = 0x00090018,
Ghcb = 0x00090019,
ReferenceTscSequence = 0x0009001A,
GuestSchedulerEvent = 0x0009001B,
Sint0 = 0x000A0000,
Sint1 = 0x000A0001,
Sint2 = 0x000A0002,
Sint3 = 0x000A0003,
Sint4 = 0x000A0004,
Sint5 = 0x000A0005,
Sint6 = 0x000A0006,
Sint7 = 0x000A0007,
Sint8 = 0x000A0008,
Sint9 = 0x000A0009,
Sint10 = 0x000A000A,
Sint11 = 0x000A000B,
Sint12 = 0x000A000C,
Sint13 = 0x000A000D,
Sint14 = 0x000A000E,
Sint15 = 0x000A000F,
Scontrol = 0x000A0010,
Sversion = 0x000A0011,
Sifp = 0x000A0012,
Sipp = 0x000A0013,
Eom = 0x000A0014,
Sirbp = 0x000A0015,
Stimer0Config = 0x000B0000,
Stimer0Count = 0x000B0001,
Stimer1Config = 0x000B0002,
Stimer1Count = 0x000B0003,
Stimer2Config = 0x000B0004,
Stimer2Count = 0x000B0005,
Stimer3Config = 0x000B0006,
Stimer3Count = 0x000B0007,
StimeUnhaltedTimerConfig = 0x000B0100,
StimeUnhaltedTimerCount = 0x000B0101,
VsmCodePageOffsets = 0x000D0002,
VsmVpStatus = 0x000D0003,
VsmPartitionStatus = 0x000D0004,
VsmVina = 0x000D0005,
VsmCapabilities = 0x000D0006,
VsmPartitionConfig = 0x000D0007,
GuestVsmPartitionConfig = 0x000D0008,
VsmVpSecureConfigVtl0 = 0x000D0010,
VsmVpSecureConfigVtl1 = 0x000D0011,
VsmVpSecureConfigVtl2 = 0x000D0012,
VsmVpSecureConfigVtl3 = 0x000D0013,
VsmVpSecureConfigVtl4 = 0x000D0014,
VsmVpSecureConfigVtl5 = 0x000D0015,
VsmVpSecureConfigVtl6 = 0x000D0016,
VsmVpSecureConfigVtl7 = 0x000D0017,
VsmVpSecureConfigVtl8 = 0x000D0018,
VsmVpSecureConfigVtl9 = 0x000D0019,
VsmVpSecureConfigVtl10 = 0x000D001A,
VsmVpSecureConfigVtl11 = 0x000D001B,
VsmVpSecureConfigVtl12 = 0x000D001C,
VsmVpSecureConfigVtl13 = 0x000D001D,
VsmVpSecureConfigVtl14 = 0x000D001E,
VsmVpWaitForTlbLock = 0x000D0020,
}
}
impl From<HvRegisterName> for $name {
fn from(name: HvRegisterName) -> Self {
Self(name.0)
}
}
impl From<$name> for HvRegisterName {
fn from(name: $name) -> Self {
Self(name.0)
}
}
};
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, AsBytes, FromBytes, FromZeroes)]
pub struct HvRegisterName(pub u32);
registers! {
HvAllArchRegisterName {}
}
impl From<HvAllArchRegisterName> for HvX64RegisterName {
fn from(name: HvAllArchRegisterName) -> Self {
Self(name.0)
}
}
impl From<HvAllArchRegisterName> for HvArm64RegisterName {
fn from(name: HvAllArchRegisterName) -> Self {
Self(name.0)
}
}
registers! {
HvX64RegisterName {
Rax = 0x00020000,
Rcx = 0x00020001,
Rdx = 0x00020002,
Rbx = 0x00020003,
Rsp = 0x00020004,
Rbp = 0x00020005,
Rsi = 0x00020006,
Rdi = 0x00020007,
R8 = 0x00020008,
R9 = 0x00020009,
R10 = 0x0002000a,
R11 = 0x0002000b,
R12 = 0x0002000c,
R13 = 0x0002000d,
R14 = 0x0002000e,
R15 = 0x0002000f,
Rip = 0x00020010,
Rflags = 0x00020011,
Xmm0 = 0x00030000,
Xmm1 = 0x00030001,
Xmm2 = 0x00030002,
Xmm3 = 0x00030003,
Xmm4 = 0x00030004,
Xmm5 = 0x00030005,
Xmm6 = 0x00030006,
Xmm7 = 0x00030007,
Xmm8 = 0x00030008,
Xmm9 = 0x00030009,
Xmm10 = 0x0003000A,
Xmm11 = 0x0003000B,
Xmm12 = 0x0003000C,
Xmm13 = 0x0003000D,
Xmm14 = 0x0003000E,
Xmm15 = 0x0003000F,
FpMmx0 = 0x00030010,
FpMmx1 = 0x00030011,
FpMmx2 = 0x00030012,
FpMmx3 = 0x00030013,
FpMmx4 = 0x00030014,
FpMmx5 = 0x00030015,
FpMmx6 = 0x00030016,
FpMmx7 = 0x00030017,
FpControlStatus = 0x00030018,
XmmControlStatus = 0x00030019,
Cr0 = 0x00040000,
Cr2 = 0x00040001,
Cr3 = 0x00040002,
Cr4 = 0x00040003,
Cr8 = 0x00040004,
Xfem = 0x00040005,
IntermediateCr0 = 0x00041000,
IntermediateCr3 = 0x00041002,
IntermediateCr4 = 0x00041003,
IntermediateCr8 = 0x00041004,
Dr0 = 0x00050000,
Dr1 = 0x00050001,
Dr2 = 0x00050002,
Dr3 = 0x00050003,
Dr6 = 0x00050004,
Dr7 = 0x00050005,
Es = 0x00060000,
Cs = 0x00060001,
Ss = 0x00060002,
Ds = 0x00060003,
Fs = 0x00060004,
Gs = 0x00060005,
Ldtr = 0x00060006,
Tr = 0x00060007,
Idtr = 0x00070000,
Gdtr = 0x00070001,
Tsc = 0x00080000,
Efer = 0x00080001,
KernelGsBase = 0x00080002,
ApicBase = 0x00080003,
Pat = 0x00080004,
SysenterCs = 0x00080005,
SysenterEip = 0x00080006,
SysenterEsp = 0x00080007,
Star = 0x00080008,
Lstar = 0x00080009,
Cstar = 0x0008000a,
Sfmask = 0x0008000b,
InitialApicId = 0x0008000c,
MsrMtrrCap = 0x0008000d,
MsrMtrrDefType = 0x0008000e,
MsrMtrrPhysBase0 = 0x00080010,
MsrMtrrPhysBase1 = 0x00080011,
MsrMtrrPhysBase2 = 0x00080012,
MsrMtrrPhysBase3 = 0x00080013,
MsrMtrrPhysBase4 = 0x00080014,
MsrMtrrPhysBase5 = 0x00080015,
MsrMtrrPhysBase6 = 0x00080016,
MsrMtrrPhysBase7 = 0x00080017,
MsrMtrrPhysBase8 = 0x00080018,
MsrMtrrPhysBase9 = 0x00080019,
MsrMtrrPhysBaseA = 0x0008001a,
MsrMtrrPhysBaseB = 0x0008001b,
MsrMtrrPhysBaseC = 0x0008001c,
MsrMtrrPhysBaseD = 0x0008001d,
MsrMtrrPhysBaseE = 0x0008001e,
MsrMtrrPhysBaseF = 0x0008001f,
MsrMtrrPhysMask0 = 0x00080040,
MsrMtrrPhysMask1 = 0x00080041,
MsrMtrrPhysMask2 = 0x00080042,
MsrMtrrPhysMask3 = 0x00080043,
MsrMtrrPhysMask4 = 0x00080044,
MsrMtrrPhysMask5 = 0x00080045,
MsrMtrrPhysMask6 = 0x00080046,
MsrMtrrPhysMask7 = 0x00080047,
MsrMtrrPhysMask8 = 0x00080048,
MsrMtrrPhysMask9 = 0x00080049,
MsrMtrrPhysMaskA = 0x0008004a,
MsrMtrrPhysMaskB = 0x0008004b,
MsrMtrrPhysMaskC = 0x0008004c,
MsrMtrrPhysMaskD = 0x0008004d,
MsrMtrrPhysMaskE = 0x0008004e,
MsrMtrrPhysMaskF = 0x0008004f,
MsrMtrrFix64k00000 = 0x00080070,
MsrMtrrFix16k80000 = 0x00080071,
MsrMtrrFix16kA0000 = 0x00080072,
MsrMtrrFix4kC0000 = 0x00080073,
MsrMtrrFix4kC8000 = 0x00080074,
MsrMtrrFix4kD0000 = 0x00080075,
MsrMtrrFix4kD8000 = 0x00080076,
MsrMtrrFix4kE0000 = 0x00080077,
MsrMtrrFix4kE8000 = 0x00080078,
MsrMtrrFix4kF0000 = 0x00080079,
MsrMtrrFix4kF8000 = 0x0008007a,
TscAux = 0x0008007B,
Bndcfgs = 0x0008007C,
DebugCtl = 0x0008007D,
MCount = 0x0008007E,
ACount = 0x0008007F,
SgxLaunchControl0 = 0x00080080,
SgxLaunchControl1 = 0x00080081,
SgxLaunchControl2 = 0x00080082,
SgxLaunchControl3 = 0x00080083,
SpecCtrl = 0x00080084,
PredCmd = 0x00080085,
VirtSpecCtrl = 0x00080086,
TscVirtualOffset = 0x00080087,
TsxCtrl = 0x00080088,
MsrMcUpdatePatchLevel = 0x00080089,
Available1 = 0x0008008A,
Xss = 0x0008008B,
UCet = 0x0008008C,
SCet = 0x0008008D,
Ssp = 0x0008008E,
Pl0Ssp = 0x0008008F,
Pl1Ssp = 0x00080090,
Pl2Ssp = 0x00080091,
Pl3Ssp = 0x00080092,
InterruptSspTableAddr = 0x00080093,
TscVirtualMultiplier = 0x00080094,
TscDeadline = 0x00080095,
TscAdjust = 0x00080096,
Pasid = 0x00080097,
UmwaitControl = 0x00080098,
Xfd = 0x00080099,
XfdErr = 0x0008009A,
Hypercall = 0x00090001,
RegisterPage = 0x0009001C,
EmulatedTimerPeriod = 0x00090030,
EmulatedTimerControl = 0x00090031,
PmTimerAssist = 0x00090032,
SevControl = 0x00090040,
}
}
registers! {
HvArm64RegisterName {
HypervisorVersion = 0x00000100,
PrivilegesAndFeaturesInfo = 0x00000200,
FeaturesInfo = 0x00000201,
ImplementationLimitsInfo = 0x00000202,
HardwareFeaturesInfo = 0x00000203,
CpuManagementFeaturesInfo = 0x00000204,
PasidFeaturesInfo = 0x00000205,
SkipLevelFeaturesInfo = 0x00000206,
NestedVirtFeaturesInfo = 0x00000207,
IptFeaturesInfo = 0x00000208,
IsolationConfiguration = 0x00000209,
X0 = 0x00020000,
X1 = 0x00020001,
X2 = 0x00020002,
X3 = 0x00020003,
X4 = 0x00020004,
X5 = 0x00020005,
X6 = 0x00020006,
X7 = 0x00020007,
X8 = 0x00020008,
X9 = 0x00020009,
X10 = 0x0002000A,
X11 = 0x0002000B,
X12 = 0x0002000C,
X13 = 0x0002000D,
X14 = 0x0002000E,
X15 = 0x0002000F,
X16 = 0x00020010,
X17 = 0x00020011,
X18 = 0x00020012,
X19 = 0x00020013,
X20 = 0x00020014,
X21 = 0x00020015,
X22 = 0x00020016,
X23 = 0x00020017,
X24 = 0x00020018,
X25 = 0x00020019,
X26 = 0x0002001A,
X27 = 0x0002001B,
X28 = 0x0002001C,
XFp = 0x0002001D,
XLr = 0x0002001E,
XSp = 0x0002001F, XSpEl0 = 0x00020020,
XSpElx = 0x00020021,
XPc = 0x00020022,
Cpsr = 0x00020023,
SpsrEl2 = 0x00021002,
SctlrEl1 = 0x00040002,
Ttbr0El1 = 0x00040005,
Ttbr1El1 = 0x00040006,
TcrEl1 = 0x00040007,
EsrEl1 = 0x00040008,
FarEl1 = 0x00040009,
MairEl1 = 0x0004000b,
VbarEl1 = 0x0004000c,
ElrEl1 = 0x00040015,
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, AsBytes, FromBytes, FromZeroes)]
pub struct HvRegisterValue(pub AlignedU128);
impl HvRegisterValue {
pub fn as_u128(&self) -> u128 {
self.0.into()
}
pub fn as_u64(&self) -> u64 {
self.as_u128() as u64
}
pub fn as_u32(&self) -> u32 {
self.as_u128() as u32
}
pub fn as_u16(&self) -> u16 {
self.as_u128() as u16
}
pub fn as_u8(&self) -> u8 {
self.as_u128() as u8
}
pub fn as_table(&self) -> HvX64TableRegister {
HvX64TableRegister::read_from_prefix(self.as_bytes()).unwrap()
}
pub fn as_segment(&self) -> HvX64SegmentRegister {
HvX64SegmentRegister::read_from_prefix(self.as_bytes()).unwrap()
}
}
impl From<u8> for HvRegisterValue {
fn from(val: u8) -> Self {
(val as u128).into()
}
}
impl From<u16> for HvRegisterValue {
fn from(val: u16) -> Self {
(val as u128).into()
}
}
impl From<u32> for HvRegisterValue {
fn from(val: u32) -> Self {
(val as u128).into()
}
}
impl From<u64> for HvRegisterValue {
fn from(val: u64) -> Self {
(val as u128).into()
}
}
impl From<u128> for HvRegisterValue {
fn from(val: u128) -> Self {
Self(val.into())
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64TableRegister {
pub pad: [u16; 3],
pub limit: u16,
pub base: u64,
}
impl From<HvX64TableRegister> for HvRegisterValue {
fn from(val: HvX64TableRegister) -> Self {
Self::read_from_prefix(val.as_bytes()).unwrap()
}
}
impl From<HvRegisterValue> for HvX64TableRegister {
fn from(val: HvRegisterValue) -> Self {
Self::read_from_prefix(val.as_bytes()).unwrap()
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64SegmentRegister {
pub base: u64,
pub limit: u32,
pub selector: u16,
pub attributes: u16,
}
impl From<HvX64SegmentRegister> for HvRegisterValue {
fn from(val: HvX64SegmentRegister) -> Self {
Self::read_from_prefix(val.as_bytes()).unwrap()
}
}
impl From<HvRegisterValue> for HvX64SegmentRegister {
fn from(val: HvRegisterValue) -> Self {
Self::read_from_prefix(val.as_bytes()).unwrap()
}
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes, PartialEq, Eq)]
pub struct HvDeliverabilityNotificationsRegister {
pub nmi_notification: bool,
pub interrupt_notification: bool,
#[bits(4)]
pub interrupt_priority: u8,
#[bits(42)]
pub reserved: u64,
pub sints: u16,
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvVtlEntryReason: u32 {
RESERVED = 0,
VTL_CALL = 1,
INTERRUPT = 2,
INTERCEPT = 3,
}
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvVpVtlControl {
pub entry_reason: HvVtlEntryReason,
pub vina_status: u8,
pub reserved_z0: u8,
pub reserved_z1: u16,
pub registers: [u64; 2],
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvRegisterVsmVina {
pub vector: u8,
pub enabled: bool,
pub auto_reset: bool,
pub auto_eoi: bool,
#[bits(53)]
pub reserved: u64,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvVpAssistPage {
pub apic_assist: u32,
pub reserved_z0: u32,
pub vtl_control: HvVpVtlControl,
pub nested_enlightenments_control: u64,
pub enlighten_vm_entry: u8,
pub reserved_z1: [u8; 7],
pub current_nested_vmcs: u64,
pub synthetic_time_unhalted_timer_expired: u8,
pub reserved_z2: [u8; 7],
pub virtualization_fault_information: [u8; 40],
pub reserved_z3: u64,
pub intercept_message: HvMessage,
pub vtl_return_actions: [u8; 256],
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvVpAssistPageActionSignalEvent {
pub action_type: u64,
pub target_vp: u32,
pub target_vtl: u8,
pub target_sint: u8,
pub flag_number: u16,
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvInterceptAccessType: u8 {
READ = 0,
WRITE = 1,
EXECUTE = 2,
}
}
#[bitfield(u16)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64VpExecutionState {
#[bits(2)]
pub cpl: u8,
pub cr0_pe: bool,
pub cr0_am: bool,
pub efer_lma: bool,
pub debug_active: bool,
pub interruption_pending: bool,
#[bits(4)]
pub vtl: u8,
pub enclave_mode: bool,
pub interrupt_shadow: bool,
pub virtualization_fault_active: bool,
#[bits(2)]
pub reserved: u8,
}
#[bitfield(u16)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvArm64VpExecutionState {
#[bits(2)]
pub cpl: u8,
pub debug_active: bool,
pub interruption_pending: bool,
#[bits(4)]
pub vtl: u8,
pub virtualization_fault_active: bool,
#[bits(7)]
pub reserved: u8,
}
#[repr(C)]
#[derive(Debug, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64InterceptMessageHeader {
pub vp_index: u32,
pub instruction_length_and_cr8: u8,
pub intercept_access_type: HvInterceptAccessType,
pub execution_state: HvX64VpExecutionState,
pub cs_segment: HvX64SegmentRegister,
pub rip: u64,
pub rflags: u64,
}
impl HvX64InterceptMessageHeader {
pub fn instruction_len(&self) -> u8 {
self.instruction_length_and_cr8 & 0xf
}
pub fn cr8(&self) -> u8 {
self.instruction_length_and_cr8 >> 4
}
}
#[repr(C)]
#[derive(Debug, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct HvArm64InterceptMessageHeader {
pub vp_index: u32,
pub instruction_length: u8,
pub intercept_access_type: HvInterceptAccessType,
pub execution_state: HvArm64VpExecutionState,
pub pc: u64,
pub cspr: u64,
}
const_assert!(size_of::<HvArm64InterceptMessageHeader>() == 0x18);
#[repr(transparent)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64IoPortAccessInfo(pub u8);
impl HvX64IoPortAccessInfo {
pub fn new(access_size: u8, string_op: bool, rep_prefix: bool) -> Self {
let mut info = access_size & 0x7;
if string_op {
info |= 0x8;
}
if rep_prefix {
info |= 0x10;
}
Self(info)
}
pub fn access_size(&self) -> u8 {
self.0 & 0x7
}
pub fn string_op(&self) -> bool {
self.0 & 0x8 != 0
}
pub fn rep_prefix(&self) -> bool {
self.0 & 0x10 != 0
}
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64IoPortInterceptMessage {
pub header: HvX64InterceptMessageHeader,
pub port_number: u16,
pub access_info: HvX64IoPortAccessInfo,
pub instruction_byte_count: u8,
pub reserved: u32,
pub rax: u64,
pub instruction_bytes: [u8; 16],
pub ds_segment: HvX64SegmentRegister,
pub es_segment: HvX64SegmentRegister,
pub rcx: u64,
pub rsi: u64,
pub rdi: u64,
}
#[bitfield(u8)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64MemoryAccessInfo {
pub gva_valid: bool,
pub gva_gpa_valid: bool,
pub hypercall_output_pending: bool,
pub tlb_locked: bool,
pub supervisor_shadow_stack: bool,
#[bits(3)]
pub reserved1: u8,
}
#[bitfield(u8)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvArm64MemoryAccessInfo {
pub gva_valid: bool,
pub gva_gpa_valid: bool,
pub hypercall_output_pending: bool,
#[bits(5)]
pub reserved1: u8,
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvCacheType: u32 {
#![allow(non_upper_case_globals)]
HvCacheTypeUncached = 0,
HvCacheTypeWriteCombining = 1,
HvCacheTypeWriteThrough = 4,
HvCacheTypeWriteProtected = 5,
HvCacheTypeWriteBack = 6,
}
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64MemoryInterceptMessage {
pub header: HvX64InterceptMessageHeader,
pub cache_type: HvCacheType,
pub instruction_byte_count: u8,
pub memory_access_info: HvX64MemoryAccessInfo,
pub tpr_priority: u8,
pub reserved: u8,
pub guest_virtual_address: u64,
pub guest_physical_address: u64,
pub instruction_bytes: [u8; 16],
}
const_assert!(size_of::<HvX64MemoryInterceptMessage>() == 0x50);
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvArm64MemoryInterceptMessage {
pub header: HvArm64InterceptMessageHeader,
pub cache_type: HvCacheType,
pub instruction_byte_count: u8,
pub memory_access_info: HvArm64MemoryAccessInfo,
pub reserved1: u16,
pub instruction_bytes: [u8; 4],
pub reserved2: u32,
pub guest_virtual_address: u64,
pub guest_physical_address: u64,
pub syndrome: u64,
}
const_assert!(size_of::<HvArm64MemoryInterceptMessage>() == 0x40);
#[repr(C)]
#[derive(Debug, FromBytes, FromZeroes)]
pub struct HvArm64MmioInterceptMessage {
pub header: HvArm64InterceptMessageHeader,
pub guest_physical_address: u64,
pub access_size: u32,
pub data: [u8; 32],
}
const_assert!(size_of::<HvArm64MmioInterceptMessage>() == 0x48);
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64MsrInterceptMessage {
pub header: HvX64InterceptMessageHeader,
pub msr_number: u32,
pub reserved: u32,
pub rdx: u64,
pub rax: u64,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64SipiInterceptMessage {
pub header: HvX64InterceptMessageHeader,
pub target_vp_index: u32,
pub vector: u32,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64SynicSintDeliverableMessage {
pub header: HvX64InterceptMessageHeader,
pub deliverable_sints: u16,
pub rsvd1: u16,
pub rsvd2: u32,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvArm64SynicSintDeliverableMessage {
pub header: HvArm64InterceptMessageHeader,
pub deliverable_sints: u16,
pub rsvd1: u16,
pub rsvd2: u32,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64InterruptionDeliverableMessage {
pub header: HvX64InterceptMessageHeader,
pub deliverable_type: HvX64PendingInterruptionType,
pub rsvd: [u8; 3],
pub rsvd2: u32,
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvX64PendingInterruptionType: u8 {
HV_X64_PENDING_INTERRUPT = 0,
HV_X64_PENDING_NMI = 2,
HV_X64_PENDING_EXCEPTION = 3,
HV_X64_PENDING_SOFTWARE_INTERRUPT = 4,
HV_X64_PENDING_PRIVILEGED_SOFTWARE_EXCEPTION = 5,
HV_X64_PENDING_SOFTWARE_EXCEPTION = 6,
}
}
#[repr(C)]
#[derive(Debug, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64HypercallInterceptMessage {
pub header: HvX64InterceptMessageHeader,
pub rax: u64,
pub rbx: u64,
pub rcx: u64,
pub rdx: u64,
pub r8: u64,
pub rsi: u64,
pub rdi: u64,
pub xmm_registers: [AlignedU128; 6],
pub flags: HvHypercallInterceptMessageFlags,
pub rsvd2: [u32; 3],
}
#[repr(C)]
#[derive(Debug, Clone, AsBytes, FromBytes, FromZeroes)]
pub struct HvArm64HypercallInterceptMessage {
pub header: HvArm64InterceptMessageHeader,
pub immediate: u16,
pub reserved: u16,
pub flags: HvHypercallInterceptMessageFlags,
pub x: [u64; 18],
}
#[bitfield(u32)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvHypercallInterceptMessageFlags {
pub is_isolated: bool,
#[bits(31)]
_reserved: u32,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64CpuidInterceptMessage {
pub header: HvX64InterceptMessageHeader,
pub rax: u64,
pub rcx: u64,
pub rdx: u64,
pub rbx: u64,
pub default_result_rax: u64,
pub default_result_rcx: u64,
pub default_result_rdx: u64,
pub default_result_rbx: u64,
}
#[bitfield(u8)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64ExceptionInfo {
pub error_code_valid: bool,
pub software_exception: bool,
#[bits(6)]
reserved: u8,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64ExceptionInterceptMessage {
pub header: HvX64InterceptMessageHeader,
pub vector: u16,
pub exception_info: HvX64ExceptionInfo,
pub instruction_byte_count: u8,
pub error_code: u32,
pub exception_parameter: u64,
pub reserved: u64,
pub instruction_bytes: [u8; 16],
pub ds_segment: HvX64SegmentRegister,
pub ss_segment: HvX64SegmentRegister,
pub rax: u64,
pub rcx: u64,
pub rdx: u64,
pub rbx: u64,
pub rsp: u64,
pub rbp: u64,
pub rsi: u64,
pub rdi: u64,
pub r8: u64,
pub r9: u64,
pub r10: u64,
pub r11: u64,
pub r12: u64,
pub r13: u64,
pub r14: u64,
pub r15: u64,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvInvalidVpRegisterMessage {
pub vp_index: u32,
pub reserved: u32,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64ApicEoiMessage {
pub vp_index: u32,
pub interrupt_vector: u32,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64UnrecoverableExceptionMessage {
pub header: HvX64InterceptMessageHeader,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64HaltMessage {
pub header: HvX64InterceptMessageHeader,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvArm64ResetInterceptMessage {
pub header: HvArm64InterceptMessageHeader,
pub reset_type: HvArm64ResetType,
pub padding: u32,
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvArm64ResetType: u32 {
POWER_OFF = 0,
REBOOT = 1,
}
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvInterruptType : u32 {
#![allow(non_upper_case_globals)]
HvArm64InterruptTypeFixed = 0x0000,
HvX64InterruptTypeFixed = 0x0000,
HvX64InterruptTypeLowestPriority = 0x0001,
HvX64InterruptTypeSmi = 0x0002,
HvX64InterruptTypeRemoteRead = 0x0003,
HvX64InterruptTypeNmi = 0x0004,
HvX64InterruptTypeInit = 0x0005,
HvX64InterruptTypeSipi = 0x0006,
HvX64InterruptTypeExtInt = 0x0007,
HvX64InterruptTypeLocalInt0 = 0x0008,
HvX64InterruptTypeLocalInt1 = 0x0009,
}
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvInterruptControl {
interrupt_type_value: u32,
pub x86_level_triggered: bool,
pub x86_logical_destination_mode: bool,
pub arm64_asserted: bool,
#[bits(29)]
pub unused: u32,
}
impl HvInterruptControl {
pub fn interrupt_type(&self) -> HvInterruptType {
HvInterruptType(self.interrupt_type_value())
}
pub fn set_interrupt_type(&mut self, ty: HvInterruptType) {
self.set_interrupt_type_value(ty.0)
}
pub fn with_interrupt_type(self, ty: HvInterruptType) -> Self {
self.with_interrupt_type_value(ty.0)
}
}
#[bitfield(u64)]
pub struct HvRegisterVsmCapabilities {
pub dr6_shared: bool,
pub mbec_vtl_mask: u16,
pub deny_lower_vtl_startup: bool,
pub supervisor_shadow_stack: bool,
pub hardware_hvpt_available: bool,
pub software_hvpt_available: bool,
#[bits(6)]
pub hardware_hvpt_range_bits: u8,
pub intercept_page_available: bool,
pub return_action_available: bool,
pub vtl0_alias_map_available: bool,
pub intercept_not_present_available: bool,
pub install_intercept_ex: bool,
pub intercept_system_reset_available: bool,
#[bits(31)]
pub reserved: u64,
}
#[bitfield(u64)]
pub struct HvRegisterVsmPartitionConfig {
pub enable_vtl_protection: bool,
#[bits(4)]
pub default_vtl_protection_mask: u8,
pub zero_memory_on_reset: bool,
pub deny_lower_vtl_startup: bool,
pub intercept_acceptance: bool,
pub intercept_enable_vtl_protection: bool,
pub intercept_vp_startup: bool,
pub intercept_cpuid_unimplemented: bool,
pub intercept_unrecoverable_exception: bool,
pub intercept_page: bool,
pub intercept_restore_partition_time: bool,
pub intercept_not_present: bool,
pub intercept_system_reset: bool,
#[bits(48)]
pub reserved: u64,
}
#[bitfield(u64)]
pub struct HvRegisterVsmPartitionStatus {
#[bits(16)]
pub enabled_vtl_set: u16,
#[bits(4)]
pub maximum_vtl: u8,
#[bits(16)]
pub mbec_enabled_vtl_set: u16,
#[bits(4)]
pub supervisor_shadow_stack_enabled_vtl_set: u8,
#[bits(24)]
pub reserved: u64,
}
#[bitfield(u64)]
pub struct HvRegisterGuestVsmPartitionConfig {
#[bits(4)]
pub maximum_vtl: u8,
#[bits(60)]
pub reserved: u64,
}
#[bitfield(u64)]
pub struct HvRegisterVsmVpStatus {
#[bits(4)]
pub active_vtl: u8,
pub active_mbec_enabled: bool,
#[bits(11)]
pub reserved_mbz0: u16,
#[bits(16)]
pub enabled_vtl_set: u16,
#[bits(32)]
pub reserved_mbz1: u32,
}
#[bitfield(u64)]
pub struct HvRegisterVsmCodePageOffsets {
#[bits(12)]
pub call_offset: u16,
#[bits(12)]
pub return_offset: u16,
#[bits(40)]
pub reserved: u64,
}
#[repr(C)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvStimerState {
pub undelivered_message_pending: u32,
pub reserved: u32,
pub config: u64,
pub count: u64,
pub adjustment: u64,
pub undelivered_expiration_time: u64,
}
#[repr(C)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvSyntheticTimersState {
pub timers: [HvStimerState; 4],
pub reserved: [u64; 5],
}
#[bitfield(u64)]
pub struct HvInternalActivityRegister {
pub startup_suspend: bool,
pub halt_suspend: bool,
pub idle_suspend: bool,
#[bits(61)]
pub reserved: u64,
}
#[bitfield(u64)]
pub struct HvSynicSint {
pub vector: u8,
_reserved: u8,
pub masked: bool,
pub auto_eoi: bool,
pub polling: bool,
_reserved2: bool,
pub proxy: bool,
#[bits(43)]
_reserved2: u64,
}
#[bitfield(u64)]
pub struct HvSynicScontrol {
pub enabled: bool,
#[bits(63)]
_reserved: u64,
}
#[bitfield(u64)]
pub struct HvSynicSimpSiefp {
pub enabled: bool,
#[bits(11)]
_reserved: u64,
#[bits(52)]
pub base_gpn: u64,
}
#[bitfield(u64)]
pub struct HvSynicStimerConfig {
pub enabled: bool,
pub periodic: bool,
pub lazy: bool,
pub auto_enable: bool,
pub apic_vector: u8,
pub direct_mode: bool,
#[bits(3)]
pub _reserved1: u8,
#[bits(4)]
pub sint: u8,
#[bits(44)]
pub _reserved2: u64,
}
pub const HV_X64_PENDING_EVENT_EXCEPTION: u8 = 0;
pub const HV_X64_PENDING_EVENT_MEMORY_INTERCEPT: u8 = 1;
pub const HV_X64_PENDING_EVENT_NESTED_MEMORY_INTERCEPT: u8 = 2;
pub const HV_X64_PENDING_EVENT_VIRTUALIZATION_FAULT: u8 = 3;
pub const HV_X64_PENDING_EVENT_HYPERCALL_OUTPUT: u8 = 4;
pub const HV_X64_PENDING_EVENT_EXT_INT: u8 = 5;
pub const HV_X64_PENDING_EVENT_SHADOW_IPT: u8 = 6;
#[bitfield(u128)]
pub struct HvX64PendingExceptionEvent {
pub event_pending: bool,
#[bits(3)]
pub event_type: u8,
#[bits(4)]
pub reserved0: u8,
pub deliver_error_code: bool,
#[bits(7)]
pub reserved1: u8,
pub vector: u16,
pub error_code: u32,
pub exception_parameter: u64,
}
#[bitfield(u128)]
pub struct HvX64PendingVirtualizationFaultEvent {
pub event_pending: bool,
#[bits(3)]
pub event_type: u8,
#[bits(4)]
pub reserved0: u8,
pub reserved1: u8,
pub parameter0: u16,
pub code: u32,
pub parameter1: u64,
}
#[bitfield(u8)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64PendingEventMemoryInterceptPendingEventHeader {
pub event_pending: bool,
#[bits(3)]
pub event_type: u8,
#[bits(4)]
_reserved0: u8,
}
#[bitfield(u8)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64PendingEventMemoryInterceptAccessFlags {
pub guest_linear_address_valid: bool,
pub caused_by_gpa_access: bool,
#[bits(6)]
_reserved1: u8,
}
#[repr(C)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64PendingEventMemoryIntercept {
pub event_header: HvX64PendingEventMemoryInterceptPendingEventHeader,
pub target_vtl: u8,
pub access_type: HvInterceptAccessType,
pub access_flags: HvX64PendingEventMemoryInterceptAccessFlags,
pub _reserved2: u32,
pub guest_linear_address: u64,
pub guest_physical_address: u64,
pub _reserved3: u64,
}
const_assert!(size_of::<HvX64PendingEventMemoryIntercept>() == 0x20);
#[bitfield(u128)]
pub struct HvX64PendingHypercallOutputEvent {
pub event_pending: bool,
#[bits(3)]
pub event_type: u8,
#[bits(4)]
pub reserved0: u8,
pub retired: bool,
#[bits(23)]
pub reserved1: u32,
pub output_size: u32,
pub output_gpa: u64,
}
#[bitfield(u128)]
pub struct HvX64PendingExtIntEvent {
pub event_pending: bool,
#[bits(3)]
pub event_type: u8,
#[bits(4)]
pub reserved0: u8,
pub vector: u8,
#[bits(48)]
pub reserved1: u64,
pub reserved2: u64,
}
#[bitfield(u128)]
pub struct HvX64PendingShadowIptEvent {
pub event_pending: bool,
#[bits(4)]
pub event_type: u8,
#[bits(59)]
pub reserved0: u64,
pub reserved1: u64,
}
#[bitfield(u128)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64PendingEventReg0 {
pub event_pending: bool,
#[bits(3)]
pub event_type: u8,
#[bits(4)]
pub reserved: u8,
#[bits(120)]
pub data: u128,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64PendingEvent {
pub reg_0: HvX64PendingEventReg0,
pub reg_1: AlignedU128,
}
const_assert!(size_of::<HvX64PendingEvent>() == 0x20);
impl From<HvX64PendingExceptionEvent> for HvX64PendingEvent {
fn from(exception_event: HvX64PendingExceptionEvent) -> Self {
HvX64PendingEvent {
reg_0: HvX64PendingEventReg0::from(u128::from(exception_event)),
reg_1: 0u128.into(),
}
}
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64PendingInterruptionRegister {
pub interruption_pending: bool,
#[bits(3)]
pub interruption_type: u8,
pub deliver_error_code: bool,
#[bits(4)]
pub instruction_length: u8,
pub nested_event: bool,
#[bits(6)]
pub reserved: u8,
pub interruption_vector: u16,
pub error_code: u32,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64InterruptStateRegister {
pub interrupt_shadow: bool,
pub nmi_masked: bool,
#[bits(62)]
pub reserved: u64,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvInstructionEmulatorHintsRegister {
pub partition_secure_vtl_enabled: bool,
pub mbec_user_execute_control: bool,
#[bits(62)]
pub _padding: u64,
}
open_enum! {
#[derive(AsBytes, FromBytes, FromZeroes)]
pub enum HvAarch64PendingEventType: u8 {
EXCEPTION = 0,
SYNTHETIC_EXCEPTION = 1,
HYPERCALL_OUTPUT = 2,
}
}
impl HvAarch64PendingEventType {
const fn from_bits(val: u8) -> Self {
HvAarch64PendingEventType(val)
}
const fn into_bits(self) -> u8 {
self.0
}
}
#[bitfield[u8]]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvAarch64PendingEventHeader {
#[bits(1)]
pub event_pending: bool,
#[bits(3)]
pub event_type: HvAarch64PendingEventType,
#[bits(4)]
pub reserved: u8,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvAarch64PendingExceptionEvent {
pub header: HvAarch64PendingEventHeader,
pub _padding: [u8; 7],
pub syndrome: u64,
pub fault_address: u64,
}
#[bitfield[u8]]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvAarch64PendingHypercallOutputEventFlags {
#[bits(1)]
pub retired: u8,
#[bits(7)]
pub reserved: u8,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvAarch64PendingHypercallOutputEvent {
pub header: HvAarch64PendingEventHeader,
pub flags: HvAarch64PendingHypercallOutputEventFlags,
pub reserved: u16,
pub output_size: u32,
pub output_gpa: u64,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvAarch64PendingEvent {
pub header: HvAarch64PendingEventHeader,
pub event_data: [u8; 15],
pub _padding: [u64; 2],
}
#[bitfield(u32)]
#[derive(PartialEq, Eq, AsBytes, FromBytes, FromZeroes)]
pub struct HvMapGpaFlags {
pub readable: bool,
pub writable: bool,
pub kernel_executable: bool,
pub user_executable: bool,
pub supervisor_shadow_stack: bool,
pub paging_writability: bool,
pub verify_paging_writability: bool,
#[bits(8)]
_padding0: u32,
pub adjustable: bool,
#[bits(16)]
_padding1: u32,
}
pub const HV_MAP_GPA_PERMISSIONS_NONE: HvMapGpaFlags = HvMapGpaFlags::new();
pub const HV_MAP_GPA_PERMISSIONS_ALL: HvMapGpaFlags = HvMapGpaFlags::new()
.with_readable(true)
.with_writable(true)
.with_kernel_executable(true)
.with_user_executable(true);
#[repr(C)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvMonitorPage {
pub trigger_state: HvMonitorTriggerState,
pub reserved1: u32,
pub trigger_group: [HvMonitorTriggerGroup; 4],
pub reserved2: [u64; 3],
pub next_check_time: [[u32; 32]; 4],
pub latency: [[u16; 32]; 4],
pub reserved3: [u64; 32],
pub parameter: [[HvMonitorParameter; 32]; 4],
pub reserved4: [u8; 1984],
}
#[repr(C)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvMonitorPageSmall {
pub trigger_state: HvMonitorTriggerState,
pub reserved1: u32,
pub trigger_group: [HvMonitorTriggerGroup; 4],
}
#[repr(C)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvMonitorTriggerGroup {
pub pending: u32,
pub armed: u32,
}
#[repr(C)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvMonitorParameter {
pub connection_id: u32,
pub flag_number: u16,
pub reserved: u16,
}
#[bitfield(u32)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvMonitorTriggerState {
#[bits(4)]
pub group_enable: u32,
#[bits(28)]
pub reserved: u32,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvPmTimerInfo {
#[bits(16)]
pub port: u16,
#[bits(1)]
pub width_24: bool,
#[bits(1)]
pub enabled: bool,
#[bits(14)]
pub reserved1: u32,
#[bits(32)]
pub reserved2: u32,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64RegisterSevControl {
pub enable_encrypted_state: bool,
#[bits(11)]
_rsvd1: u64,
#[bits(52)]
pub vmsa_gpa_page_number: u64,
}
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvRegisterReferenceTsc {
pub enable: bool,
#[bits(11)]
pub reserved_p: u64,
#[bits(52)]
pub gpn: u64,
}
#[repr(C)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvReferenceTscPage {
pub tsc_sequence: u32,
pub reserved1: u32,
pub tsc_scale: u64,
pub tsc_offset: i64,
pub timeline_bias: u64,
pub tsc_multiplier: u64,
pub reserved2: [u64; 507],
}
pub const HV_REFERENCE_TSC_SEQUENCE_INVALID: u32 = 0;
#[bitfield(u64)]
#[derive(AsBytes, FromBytes, FromZeroes)]
pub struct HvX64VmgexitInterceptMessageFlags {
pub ghcb_page_valid: bool,
pub ghcb_request_error: bool,
#[bits(62)]
_reserved: u64,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64VmgexitInterceptMessageGhcbPageStandard {
pub ghcb_protocol_version: u16,
_reserved: [u16; 3],
pub sw_exit_code: u64,
pub sw_exit_info1: u64,
pub sw_exit_info2: u64,
pub sw_scratch: u64,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64VmgexitInterceptMessageGhcbPage {
pub ghcb_usage: u32,
_reserved: u32,
pub standard: HvX64VmgexitInterceptMessageGhcbPageStandard,
}
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64VmgexitInterceptMessage {
pub header: HvX64InterceptMessageHeader,
pub ghcb_msr: u64,
pub flags: HvX64VmgexitInterceptMessageFlags,
pub ghcb_page: HvX64VmgexitInterceptMessageGhcbPage,
}
#[bitfield(u64)]
pub struct HvRegisterVpAssistPage {
pub enabled: bool,
#[bits(11)]
_reserved: u64,
#[bits(52)]
pub gpa_page_number: u64,
}
pub const HV_X64_REGISTER_CLASS_GENERAL: u8 = 0;
pub const HV_X64_REGISTER_CLASS_IP: u8 = 1;
pub const HV_X64_REGISTER_CLASS_XMM: u8 = 2;
pub const HV_X64_REGISTER_CLASS_SEGMENT: u8 = 3;
pub const HV_X64_REGISTER_CLASS_FLAGS: u8 = 4;
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, FromZeroes)]
pub struct HvX64RegisterPage {
pub version: u16,
pub is_valid: u8,
pub vtl: u8,
pub dirty: u32,
pub gp_registers: [u64; 16],
pub rip: u64,
pub rflags: u64,
pub reserved: u64,
pub xmm: [u128; 6],
pub segment: [u128; 6],
pub cr0: u64,
pub cr3: u64,
pub cr4: u64,
pub cr8: u64,
pub efer: u64,
pub dr7: u64,
pub pending_interruption: HvX64PendingInterruptionRegister,
pub interrupt_state: HvX64InterruptStateRegister,
pub instruction_emulation_hints: HvInstructionEmulatorHintsRegister,
pub reserved_end: [u8; 3672],
}
const _: () = assert!(size_of::<HvX64RegisterPage>() == HV_PAGE_SIZE_USIZE);
#[bitfield(u64)]
pub struct HvRegisterVsmWpWaitForTlbLock {
pub wait: bool,
#[bits(63)]
_reserved: u64,
}
#[bitfield(u64)]
pub struct HvRegisterVsmVpSecureVtlConfig {
pub mbec_enabled: bool,
pub tlb_locked: bool,
pub supervisor_shadow_stack_enabled: bool,
pub hardware_hvpt_enabled: bool,
#[bits(60)]
_reserved: u64,
}