use core::arch::asm;
use moon_struct::vmx::{vmcs_encoding::VM_INSTRUCTION_ERROR, InvType, VM_INSTRUCTION_ERROR_MAP};
use wdk::println;
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct VmxVmcallResult {
pub rax: u64,
}
impl VmxVmcallResult {
pub const SUCCESS: u64 = 0;
pub const NEED_ALLOCATE_MEMORY: u64 = 1;
pub const UNKNOWN: u64 = 999;
pub fn is_success(&self) -> bool {
self.rax == Self::SUCCESS
}
}
impl From<u64> for VmxVmcallResult {
fn from(value: u64) -> Self {
Self { rax: value }
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum VmxInstructionResult {
VmxSuccess = 0,
VmxFailValid = 1,
VmxFailInvalid = 2,
}
impl From<u64> for VmxInstructionResult {
fn from(value: u64) -> Self {
match value {
0 => VmxInstructionResult::VmxSuccess,
1 => VmxInstructionResult::VmxFailValid,
2 => VmxInstructionResult::VmxFailInvalid,
_ => panic!("Invalid value for VmxInstructionResult"),
}
}
}
pub fn __vmx_on(value: *mut u64) -> VmxInstructionResult {
let mut result: u64;
unsafe {
asm!(
"xor rax,rax",
"vmxon [rcx]",
"setc al",
"setz cl",
"adc al,cl",
inout("rcx") value => _,
out("rax") result,
options(nostack)
);
}
VmxInstructionResult::from(result)
}
pub fn __vmx_off() -> VmxInstructionResult {
let mut result: u64;
unsafe {
asm!(
"xor rax,rax",
"vmxoff",
"setc al",
"setz cl",
"adc al,cl",
out("rax") result,
out("rcx") _,
options(nostack)
);
}
VmxInstructionResult::from(result)
}
pub fn __vmx_vmclear(value: *mut u64) -> VmxInstructionResult {
let mut result: u64;
unsafe {
asm!(
"xor rax,rax",
"vmclear [rcx]",
"setc al",
"setz cl",
"adc al,cl",
inout("rcx") value => _,
out("rax") result,
options(nostack)
);
}
VmxInstructionResult::from(result)
}
pub fn __vmx_vmptrld(value: *mut u64) -> VmxInstructionResult {
let mut result: u64;
unsafe {
asm!(
"xor rax,rax",
"vmptrld [rcx]",
"setc al",
"setz cl",
"adc al,cl",
inout("rcx") value => _,
out("rax") result,
options(nostack)
);
}
VmxInstructionResult::from(result)
}
pub fn __vmx_vmlaunch() -> VmxInstructionResult {
let mut result: u64;
unsafe {
asm!(
"xor rax,rax",
"vmlaunch",
"setc al",
"setz cl",
"adc al,cl",
out("rax") result,
out("rcx") _,
options(nostack)
);
}
VmxInstructionResult::from(result)
}
pub fn __vmx_vmwrite(field: u64, value: u64) -> VmxInstructionResult {
let mut result: u64;
unsafe {
asm!(
"xor rax,rax",
"vmwrite rcx,rdx",
"setc al",
"setz cl",
"adc al,cl",
inout("rcx") field => _,
in("rdx") value,
out("rax") result,
options(nostack)
);
}
if result != 0 {
println!(
"__vmx_vmwrite error {},{}: {}",
field,
value,
__vmx_read_error()
);
}
VmxInstructionResult::from(result)
}
pub fn __vmx_read_error() -> &'static str {
let mut error_code: u64 = 0;
match __vmx_vmread(VM_INSTRUCTION_ERROR, &mut error_code) {
VmxInstructionResult::VmxSuccess => {
println!("Read ins error code success:{}", error_code);
VM_INSTRUCTION_ERROR_MAP[error_code as usize]
}
_ => "error to read vmlaunch error code",
}
}
pub fn __vmx_vmread(field: u64, value: &mut u64) -> VmxInstructionResult {
let mut result: u64;
unsafe {
asm!(
"xor rax,rax",
"vmread [rdx],rcx",
"setc al",
"setz cl",
"adc al,cl",
inout("rcx") field => _,
in("rdx") value,
out("rax") result,
options(nostack)
);
}
VmxInstructionResult::from(result)
}
pub fn vmcs_read(field: u64) -> u64 {
let mut v: u64 = 0;
let r = __vmx_vmread(field, &mut v);
match r {
VmxInstructionResult::VmxSuccess => v,
_ => 0,
}
}
pub fn __vmx_vmcall(vmcall_no: u64, arg1: u64, arg2: u64, arg3: u64) -> VmxVmcallResult {
let mut result: u64;
unsafe {
asm!(
"xor rax,rax",
"vmcall",
in("rcx") vmcall_no,
in("rdx") arg1,
in("r8") arg2,
in("r9") arg3,
out("rax") result,
options(nostack)
);
}
VmxVmcallResult::from(result)
}
pub fn __invept(invept_type: InvType, ept_ctx: u64) -> VmxInstructionResult {
let mut result: u64;
unsafe {
asm!(
"xor rax,rax",
"invept rcx, [rdx]",
"setc al",
"setz cl",
"adc al,cl",
inout("rcx") (invept_type as u64) => _,
in("rdx") ept_ctx,
out("rax") result,
options(nostack)
);
}
VmxInstructionResult::from(result)
}