whpx 0.1.0

Idiomatic Rust Bindings of Windows Hypervisor Platform
Documentation
// Windows Hypervisor Instruction Emulator APIs

use core::{ffi::c_void, mem::transmute};

use bitfield_struct::bitfield;

use super::{GetProcAddress, HResult, LoadLibraryA, whv_binding, winhvplatformdefs::*};

#[bitfield(u32)] pub struct WHvEmulatorStatus
{
	pub emulation_successful:bool,
	pub internal_emulation_failure:bool,
	pub io_port_callback_failed:bool,
	pub memory_callback_failed:bool,
	pub translate_gva_page_callback_failed:bool,
	pub translate_gva_page_callback_gpa_is_not_aligned:bool,
	pub get_virtual_processor_registers_callback_failed:bool,
	pub set_virtual_processor_registers_callback_failed:bool,
	pub interrupt_caused_intercept:bool,
	pub guest_cannot_be_faulted:bool,
	#[bits(22)] rsvd:u32
}

#[derive(Default, Debug)]
#[repr(C)] pub struct WHvEmulatorMemoryAccessInfo
{
	pub gpa:u64,
	pub direction:bool,
	pub access_size:u8,
	pub data:[u8;8]
}

#[derive(Default, Debug)]
#[repr(C,align(4))] pub struct WHvEmulatorIoAccessInfo
{
	pub direction:bool,
	pub port:u16,
	pub access_size:u16,
	pad:u16,
	pub data:[u8;4]
}

pub type WHvEmulatorIoPortCallback=unsafe extern "system" fn (context:*const c_void,io_access:*mut WHvEmulatorIoAccessInfo)->HResult;
pub type WHvEmulatorMemoryCallback=unsafe extern "system" fn (context:*const c_void,memory_access:*mut WHvEmulatorMemoryAccessInfo)->HResult;
pub type WHvEmulatorGetVirtualRegisterCallback=unsafe extern "system" fn (context:*const c_void,register_name:*const WHvRegisterName,register_count:u32,register_values:*mut WHvRegisterValue)->HResult;
pub type WHvEmulatorSetVirtualRegisterCallback=unsafe extern "system" fn (context:*const c_void,register_name:*const WHvRegisterName,register_count:u32,register_values:*const WHvRegisterValue)->HResult;
pub type WHvEmulatorTranslateGvaPageCallback=unsafe extern "system" fn (context:*const c_void,gva:u64,translate_flags:WHvTranslateGvaFlags,result_code:*mut WHvTranslateGvaResultCode,gpa:*mut u64)->HResult;

#[derive(Default, Debug, Clone)]
#[repr(C)] pub struct WHvEmulatorCallbacks
{
	pub size:u32,
	pub reserved:u32,
	pub io_port_callback:Option<WHvEmulatorIoPortCallback>,
	pub memory_callback:Option<WHvEmulatorMemoryCallback>,
	pub get_virtual_register_callback:Option<WHvEmulatorGetVirtualRegisterCallback>,
	pub set_virtual_register_callback:Option<WHvEmulatorSetVirtualRegisterCallback>,
	pub translate_gva_page_callback:Option<WHvEmulatorTranslateGvaPageCallback>
}

#[derive(Default, Debug, Clone, Copy)]
#[repr(C)] pub struct WHvEmulatorHandle(*mut c_void);

whv_binding!(WHV_EMULATOR_CREATE_EMULATOR,WHvEmulatorCreateEmulator,whpx_default_create_emulator,(callbacks:*const WHvEmulatorCallbacks,emulator:*mut WHvEmulatorHandle));
whv_binding!(WHV_EMULATOR_DESTROY_EMULATOR,WHvEmulatorDestroyEmulator,whpx_default_destroy_emulator,(emulator:WHvEmulatorHandle));
whv_binding!(WHV_EMULATOR_TRY_IO_EMULATION,WHvEmulatorTryIoEmulation,whpx_default_try_io_emulation,(emulator:WHvEmulatorHandle,context:*const c_void,vp_context:*const WHvX64VpExitContext,io_context:*const WHvX64IoPortAccessContext,emulator_status:*mut WHvEmulatorStatus));
whv_binding!(WHV_EMULATOR_TRY_MMIO_EMULATION,WHvEmulatorTryMmioEmulation,whpx_default_try_mmio_emulation,(emulator:WHvEmulatorHandle,context:*const c_void,vp_context:*const WHvX64VpExitContext,mmio_context:*const WHvMemoryAccessContext,emulator_status:*mut WHvEmulatorStatus));

pub(super) fn init_bindings()->bool
{
	let dll_base=unsafe{LoadLibraryA(c"WinHvEmulation.dll".as_ptr())};
	if dll_base.is_null()
	{
		// WinHvEmulator.dll does not exist!
		return false;
	}
	unsafe
	{
		macro_rules! get_proc_address
		{
			($name:expr,$type:expr,$type_name:ty)=>
			{
				let p=GetProcAddress(dll_base,$type.as_ptr());
				if p.is_null()
				{
					core::hint::cold_path();
				}
				else
				{
					$name=transmute::<*const c_void,$type_name>(p);
				}
			};
		}
		get_proc_address!(WHV_EMULATOR_CREATE_EMULATOR,c"WHvEmulatorCreateEmulator",WHvEmulatorCreateEmulator);
		get_proc_address!(WHV_EMULATOR_DESTROY_EMULATOR,c"WHvEmulatorDestroyEmulator",WHvEmulatorDestroyEmulator);
		get_proc_address!(WHV_EMULATOR_TRY_IO_EMULATION,c"WHvEmulatorTryIoEmulation",WHvEmulatorTryIoEmulation);
		get_proc_address!(WHV_EMULATOR_TRY_MMIO_EMULATION,c"WHvEmulatorTryMmioEmulation",WHvEmulatorTryMmioEmulation);
	}
	true
}

/// ## Safety
/// This function is a very simple wrapper of WHPX API. Make sure arguments are valid.
pub unsafe fn create_emulator(callbacks:*const WHvEmulatorCallbacks)->Result<WHvEmulatorHandle,HResult>
{
	let mut handle=WHvEmulatorHandle::default();
	let hr=unsafe{WHV_EMULATOR_CREATE_EMULATOR(callbacks,&raw mut handle)};
	match hr
	{
		HResult::S_OK=>Ok(handle),
		_=>Err(hr)
	}
}

/// ## Safety
/// This function is a very simple wrapper of WHPX API. Make sure arguments are valid.
pub unsafe fn destroy_emulator(emulator:WHvEmulatorHandle)->Result<(),HResult>
{
	let hr=unsafe{WHV_EMULATOR_DESTROY_EMULATOR(emulator)};
	match hr
	{
		HResult::S_OK=>Ok(()),
		_=>Err(hr)
	}
}

/// ## Safety
/// This function is a very simple wrapper of WHPX API. Make sure arguments are valid.
pub unsafe fn try_io_emulation(emulator:WHvEmulatorHandle,context:*const c_void,vp_context:*const WHvX64VpExitContext,io_context:*const WHvX64IoPortAccessContext)->Result<WHvEmulatorStatus,HResult>
{
	let mut emulator_status=WHvEmulatorStatus::default();
	let hr=unsafe{WHV_EMULATOR_TRY_IO_EMULATION(emulator,context,vp_context,io_context,&mut emulator_status)};
	match hr
	{
		HResult::S_OK=>Ok(emulator_status),
		_=>Err(hr)
	}
}

/// ## Safety
/// This function is a very simple wrapper of WHPX API. Make sure arguments are valid.
pub unsafe fn try_mmio_emulation(emulator:WHvEmulatorHandle,context:*const c_void,vp_context:*const WHvX64VpExitContext,mmio_context:*const WHvMemoryAccessContext)->Result<WHvEmulatorStatus,HResult>
{
	let mut emulator_status=WHvEmulatorStatus::default();
	let hr=unsafe{WHV_EMULATOR_TRY_MMIO_EMULATION(emulator,context,vp_context,mmio_context,&mut emulator_status)};
	match hr
	{
		HResult::S_OK=>Ok(emulator_status),
		_=>Err(hr)
	}
}