hypervisor-rs
hypervisor-rs copied to clipboard
Need a simple example
I used this crate, with the code below, and it seems there must be something wrong in using this crate, can you help?
extern crate hypervisor;
use hypervisor::vCPU;
use hypervisor::VMXCap;
use hypervisor::read_vmx_cap;
use hypervisor::consts::vmcs;
use hypervisor::consts::vmx_exit;
use hypervisor::map_mem;
use hypervisor::MemPerm;
use hypervisor::x86Reg;
use hypervisor::Error;
fn cap2ctrl(cap: u64, ctrl: u64) -> u64 {
return ((ctrl) | ((cap) & 0xffffffff)) & ((cap) >> 32);
}
fn req(e: Error) {
match e {
Error::Success => println!("Exited OK"),
_ => println!("Exited Error")
}
}
const VMCS_PRI_PROC_BASED_CTLS_HLT: u64 = (1 << 7);
const VMCS_PRI_PROC_BASED_CTLS_CR8_LOAD: u64 = (1 << 19);
const VMCS_PRI_PROC_BASED_CTLS_CR8_STORE: u64 = (1 << 20);
fn main() {
hypervisor::create_vm();
let cpu = vCPU::new().expect("Failed create vCPU");
let cap_pinbased_type = VMXCap::PINBASED;
let cap_procbased_type = VMXCap::PROCBASED;
let cap_procbased2_type = VMXCap::PROCBASED2;
let cap_entry_type = VMXCap::ENTRY;
let cap_pinbased: u64;
let cap_procbased: u64;
let cap_procbased2: u64;
let cap_entry: u64;
cap_pinbased = read_vmx_cap(&cap_pinbased_type).expect("Reading cap error");
cap_procbased = read_vmx_cap(&cap_procbased_type).expect("Reading cap error");
cap_procbased2 = read_vmx_cap(&cap_procbased2_type).expect("Reading cap error");
cap_entry = read_vmx_cap(&cap_entry_type).expect("Reading cap error");
req(cpu.write_vmcs(vmcs::VMCS_CTRL_PIN_BASED, cap2ctrl(cap_pinbased, 0)));
req(cpu.write_vmcs(vmcs::VMCS_CTRL_CPU_BASED, cap2ctrl(cap_procbased,
VMCS_PRI_PROC_BASED_CTLS_HLT |
VMCS_PRI_PROC_BASED_CTLS_CR8_LOAD |
VMCS_PRI_PROC_BASED_CTLS_CR8_STORE)));
req(cpu.write_vmcs(vmcs::VMCS_CTRL_CPU_BASED2, cap2ctrl(cap_procbased2, 0) | (1 << 7)));
req(cpu.write_vmcs(vmcs::VMCS_CTRL_VMENTRY_CONTROLS, cap2ctrl(cap_entry, 0)));
req(cpu.write_vmcs(vmcs::VMCS_CTRL_EXC_BITMAP, 0xffffffff));
req(cpu.write_vmcs(vmcs::VMCS_CTRL_CR0_MASK, 0xffffffff));
req(cpu.write_vmcs(vmcs::VMCS_CTRL_CR0_SHADOW, 0xffffffff));
req(cpu.write_vmcs(vmcs::VMCS_CTRL_CR4_MASK, 0xffffffff));
req(cpu.write_vmcs(vmcs::VMCS_CTRL_CR4_SHADOW, 0xffffffff));
req(cpu.write_vmcs(vmcs::VMCS_GUEST_CS, 1 << 3));
req(cpu.write_vmcs(vmcs::VMCS_GUEST_CS_AR, 0xc093));
req(cpu.write_vmcs(vmcs::VMCS_GUEST_CS_LIMIT, 0xffffffff));
cpu.write_vmcs(vmcs::VMCS_GUEST_CS_BASE, 0x0);
cpu.write_vmcs(vmcs::VMCS_GUEST_DS, 2 << 3);
cpu.write_vmcs(vmcs::VMCS_GUEST_DS_AR, 0xc093);
cpu.write_vmcs(vmcs::VMCS_GUEST_DS_LIMIT, 0xffffffff);
cpu.write_vmcs(vmcs::VMCS_GUEST_DS_BASE, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_ES, 2 << 3);
cpu.write_vmcs(vmcs::VMCS_GUEST_ES_AR, 0xc093);
cpu.write_vmcs(vmcs::VMCS_GUEST_ES_LIMIT, 0xffffffff);
cpu.write_vmcs(vmcs::VMCS_GUEST_ES_BASE, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_FS, 2 << 3);
cpu.write_vmcs(vmcs::VMCS_GUEST_FS_AR, 0xc093);
cpu.write_vmcs(vmcs::VMCS_GUEST_FS_LIMIT, 0xffffffff);
cpu.write_vmcs(vmcs::VMCS_GUEST_FS_BASE, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_GS, 2 << 3);
cpu.write_vmcs(vmcs::VMCS_GUEST_GS_AR, 0xc093);
cpu.write_vmcs(vmcs::VMCS_GUEST_GS_LIMIT, 0xffffffff);
cpu.write_vmcs(vmcs::VMCS_GUEST_GS_BASE, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_SS, 2 << 3);
cpu.write_vmcs(vmcs::VMCS_GUEST_SS_AR, 0xc093);
cpu.write_vmcs(vmcs::VMCS_GUEST_SS_LIMIT, 0xffffffff);
cpu.write_vmcs(vmcs::VMCS_GUEST_SS_BASE, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_LDTR, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_LDTR_LIMIT, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_LDTR_AR, 0x10000);
cpu.write_vmcs(vmcs::VMCS_GUEST_LDTR_BASE, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_TR, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_TR_LIMIT, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_TR_AR, 0x83);
cpu.write_vmcs(vmcs::VMCS_GUEST_LDTR_BASE, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_GDTR_LIMIT, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_GDTR_BASE, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_IDTR_LIMIT, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_IDTR_BASE, 0);
cpu.write_vmcs(vmcs::VMCS_GUEST_CR0, 0x20);
cpu.write_vmcs(vmcs::VMCS_GUEST_CR3, 0x0);
cpu.write_vmcs(vmcs::VMCS_GUEST_CR4, 0x2000);
// mov ax, 0x1234
// nop
// nop
// hlt
let vm_mem: Vec<u8> = vec![0xB8, 0x34, 0x12, 0x90, 0x90, 0xF4];
// ### I think i am doing wrong here?
match map_mem(&vm_mem as &[u8], 0, &MemPerm::ExecAndWrite) {
Error::Success => println!("map_mem() OK"),
_ => println!("map_mem() error")
}
req(cpu.write_register(&x86Reg::RIP, 0));
req(cpu.write_register(&x86Reg::RFLAGS, 0x2));
req(cpu.write_register(&x86Reg::RAX, 0));
loop {
match cpu.run() {
Error::Success => println!("Cpu running..."),
_ => println!("Running cpu error")
}
let exit_reason = cpu.read_vmcs(vmcs::VMCS_RO_EXIT_REASON).expect("read vmcs error");
println!("Exit reason: {:x}, {}", exit_reason, exit_reason);
if exit_reason == vmx_exit::VMX_REASON_EPT_VIOLATION ||
exit_reason == vmx_exit::VMX_REASON_IRQ {
continue;
}
break;
}
let v = cpu.read_register(&x86Reg::RAX).expect("Read register error");
println!("RAX = {:x}", v);
let ip = cpu.read_register(&x86Reg::RIP).expect("Read register error");
println!("RIP = {:x}", ip);
println!("Done.");
}
RAX
should be 0x90901234
RIP
should be 0x5
The above code is ported from this C program, and this C program works as expected.
And here is the command line to build this program (Let's call it protect_mode.c
):
clang++ -std=c++11 -framework Hypervisor -o protect_mode protect_mode.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Hypervisor/hv.h>
#include <Hypervisor/hv_arch_vmx.h>
#include <Hypervisor/hv_vmx.h>
#define req(x) { \
hv_return_t ret = (x); \
if (ret != HV_SUCCESS) { \
printf("%s exited with code %d\n", #x, (int)ret); \
exit(1); \
} \
}
#define cap2ctrl(cap, ctrl) ((ctrl) | ((cap) & 0xffffffff)) & ((cap) >> 32)
#define VMCS_PRI_PROC_BASED_CTLS_HLT (1 << 7)
#define VMCS_PRI_PROC_BASED_CTLS_CR8_LOAD (1 << 19)
#define VMCS_PRI_PROC_BASED_CTLS_CR8_STORE (1 << 20)
int main() {
req(hv_vm_create(HV_VM_DEFAULT));
hv_vcpuid_t vcpu;
req(hv_vcpu_create(&vcpu, HV_VCPU_DEFAULT));
uint64_t vmx_cap_pinbased, vmx_cap_procbased, vmx_cap_procbased2, vmx_cap_entry;
req(hv_vmx_read_capability(HV_VMX_CAP_PINBASED, &vmx_cap_pinbased));
req(hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &vmx_cap_procbased));
req(hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &vmx_cap_procbased2));
req(hv_vmx_read_capability(HV_VMX_CAP_ENTRY, &vmx_cap_entry));
printf("pinbased: %llu procbased: %llu procbased2: %llu, entry: %llu\n", vmx_cap_pinbased,
vmx_cap_procbased, vmx_cap_procbased2, vmx_cap_entry);
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_PIN_BASED, cap2ctrl(vmx_cap_pinbased, 0)));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CPU_BASED, cap2ctrl(
vmx_cap_procbased,
VMCS_PRI_PROC_BASED_CTLS_HLT |
VMCS_PRI_PROC_BASED_CTLS_CR8_LOAD |
VMCS_PRI_PROC_BASED_CTLS_CR8_STORE)));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, cap2ctrl(vmx_cap_procbased2, 0) | (1 << 7)));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_VMENTRY_CONTROLS, cap2ctrl(vmx_cap_entry, 0)));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_EXC_BITMAP, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CR0_MASK, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CR4_MASK, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS, 1 << 3));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS_AR, 0xc093));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS_LIMIT, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS_BASE, 0x0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS, 2 << 3));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS_AR, 0xc093));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS_LIMIT, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS_BASE, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES, 2 << 3));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES_AR, 0xc093));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES_LIMIT, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES_BASE, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS, 2 << 3));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS_AR, 0xc093));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS_LIMIT, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS_BASE, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS, 2 << 3));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS_AR, 0xc093));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS_LIMIT, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS_BASE, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS, 2 << 3));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS_AR, 0xc093));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS_LIMIT, 0xffffffff));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS_BASE, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR_LIMIT, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR_AR, 0x10000));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR_BASE, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR_LIMIT, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR_AR, 0x83));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR_BASE, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_IDTR_LIMIT, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_IDTR_BASE, 0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CR0, 0x20));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CR3, 0x0));
req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CR4, 0x2000));
// Online assembly: https://defuse.ca/online-x86-assembler.htm#disassembly
// loads 0x1234 to ax if in 16-bit mode
// loads 0x90901234 to eax if in 32-bit mode
// mov ax, 0x1234
// nop
// nop
// hlt
unsigned char code[] = { 0xB8, 0x34, 0x12, 0x90, 0x90, 0xF4};
//void *vm_mem = valloc(1 << 30);
void *vm_mem = valloc(6);
memcpy(vm_mem, code, sizeof code);
req(hv_vm_map(vm_mem, 0, 6, HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC));
req(hv_vcpu_write_register(vcpu, HV_X86_RIP, 0));
req(hv_vcpu_write_register(vcpu, HV_X86_RFLAGS, 0x2));
req(hv_vcpu_write_register(vcpu, HV_X86_RAX, 0));
for (;;) {
req(hv_vcpu_run(vcpu));
uint64_t rip;
req(hv_vcpu_read_register(vcpu, HV_X86_RIP, &rip));
printf("rip = 0x%llx\n", rip);
uint64_t exit_reason;
req(hv_vmx_vcpu_read_vmcs(vcpu, VMCS_RO_EXIT_REASON, &exit_reason));
printf("exit reason: %llu\n", exit_reason);
if (exit_reason == VMX_REASON_EPT_VIOLATION || exit_reason == VMX_REASON_IRQ)
continue;
break;
}
uint64_t x;
req(hv_vcpu_read_register(vcpu, HV_X86_RAX, &x));
printf("rax = 0x%llx\n", x);
uint64_t rip;
req(hv_vcpu_read_register(vcpu, HV_X86_RIP, &rip));
printf("rip = 0x%llx\n", rip);
printf("protect mode\n");
return 0;
}
Hello, I create a fork and add a small example. Does it help?
@saurvs Do you want to integrate the example in your repository? If yes, I will create a pull requesst.