pub mod consts;
pub mod ffi;
use self::ffi::*;
use crate::{match_MemPerm, match_error_code, Error, MemPerm};
use core::fmt;
use libc::*;
pub fn create_vm() -> Result<(), Error> {
match_error_code(unsafe { hv_vm_create(HV_VM_DEFAULT) })
}
pub fn map_mem(mem: &[u8], gpa: u64, mem_perm: MemPerm) -> Result<(), Error> {
match_error_code(unsafe {
hv_vm_map(
mem.as_ptr() as *const c_void,
gpa as hv_gpaddr_t,
mem.len() as size_t,
match_MemPerm(mem_perm),
)
})
}
pub fn protect_mem(gpa: u64, size: usize, mem_perm: MemPerm) -> Result<(), Error> {
match_error_code(unsafe {
hv_vm_protect(gpa as hv_gpaddr_t, size as size_t, match_MemPerm(mem_perm))
})
}
pub fn unmap_mem(gpa: u64, size: usize) -> Result<(), Error> {
match_error_code(unsafe { hv_vm_unmap(gpa as hv_gpaddr_t, size as size_t) })
}
pub fn sync_tsc(tsc: u64) -> Result<(), Error> {
match_error_code(unsafe { hv_vm_sync_tsc(tsc) })
}
pub fn interrupt_vcpus(vcpu_ids: &[u32]) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_interrupt(vcpu_ids.as_ptr(), vcpu_ids.len() as c_uint) })
}
pub struct VirtualCpu {
id: hv_vcpuid_t,
}
#[derive(Clone)]
#[repr(C)]
pub enum Register {
RIP,
RFLAGS,
RAX,
RCX,
RDX,
RBX,
RSI,
RDI,
RSP,
RBP,
R8,
R9,
R10,
R11,
R12,
R13,
R14,
R15,
CS,
SS,
DS,
ES,
FS,
GS,
IDT_BASE,
IDT_LIMIT,
GDT_BASE,
GDT_LIMIT,
LDTR,
LDT_BASE,
LDT_LIMIT,
LDT_AR,
TR,
TSS_BASE,
TSS_LIMIT,
TSS_AR,
CR0,
CR1,
CR2,
CR3,
CR4,
DR0,
DR1,
DR2,
DR3,
DR4,
DR5,
DR6,
DR7,
TPR,
XCR0,
REGISTERS_MAX,
}
impl VirtualCpu {
pub fn new() -> Result<VirtualCpu, Error> {
let mut vcpuid: hv_vcpuid_t = 0;
match_error_code(unsafe { hv_vcpu_create(&mut vcpuid, HV_VCPU_DEFAULT) })?;
Ok(VirtualCpu { id: vcpuid })
}
pub fn get_id(&self) -> hv_vcpuid_t {
self.id
}
pub fn interrupt(&self) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_interrupt(&(self.id), 1 as c_uint) })
}
pub fn exec_time(&self) -> Result<u64, Error> {
let mut exec_time: u64 = 0;
let _error = match_error_code(unsafe { hv_vcpu_get_exec_time(self.id, &mut exec_time) })?;
Ok(exec_time)
}
pub fn flush(&self) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_flush(self.id) })
}
pub fn invalidate_tlb(&self) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_invalidate_tlb(self.id) })
}
pub fn enable_native_msr(&self, msr: u32, enable: bool) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_enable_native_msr(self.id, msr, enable) })
}
pub fn read_msr(&self, msr: u32) -> Result<u64, Error> {
let mut value: u64 = 0;
let _error = match_error_code(unsafe { hv_vcpu_read_msr(self.id, msr, &mut value) })?;
Ok(value)
}
pub fn write_msr(&self, msr: u32, value: u64) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_write_msr(self.id, msr, &(value)) })
}
pub fn read_register(&self, reg: &Register) -> Result<u64, Error> {
let mut value: u64 = 0;
match_error_code(unsafe { hv_vcpu_read_register(self.id, (*reg).clone(), &mut value) })?;
Ok(value)
}
pub fn write_register(&self, reg: &Register, value: u64) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_write_register(self.id, (*reg).clone(), value) })
}
pub fn read_vmcs(&self, field: u32) -> Result<u64, Error> {
let mut value: u64 = 0;
match_error_code(unsafe { hv_vmx_vcpu_read_vmcs(self.get_id(), field, &mut value) })?;
Ok(value)
}
pub fn write_vmcs(&self, field: u32, value: u64) -> Result<(), Error> {
match_error_code(unsafe { hv_vmx_vcpu_write_vmcs(self.id, field, value) })
}
pub fn set_apic_addr(&self, gpa: u64) -> Result<(), Error> {
match_error_code(unsafe { hv_vmx_vcpu_set_apic_address(self.id, gpa) })
}
pub fn read_fpstate(&self, buffer: &mut [u8]) -> Result<(), Error> {
match_error_code(unsafe {
hv_vcpu_read_fpstate(
self.id,
buffer.as_mut_ptr() as *mut c_void,
buffer.len() as size_t,
)
})
}
pub fn write_fpstate(&self, buffer: &[u8]) -> Result<(), Error> {
match_error_code(unsafe {
hv_vcpu_write_fpstate(
self.id,
buffer.as_ptr() as *const c_void,
buffer.len() as size_t,
)
})
}
}
#[allow(non_camel_case_types)]
#[derive(Clone, Debug)]
#[repr(C)]
pub enum VMXCap {
PINBASED = 0,
PROCBASED = 1,
PROCBASED2 = 2,
ENTRY = 3,
EXIT = 4,
PREEMPTION_TIMER = 32,
}
pub fn read_vmx_cap(vmx_cap: &VMXCap) -> Result<u64, Error> {
let mut value: u64 = 0;
match_error_code(unsafe { hv_vmx_read_capability((*vmx_cap).clone(), &mut value) })?;
Ok(value)
}
impl fmt::Display for VMXCap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
VMXCap::PINBASED => write!(f, "Pin-based VMX capabilities"),
VMXCap::PROCBASED => write!(f, "Primary proc-based VMX capabilities"),
VMXCap::PROCBASED2 => write!(f, "Secondary proc-based VMX capabilities"),
VMXCap::ENTRY => write!(f, "VM-entry VMX capabilities"),
VMXCap::EXIT => write!(f, "VM-exit VMX capabilities"),
VMXCap::PREEMPTION_TIMER => write!(f, "VMX preemption timer frequency"),
}
}
}