use core::{ffi::c_void, mem::MaybeUninit};
use crate::{ffi::{HResult, winhvemulation::*, winhvplatform::*, winhvplatformdefs::*}, hvplatform::Partition};
impl WHvEmulatorIoAccessInfo
{
pub fn buffer(&self)->&[u8]
{
&self.data[..self.access_size as usize]
}
pub fn buffer_mut(&mut self)->&mut [u8]
{
&mut self.data[..self.access_size as usize]
}
}
impl WHvEmulatorMemoryAccessInfo
{
pub fn buffer(&self)->&[u8]
{
&self.data[..self.access_size as usize]
}
pub fn buffer_mut(&mut self)->&mut [u8]
{
&mut self.data[..self.access_size as usize]
}
}
pub struct EmulationContext<'a>
{
partition:&'a Partition,
emulator:&'a Emulator,
vp_index:u32
}
impl<'a> EmulationContext<'a>
{
pub const fn from_raw_parts(partition:&'a Partition,emulator:&'a Emulator,vp_index:u32)->Self
{
Self
{
partition,
emulator,
vp_index
}
}
}
unsafe extern "system" fn port_io_callback(context:*const c_void,io_access:*mut WHvEmulatorIoAccessInfo)->HResult
{
let ctxt:&EmulationContext=unsafe{&*context.cast()};
let access=unsafe{&mut *io_access};
if access.direction
{
match ctxt.emulator.port_output_fn
{
Some(f)=>f(access.port,access.buffer()),
None=>HResult::E_FAIL
}
}
else
{
match ctxt.emulator.port_input_fn
{
Some(f)=>f(access.port,access.buffer_mut()),
None=>HResult::E_FAIL
}
}
}
unsafe extern "system" fn memory_callback(context:*const c_void,memory_access:*mut WHvEmulatorMemoryAccessInfo)->HResult
{
let ctxt:&EmulationContext=unsafe{&*context.cast()};
let access=unsafe{&mut *memory_access};
if access.direction
{
match ctxt.emulator.memory_write_fn
{
Some(f)=>f(access.gpa,access.buffer()),
None=>HResult::E_FAIL
}
}
else
{
match ctxt.emulator.memory_read_fn
{
Some(f)=>f(access.gpa,access.buffer_mut()),
None=>HResult::E_FAIL
}
}
}
unsafe extern "system" fn get_vcpu_reg_callback(context:*const c_void,register_name:*const WHvRegisterName,register_count:u32,register_values:*mut WHvRegisterValue)->HResult
{
unsafe
{
let ctxt:&EmulationContext=&*context.cast();
match get_virtual_processor_registers(ctxt.partition.0,ctxt.vp_index,register_name,register_count,register_values)
{
Ok(_)=>HResult::S_OK,
Err(e)=>e
}
}
}
unsafe extern "system" fn set_vcpu_reg_callback(context:*const c_void,register_name:*const WHvRegisterName,register_count:u32,register_values:*const WHvRegisterValue)->HResult
{
unsafe
{
let ctxt:&EmulationContext=&*context.cast();
match set_virtual_processor_registers(ctxt.partition.0,ctxt.vp_index,register_name,register_count,register_values)
{
Ok(_)=>HResult::S_OK,
Err(e)=>e
}
}
}
unsafe extern "system" fn translation_callback(context:*const c_void,gva:u64,translate_flags:WHvTranslateGvaFlags,result_code:*mut WHvTranslateGvaResultCode,gpa:*mut u64)->HResult
{
unsafe
{
let ctxt:&EmulationContext=&*context.cast();
let mut result:MaybeUninit<WHvTranslateGvaResult>=MaybeUninit::uninit();
let hr=match translate_gva(ctxt.partition.0,ctxt.vp_index,gva,translate_flags,result.as_mut_ptr(),gpa)
{
Ok(_)=>HResult::S_OK,
Err(e)=>e
};
*result_code=result.assume_init_ref().result_code;
hr
}
}
static EMULATOR_CALLBACKS:WHvEmulatorCallbacks=WHvEmulatorCallbacks
{
size:size_of::<WHvEmulatorCallbacks>() as u32,
reserved:0,
io_port_callback:Some(port_io_callback),
memory_callback:Some(memory_callback),
get_virtual_register_callback:Some(get_vcpu_reg_callback),
set_virtual_register_callback:Some(set_vcpu_reg_callback),
translate_gva_page_callback:Some(translation_callback)
};
pub struct Emulator
{
handle:WHvEmulatorHandle,
port_input_fn:Option<PortInputFn>,
port_output_fn:Option<PortOutputFn>,
memory_read_fn:Option<MemoryReadFn>,
memory_write_fn:Option<MemoryWriteFn>
}
pub type PortInputFn=fn(port:u16,buffer:&mut [u8])->HResult;
pub type PortOutputFn=fn(port:u16,buffer:&[u8])->HResult;
pub type MemoryReadFn=fn(gpa:u64,buffer:&mut [u8])->HResult;
pub type MemoryWriteFn=fn(gpa:u64,buffer:&[u8])->HResult;
impl Emulator
{
pub fn new(port_input_fn:Option<PortInputFn>,port_output_fn:Option<PortOutputFn>,memory_read_fn:Option<MemoryReadFn>,memory_write_fn:Option<MemoryWriteFn>)->Result<Self,HResult>
{
unsafe
{
match create_emulator(&raw const EMULATOR_CALLBACKS)
{
Ok(handle)=>Ok
(
Self
{
handle,
port_input_fn,
port_output_fn,
memory_read_fn,
memory_write_fn
}
),
Err(e)=>return Err(e)
}
}
}
pub fn try_io_emulation(&self,partition:&Partition,vp_index:u32,exit_context:&WHvRunVpExitContext)->Result<WHvEmulatorStatus,HResult>
{
let ctxt=EmulationContext::from_raw_parts(partition,self,vp_index);
unsafe
{
try_io_emulation(self.handle,(&raw const ctxt).cast(),&raw const exit_context.vp_context,&raw const exit_context.exit_context.io_port_access)
}
}
pub fn try_mmio_emulation(&self,partition:&Partition,vp_index:u32,exit_context:&WHvRunVpExitContext)->Result<WHvEmulatorStatus,HResult>
{
let ctxt=EmulationContext::from_raw_parts(partition,self,vp_index);
unsafe
{
try_mmio_emulation(self.handle,(&raw const ctxt).cast(),&raw const exit_context.vp_context,&raw const exit_context.exit_context.memory_access)
}
}
}
impl Drop for Emulator
{
fn drop(&mut self)
{
unsafe
{
let _=destroy_emulator(self.handle);
}
}
}