use core::arch::asm;
use thiserror_no_std::Error;
use crate::x86::rfalgs::{self, RFlags};
#[derive(Error,Debug, PartialEq)]
pub enum VmFail {
VmFailValid,
VmFailInvalid,
}
pub type Result<T> = core::result::Result<T, VmFail>;
#[inline(always)]
pub fn vmx_capture_status() -> Result<()> {
let flags = rfalgs::read();
if flags.contains(RFlags::FLAGS_ZF) {
Err(VmFail::VmFailValid)
} else if flags.contains(RFlags::FLAGS_CF) {
Err(VmFail::VmFailInvalid)
} else {
Ok(())
}
}
pub fn vmxon(addr: u64) -> Result<()> {
unsafe {
asm!("vmxon ({0})", in(reg) &addr, options(att_syntax));
vmx_capture_status()
}
}
pub fn vmxoff() -> Result<()> {
unsafe { asm!("vmxoff");
vmx_capture_status()
}
}
pub fn vmclear(addr: u64) -> Result<()> {
unsafe {
asm!("vmclear ({0})", in(reg) &addr, options(att_syntax));
vmx_capture_status()
}
}
pub fn vmptrld(addr: u64) -> Result<()> {
unsafe { asm!("vmptrld ({0})", in(reg) &addr, options(att_syntax));
vmx_capture_status()
}
}
pub fn vmptrst() -> Result<u64> {
let value: u64 = 0;
unsafe { asm!("vmptrst ({0})", in(reg) &value, options(att_syntax)) };
vmx_capture_status().and(Ok(value))
}
pub fn vmread(field: u32) -> Result<u64> {
let field: u64 = field.into();
let value: u64;
unsafe { asm!("vmread {0}, {1}", in(reg) field, out(reg) value, options(att_syntax)) };
vmx_capture_status().and(Ok(value))
}
pub fn vmwrite(field: u32, value: u64) -> Result<()> {
let field: u64 = field.into();
unsafe { asm!("vmwrite {1}, {0}", in(reg) field, in(reg) value, options(att_syntax))};
vmx_capture_status()
}
#[inline(always)]
pub fn vmlaunch() -> Result<()> {
unsafe { asm!("vmlaunch") };
vmx_capture_status()
}
#[inline(always)]
pub fn vmresume() -> Result<()> {
unsafe { asm!("vmresume")};
vmx_capture_status()
}