moon-instructions 0.1.1

Windows Kernel Instructions
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"),
        }
    }
}

// success on rflags.cf = 0
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)
}