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()
{
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
}
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)
}
}
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)
}
}
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)
}
}
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)
}
}