extern crate core;
extern crate libc;
pub mod consts;
#[allow(non_camel_case_types)]
pub mod ffi;
use self::core::fmt;
use libc::*;
use self::ffi::*;
#[derive(Clone)]
pub enum Error {
Success,
Error,
Busy,
BadArg,
NoRes,
NoDev,
Unsupp,
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Success => write!(f, "Success"),
Error::Error => write!(f, "Error"),
Error::Busy => write!(f, "Busy"),
Error::BadArg => write!(f, "Bad argument"),
Error::NoRes => write!(f, "No resources"),
Error::NoDev => write!(f, "No device"),
Error::Unsupp => write!(f, "Unsupported"),
}
}
}
fn match_error_code(code: hv_return_t) -> Result<(), Error> {
match code {
HV_SUCCESS => Ok(()),
HV_BUSY => Err(Error::Busy),
HV_BAD_ARGUMENT => Err(Error::BadArg),
HV_NO_RESOURCES => Err(Error::NoRes),
HV_NO_DEVICE => Err(Error::NoDev),
HV_UNSUPPORTED => Err(Error::Unsupp),
_ => Err(Error::Error),
}
}
pub fn create_vm() -> Result<(), Error> {
match_error_code(unsafe { hv_vm_create(HV_VM_DEFAULT) })
}
pub fn destroy_vm() -> Result<(), Error> {
match_error_code(unsafe { hv_vm_destroy() })
}
pub enum MemPerm {
Read,
Write,
Exec,
ExecAndWrite,
ExecAndRead,
}
#[allow(non_snake_case)]
#[inline(always)]
fn match_MemPerm(mem_perm: &MemPerm) -> u64 {
match mem_perm {
&MemPerm::Read => HV_MEMORY_READ,
&MemPerm::Write => HV_MEMORY_WRITE | HV_MEMORY_READ,
&MemPerm::Exec => HV_MEMORY_EXEC,
&MemPerm::ExecAndWrite => HV_MEMORY_EXEC | HV_MEMORY_WRITE | HV_MEMORY_READ,
&MemPerm::ExecAndRead => HV_MEMORY_EXEC | HV_MEMORY_READ,
}
}
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 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 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 sync_tsc(tsc: u64) -> Result<(), Error> {
match_error_code(unsafe { hv_vm_sync_tsc(tsc as u64) })
}
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) })
}
#[allow(non_camel_case_types)]
pub struct vCPU {
pub id: u32,
}
#[allow(non_camel_case_types)]
#[derive(Clone)]
#[repr(C)]
pub enum x86Reg {
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 vCPU {
pub fn new() -> Result<vCPU, Error> {
let mut vcpuid: hv_vcpuid_t = 0;
match_error_code(unsafe { hv_vcpu_create(&mut vcpuid, HV_VCPU_DEFAULT) })?;
Ok(vCPU { id: vcpuid as u32 })
}
pub fn destroy(&self) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_destroy(self.id as hv_vcpuid_t) })
}
pub fn run(&self) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_run(self.id as hv_vcpuid_t) })
}
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 as u64)
}
pub fn flush(&self) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_flush(self.id as hv_vcpuid_t) })
}
pub fn invalidate_tlb(&self) -> Result<(), Error> {
match_error_code(unsafe { hv_vcpu_invalidate_tlb(self.id as hv_vcpuid_t) })
}
pub fn enable_native_msr(&self, msr: u32, enable: bool) -> Result<(), Error> {
match_error_code(unsafe {
hv_vcpu_enable_native_msr(self.id as hv_vcpuid_t, msr as u32, 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 as hv_vcpuid_t, msr as u32, &mut value)
})?;
Ok(value as u64)
}
pub fn write_msr(&self, msr: u32, value: u64) -> Result<(), Error> {
match_error_code(unsafe {
hv_vcpu_write_msr(self.id as hv_vcpuid_t, msr as u32, &(value as u64))
})
}
pub fn read_register(&self, reg: &x86Reg) -> Result<u64, Error> {
let mut value: u64 = 0;
match_error_code(unsafe {
hv_vcpu_read_register(self.id as hv_vcpuid_t, (*reg).clone(), &mut value)
})?;
Ok(value as u64)
}
pub fn write_register(&self, reg: &x86Reg, value: u64) -> Result<(), Error> {
match_error_code(unsafe {
hv_vcpu_write_register(self.id as hv_vcpuid_t, (*reg).clone(), value as u64)
})
}
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.id as hv_vcpuid_t, field as u32, &mut value)
})?;
Ok(value as u64)
}
pub fn write_vmcs(&self, field: u32, value: u64) -> Result<(), Error> {
match_error_code(unsafe {
hv_vmx_vcpu_write_vmcs(self.id as hv_vcpuid_t, field as u32, value as u64)
})
}
pub fn set_apic_addr(&self, gpa: u64) -> Result<(), Error> {
match_error_code(unsafe {
hv_vmx_vcpu_set_apic_address(self.id as hv_vcpuid_t, gpa as u64)
})
}
pub fn read_fpstate(&self, buffer: &mut [u8]) -> Result<(), Error> {
match_error_code(unsafe {
hv_vcpu_read_fpstate(
self.id as hv_vcpuid_t,
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 as hv_vcpuid_t,
buffer.as_ptr() as *const c_void,
buffer.len() as size_t,
)
})
}
}
impl fmt::Debug for vCPU {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "vCPU ID: {}", (*self).id)
}
}
#[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 as u64)
}
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"),
}
}
}