Abstracted away hypervisor interface.

This commit is contained in:
Cody Brocious 2016-05-17 12:37:00 -06:00
parent 2872766a5b
commit a9cc9c018d
10 changed files with 402 additions and 446 deletions

469
Cpu.cpp
View file

@ -24,31 +24,10 @@ Cpu::Cpu(uint8_t *ram, uint8_t *kram) {
mem = ram;
kmem = kram;
bailout(hv_vm_create(HV_VM_DEFAULT));
hv = new HVImpl();
memset(mem, 0, RAM_SIZE);
bailout(hv_vm_map(mem, 0, RAM_SIZE, HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC));
bailout(hv_vm_map(kmem, 0xc0000000, KRAM_SIZE, HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC));
bailout(hv_vcpu_create(&vcpu, HV_VCPU_DEFAULT));
uint64_t vmx_cap_pinbased, vmx_cap_procbased, vmx_cap_procbased2, vmx_cap_entry;
bailout(hv_vmx_read_capability(HV_VMX_CAP_PINBASED, &vmx_cap_pinbased));
bailout(hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &vmx_cap_procbased));
bailout(hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &vmx_cap_procbased2));
bailout(hv_vmx_read_capability(HV_VMX_CAP_ENTRY, &vmx_cap_entry));
wvmcs(VMCS_CTRL_PIN_BASED, cap2ctrl(vmx_cap_pinbased, 0));
wvmcs(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));
wvmcs(VMCS_CTRL_CPU_BASED2, cap2ctrl(vmx_cap_procbased2, 0));
wvmcs(VMCS_CTRL_VMENTRY_CONTROLS, cap2ctrl(vmx_cap_entry, 0));
wvmcs(VMCS_CTRL_EXC_BITMAP, 0xffffffff);
wvmcs(VMCS_CTRL_CR0_MASK, 0xffffffff);
wvmcs(VMCS_CTRL_CR0_SHADOW, 0xffffffff);
wvmcs(VMCS_CTRL_CR4_MASK, 0xffffffff);
wvmcs(VMCS_CTRL_CR4_SHADOW, 0xffffffff);
hv->map_phys(mem, 0x00000000, RAM_SIZE);
hv->map_phys(kmem, 0xc0000000, KRAM_SIZE);
auto directory = 64*1024*1024; // Page directory base
auto dir = (uint32_t *) (mem + directory);
@ -59,59 +38,19 @@ Cpu::Cpu(uint8_t *ram, uint8_t *kram) {
table[j] = 0x0;
}
}
wvmcs(VMCS_GUEST_CR3, directory);
wvmcs(VMCS_GUEST_CR0, 0x80000000 | 0x20 | 0x01); // Paging | NE | PE
hv->reg(CR3, directory);
hv->reg(CR0, 0x80000000 | 0x20 | 0x01); // Paging | NE | PE
auto gdt = ram + 96*1024*1024;
memset(gdt, 0, 0x10000);
gdt_encode(gdt, 0, 0, 0, 0); // Null entry
gdt_encode(gdt, 1, 0, 0xffffffff, 0x9A); // Code
gdt_encode(gdt, 2, 0, 0xffffffff, 0x92); // Data
wvmcs(VMCS_GUEST_GDTR_LIMIT, 0xFFFF);
wvmcs(VMCS_GUEST_GDTR_BASE, 96*1024*1024);
hv->reg(GDT_LIMIT, 0xFFFF);
hv->reg(GDT_BASE, 96*1024*1024);
map_pages(96 * 1024 * 1024, 96 * 1024 * 1024, 16);
wvmcs(VMCS_GUEST_CS, 1 << 3);
wvmcs(VMCS_GUEST_CS_AR, 0xc093);
wvmcs(VMCS_GUEST_CS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_CS_BASE, 0x0);
wvmcs(VMCS_GUEST_DS, 2 << 3);
wvmcs(VMCS_GUEST_DS_AR, 0xc093);
wvmcs(VMCS_GUEST_DS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_DS_BASE, 0);
wvmcs(VMCS_GUEST_ES, 2 << 3);
wvmcs(VMCS_GUEST_ES_AR, 0xc093);
wvmcs(VMCS_GUEST_ES_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_ES_BASE, 0);
wvmcs(VMCS_GUEST_FS, 2 << 3);
wvmcs(VMCS_GUEST_FS_AR, 0xc093);
wvmcs(VMCS_GUEST_FS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_FS_BASE, 0);
wvmcs(VMCS_GUEST_GS, 2 << 3);
wvmcs(VMCS_GUEST_GS_AR, 0xc093);
wvmcs(VMCS_GUEST_GS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_GS_BASE, 0);
wvmcs(VMCS_GUEST_SS, 2 << 3);
wvmcs(VMCS_GUEST_SS_AR, 0xc093);
wvmcs(VMCS_GUEST_SS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_SS_BASE, 0);
wvmcs(VMCS_GUEST_LDTR, 0);
wvmcs(VMCS_GUEST_LDTR_LIMIT, 0);
wvmcs(VMCS_GUEST_LDTR_AR, 0x10000);
wvmcs(VMCS_GUEST_LDTR_BASE, 0);
wvmcs(VMCS_GUEST_TR, 0);
wvmcs(VMCS_GUEST_TR_LIMIT, 0);
wvmcs(VMCS_GUEST_TR_AR, 0x83);
wvmcs(VMCS_GUEST_TR_BASE, 0);
wvmcs(VMCS_GUEST_CR4, 0x2000);
hv->reg(CR4, 0x2000);
}
void Cpu::map_pages(uint32_t virt, uint32_t phys, uint32_t count) {
@ -122,15 +61,11 @@ void Cpu::map_pages(uint32_t virt, uint32_t phys, uint32_t count) {
virt += 4096;
phys += 4096;
}
invalidate_tlb();
}
void Cpu::invalidate_tlb() {
hv_vcpu_invalidate_tlb(vcpu);
hv->invalidate_tlb(); // Do we really need to do this all the time?
}
uint32_t Cpu::virt2phys(uint32_t addr) {
auto cr3 = rreg(HV_X86_CR3);
auto cr3 = hv->reg(CR3);
if(cr3 == 0)
return addr;
@ -140,7 +75,7 @@ uint32_t Cpu::virt2phys(uint32_t addr) {
}
bool Cpu::is_mapped(uint32_t addr) {
auto cr3 = rreg(HV_X86_CR3);
auto cr3 = hv->reg(CR3);
if(cr3 == 0)
return true;
@ -150,7 +85,7 @@ bool Cpu::is_mapped(uint32_t addr) {
}
void Cpu::read_memory(uint32_t addr, uint32_t size, void *buffer) {
auto cr3 = rreg(HV_X86_CR3);
auto cr3 = hv->reg(CR3);
if(cr3 == 0) {
if(addr >= 0xc0000000)
memcpy(buffer, &kmem[addr - 0xc0000000], size);
@ -172,7 +107,7 @@ void Cpu::read_memory(uint32_t addr, uint32_t size, void *buffer) {
}
void Cpu::write_memory(uint32_t addr, uint32_t size, void *buffer) {
auto cr3 = rreg(HV_X86_CR3);
auto cr3 = hv->reg(CR3);
if(cr3 == 0) {
if(addr >= 0xc0000000)
memcpy(&kmem[addr - 0xc0000000], buffer, size);
@ -193,26 +128,8 @@ void Cpu::write_memory(uint32_t addr, uint32_t size, void *buffer) {
}
}
uint64_t Cpu::rdmsr(uint32_t msr) {
switch(msr) {
default:
cout << "Unknown MSR being read: " << hex << msr << endl;
return 0;
}
}
void Cpu::wrmsr(uint32_t msr, uint64_t val) {
switch(msr) {
default:
cout << "Unknown MSR being written: " << hex << msr << " == 0x" << hex << val << endl;
break;
}
}
Cpu::~Cpu() {
bailout(hv_vcpu_destroy(vcpu));
bailout(hv_vm_unmap(0, RAM_SIZE));
bailout(hv_vm_destroy());
delete hv;
}
#define TASK_TIMER 20 // Milliseconds
@ -224,202 +141,9 @@ uint64_t systime() {
return (time.tv_sec * 1000) + (time.tv_usec / 1000);
}
void log_exit_reason(uint32_t reason, uint32_t eip) {
if(reason & 0x80000000) {
reason &= 0x7FFFFFFF;
cout << "Entry failed: ";
} else
cout << "Exit ";
switch(reason) {
case VMX_REASON_EXC_NMI:
cout << "VMX_REASON_EXC_NMI";
break;
case VMX_REASON_IRQ:
cout << "VMX_REASON_IRQ";
break;
case VMX_REASON_TRIPLE_FAULT:
cout << "VMX_REASON_TRIPLE_FAULT";
break;
case VMX_REASON_INIT:
cout << "VMX_REASON_INIT";
break;
case VMX_REASON_SIPI:
cout << "VMX_REASON_SIPI";
break;
case VMX_REASON_IO_SMI:
cout << "VMX_REASON_IO_SMI";
break;
case VMX_REASON_OTHER_SMI:
cout << "VMX_REASON_OTHER_SMI";
break;
case VMX_REASON_IRQ_WND:
cout << "VMX_REASON_IRQ_WND";
break;
case VMX_REASON_VIRTUAL_NMI_WND:
cout << "VMX_REASON_VIRTUAL_NMI_WND";
break;
case VMX_REASON_TASK:
cout << "VMX_REASON_TASK";
break;
case VMX_REASON_CPUID:
cout << "VMX_REASON_CPUID";
break;
case VMX_REASON_GETSEC:
cout << "VMX_REASON_GETSEC";
break;
case VMX_REASON_HLT:
cout << "VMX_REASON_HLT";
break;
case VMX_REASON_INVD:
cout << "VMX_REASON_INVD";
break;
case VMX_REASON_INVLPG:
cout << "VMX_REASON_INVLPG";
break;
case VMX_REASON_RDPMC:
cout << "VMX_REASON_RDPMC";
break;
case VMX_REASON_RDTSC:
cout << "VMX_REASON_RDTSC";
break;
case VMX_REASON_RSM:
cout << "VMX_REASON_RSM";
break;
case VMX_REASON_VMCALL:
cout << "VMX_REASON_VMCALL";
break;
case VMX_REASON_VMCLEAR:
cout << "VMX_REASON_VMCLEAR";
break;
case VMX_REASON_VMLAUNCH:
cout << "VMX_REASON_VMLAUNCH";
break;
case VMX_REASON_VMPTRLD:
cout << "VMX_REASON_VMPTRLD";
break;
case VMX_REASON_VMPTRST:
cout << "VMX_REASON_VMPTRST";
break;
case VMX_REASON_VMREAD:
cout << "VMX_REASON_VMREAD";
break;
case VMX_REASON_VMRESUME:
cout << "VMX_REASON_VMRESUME";
break;
case VMX_REASON_VMWRITE:
cout << "VMX_REASON_VMWRITE";
break;
case VMX_REASON_VMOFF:
cout << "VMX_REASON_VMOFF";
break;
case VMX_REASON_VMON:
cout << "VMX_REASON_VMON";
break;
case VMX_REASON_MOV_CR:
cout << "VMX_REASON_MOV_CR";
break;
case VMX_REASON_MOV_DR:
cout << "VMX_REASON_MOV_DR";
break;
case VMX_REASON_IO:
cout << "VMX_REASON_IO";
break;
case VMX_REASON_RDMSR:
cout << "VMX_REASON_RDMSR";
break;
case VMX_REASON_WRMSR:
cout << "VMX_REASON_WRMSR";
break;
case VMX_REASON_VMENTRY_GUEST:
cout << "VMX_REASON_VMENTRY_GUEST";
break;
case VMX_REASON_VMENTRY_MSR:
cout << "VMX_REASON_VMENTRY_MSR";
break;
case VMX_REASON_MWAIT:
cout << "VMX_REASON_MWAIT";
break;
case VMX_REASON_MTF:
cout << "VMX_REASON_MTF";
break;
case VMX_REASON_MONITOR:
cout << "VMX_REASON_MONITOR";
break;
case VMX_REASON_PAUSE:
cout << "VMX_REASON_PAUSE";
break;
case VMX_REASON_VMENTRY_MC:
cout << "VMX_REASON_VMENTRY_MC";
break;
case VMX_REASON_TPR_THRESHOLD:
cout << "VMX_REASON_TPR_THRESHOLD";
break;
case VMX_REASON_APIC_ACCESS:
cout << "VMX_REASON_APIC_ACCESS";
break;
case VMX_REASON_VIRTUALIZED_EOI:
cout << "VMX_REASON_VIRTUALIZED_EOI";
break;
case VMX_REASON_GDTR_IDTR:
cout << "VMX_REASON_GDTR_IDTR";
break;
case VMX_REASON_LDTR_TR:
cout << "VMX_REASON_LDTR_TR";
break;
case VMX_REASON_EPT_VIOLATION:
cout << "VMX_REASON_EPT_VIOLATION";
break;
case VMX_REASON_EPT_MISCONFIG:
cout << "VMX_REASON_EPT_MISCONFIG";
break;
case VMX_REASON_EPT_INVEPT:
cout << "VMX_REASON_EPT_INVEPT";
break;
case VMX_REASON_RDTSCP:
cout << "VMX_REASON_RDTSCP";
break;
case VMX_REASON_VMX_TIMER_EXPIRED:
cout << "VMX_REASON_VMX_TIMER_EXPIRED";
break;
case VMX_REASON_INVVPID:
cout << "VMX_REASON_INVVPID";
break;
case VMX_REASON_WBINVD:
cout << "VMX_REASON_WBINVD";
break;
case VMX_REASON_XSETBV:
cout << "VMX_REASON_XSETBV";
break;
case VMX_REASON_APIC_WRITE:
cout << "VMX_REASON_APIC_WRITE";
break;
case VMX_REASON_RDRAND:
cout << "VMX_REASON_RDRAND";
break;
case VMX_REASON_INVPCID:
cout << "VMX_REASON_INVPCID";
break;
case VMX_REASON_VMFUNC:
cout << "VMX_REASON_VMFUNC";
break;
case VMX_REASON_RDSEED:
cout << "VMX_REASON_RDSEED";
break;
case VMX_REASON_XSAVES:
cout << "VMX_REASON_XSAVES";
break;
case VMX_REASON_XRSTORS:
cout << "VMX_REASON_XRSTORS";
break;
default:
cout << "Unknown reason: " << dec << reason;
}
cout << " @ " << hex << eip << endl;
}
void Cpu::run(uint32_t eip) {
wreg(HV_X86_RIP, eip);
wreg(HV_X86_RFLAGS, 0x2);
hv->reg(EIP, eip);
hv->reg(EFLAGS, 0x2);
box->debugger->enter(0);
@ -427,113 +151,74 @@ void Cpu::run(uint32_t eip) {
auto swap = true;
do {
bailout(hv_vcpu_run(vcpu));
auto exit = hv->enter();
auto exit_reason = rvmcs(VMCS_RO_EXIT_REASON);
if(exit_reason & 0x80000000) {
cout << "Entry failed? " << dec << (exit_reason & 0x7FFFFFFF) << endl;
stop = true;
} else
switch (exit_reason) {
case VMX_REASON_EXC_NMI: {
auto vec_val = rvmcs(VMCS_RO_VMEXIT_IRQ_INFO) & 0xFFFF;
switch((vec_val >> 8) & 7) {
case 6: { // Interrupt
if((vec_val & 0xFF) == 3) {
box->debugger->enter();
} else {
cout << "Unknown interrupt. " << dec << (vec_val & 0xFF) << endl;
box->debugger->enter();
exit(0);
}
break;
}
case 3: { // Exception
switch(vec_val & 0xFF) {
case 1: { // Single step
auto flags = rreg(HV_X86_RFLAGS);
wreg(HV_X86_RFLAGS, flags & ~(1 << 8));
if(single_step == 2) { // Requested
single_step = 0;
box->debugger->enter();
}
else
box->debugger->reenable();
swap = true;
break;
}
case 6: {
cout << "Invalid opcode" << endl;
box->debugger->enter();
break;
}
case 14: {
cout << format("Page fault reading %08x") % rvmcs(VMCS_RO_EXIT_QUALIFIC) << endl;
box->debugger->enter();
break;
}
default:
cout << "Unknown exception. " << dec << (vec_val & 0xFF) << endl;
box->debugger->enter();
exit(0);
}
break;
}
default:
cout << "Unknown NMI class. " << hex << vec_val << endl;
}
break;
}
case VMX_REASON_VMCALL: {
wreg(HV_X86_RIP, rreg(HV_X86_RIP) + 3);
hypercall_dispatch(rreg(HV_X86_RAX), rreg(HV_X86_RDX));
break;
}
case VMX_REASON_IRQ:
break;
case VMX_REASON_TRIPLE_FAULT:
cout << "Triple fault!" << endl;
cout << "IDTR Base " << hex << rreg(HV_X86_IDT_BASE) << " " << hex << rvmcs(VMCS_GUEST_IDTR_BASE) << endl;
cout << "IDTR Limit " << hex << rreg(HV_X86_IDT_LIMIT) << endl;
cout << "ISR 0 == " << hex << read_memory<uint64_t>(rvmcs(VMCS_GUEST_IDTR_BASE)) << endl;
cout << "ISR 7 == " << hex << read_memory<uint64_t>(rvmcs(VMCS_GUEST_IDTR_BASE) + 8 * 7) << endl;
stop = 1;
break;
case VMX_REASON_RDMSR: {
auto msr = 0L;
cout << "RDMSR " << hex << rreg(HV_X86_RCX);
msr = rdmsr(rreg(HV_X86_RCX));
cout << " == 0x" << hex << msr << endl;
wreg(HV_X86_RIP, rreg(HV_X86_RIP) + 2);
wreg(HV_X86_RAX, msr & 0xFFFFFFFF);
wreg(HV_X86_RDX, msr >> 32);
break;
}
case VMX_REASON_WRMSR: {
auto msr = ((uint64_t) rreg(HV_X86_RDX) << 32) | (uint64_t) rreg(HV_X86_RAX);
cout << "WRMSR " << hex << rreg(HV_X86_RCX) << " == 0x" << hex << msr << endl;
wrmsr(rreg(HV_X86_RCX), msr);
wreg(HV_X86_RIP, rreg(HV_X86_RIP) + 2);
break;
}
case VMX_REASON_HLT:
cout << "HLT" << endl;
stop = true;
break;
case VMX_REASON_EPT_VIOLATION:
// cout << "EPT_VIOLATION" << endl;
break;
default:
cout << "Unhandled VM exit: " << dec << exit_reason << endl;
switch (exit.reason) {
case Interrupt: {
if(exit.interrupt_no == 3) {
box->debugger->enter();
} else {
cout << "Unknown interrupt. " << dec << exit.interrupt_no << endl;
box->debugger->enter();
stop = true;
}
break;
}
case Exception: {
switch(exit.interrupt_no) {
case 1: { // Single step
auto flags = hv->reg(EFLAGS);
hv->reg(EFLAGS, flags & ~(1 << 8));
if(single_step == 2) { // Requested
single_step = 0;
box->debugger->enter();
}
else
box->debugger->reenable();
swap = true;
break;
}
case 6: {
cout << "Invalid opcode" << endl;
stop = true;
break;
}
case 14: {
cout << format("Page fault reading %08x") % exit.address << endl;
stop = true;
break;
}
default:
cout << "Unknown exception. " << dec << exit.interrupt_no << endl;
stop = true;
}
break;
}
case VmCall: {
hv->reg(EIP, hv->reg(EIP) + 3);
hypercall_dispatch(hv->reg(EAX), hv->reg(EDX));
break;
}
case TripleFault:
cout << "Triple fault!" << endl;
stop = true;
break;
case Hlt:
cout << "HLT" << endl;
stop = true;
break;
case Ignore:
break;
default:
stop = true;
}
if(single_step) {
if(single_step == 1)
single_step = 0;
auto flags = rreg(HV_X86_RFLAGS);
wreg(HV_X86_RFLAGS, flags | (1 << 8));
auto flags = hv->reg(EFLAGS);
hv->reg(EFLAGS, flags | (1 << 8));
swap = false;
}

33
Cpu.hpp
View file

@ -2,11 +2,6 @@
#include "Zookeeper.hpp"
#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)
class Cpu {
public:
Cpu(uint8_t *ram, uint8_t *kram);
@ -28,33 +23,11 @@ public:
write_memory(addr, sizeof(T), &value);
}
void invalidate_tlb();
uint64_t rdmsr(uint32_t msr);
void wrmsr(uint32_t msr, uint64_t val);
/* read GPR */
uint32_t rreg(hv_x86_reg_t reg) {
uint64_t v;
bailout(hv_vcpu_read_register(vcpu, reg, &v));
return (uint32_t) v;
}
/* write GPR */
void wreg(hv_x86_reg_t reg, uint32_t v) {
bailout(hv_vcpu_write_register(vcpu, reg, (uint32_t) v));
}
/* read VMCS field */
uint64_t rvmcs(uint32_t field) {
uint64_t v;
bailout(hv_vmx_vcpu_read_vmcs(vcpu, field, &v));
return v;
}
/* write VMCS field */
void wvmcs(uint32_t field, uint64_t v) {
bailout(hv_vmx_vcpu_write_vmcs(vcpu, field, v));
void invalidate_tlb() {
hv->invalidate_tlb();
}
hv_vcpuid_t vcpu;
HV *hv;
uint8_t *mem, *kmem;
int single_step = 0;
bool stop = false;

View file

@ -28,7 +28,7 @@ Debugger::Debugger() {
void Debugger::stack_trace() {
cout << "Stack trace:" << endl;
auto ebp = box->cpu->rreg(HV_X86_RBP);
auto ebp = box->cpu->hv->reg(EBP);
for(auto i = 0; i < MAX_FRAMES; ++i) {
if(ebp == 0)
break;
@ -42,13 +42,13 @@ void Debugger::stack_trace() {
#define MAX_LENGTH 20
void Debugger::dump_stack() {
auto esp = box->cpu->rreg(HV_X86_RSP);
auto esp = box->cpu->hv->reg(ESP);
for(auto i = 0; i < MAX_LENGTH; ++i)
cout << format("%08x") % box->cpu->read_memory<uint32_t>(esp + i * 4) << endl;
}
void Debugger::enter(uint32_t reason) {
auto eip = box->cpu->rreg(HV_X86_RIP);
auto eip = box->cpu->hv->reg(EIP);
if(breakpoints.find(eip) != breakpoints.end()) {
cout << format("Hit breakpoint at 0x%08x") % eip << endl;
@ -91,11 +91,11 @@ void Debugger::enter(uint32_t reason) {
} else if(cmd == "stack") {
dump_stack();
} else if(cmd == "r" || cmd == "regs") {
cout << format("eax %08x ebx %08x") % box->cpu->rreg(HV_X86_RAX) % box->cpu->rreg(HV_X86_RBX) << endl;
cout << format("ecx %08x edx %08x") % box->cpu->rreg(HV_X86_RCX) % box->cpu->rreg(HV_X86_RDX) << endl;
cout << format("edi %08x esi %08x") % box->cpu->rreg(HV_X86_RDI) % box->cpu->rreg(HV_X86_RSI) << endl;
cout << format("ebp %08x esp %08x") % box->cpu->rreg(HV_X86_RBP) % box->cpu->rreg(HV_X86_RSP) << endl;
cout << format("eflags %08x") % box->cpu->rreg(HV_X86_RFLAGS) << endl;
cout << format("eax %08x ebx %08x") % box->cpu->hv->reg(EAX) % box->cpu->hv->reg(EBX) << endl;
cout << format("ecx %08x edx %08x") % box->cpu->hv->reg(ECX) % box->cpu->hv->reg(EDX) << endl;
cout << format("edi %08x esi %08x") % box->cpu->hv->reg(EDI) % box->cpu->hv->reg(ESI) << endl;
cout << format("ebp %08x esp %08x") % box->cpu->hv->reg(EBP) % box->cpu->hv->reg(ESP) << endl;
cout << format("eflags %08x") % box->cpu->hv->reg(EFLAGS) << endl;
} else if(cmd == "rm" || cmd == "read") {
string type = "u32";
auto offset = 1;

45
HV.hpp Normal file
View file

@ -0,0 +1,45 @@
#pragma once
#include "Zookeeper.hpp"
enum HVReg {
EIP,
EFLAGS,
EAX, ECX, EDX, EBX,
ESI, EDI, ESP, EBP,
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
};
enum HVExitReason {
Ignore,
Unknown,
EntryFailed,
Interrupt,
Exception,
VmCall,
TripleFault,
Hlt
};
typedef struct exit {
HVExitReason reason;
uint32_t instruction_length;
uint32_t interrupt_no;
uint32_t address; // Used for page faults
} exit_t;
class HV {
public:
virtual ~HV() = 0;
virtual void map_phys(void *memory, uint32_t base, uint32_t size) = 0;
virtual void invalidate_tlb() = 0;
virtual uint32_t reg(HVReg reg) = 0;
virtual void reg(HVReg reg, uint32_t val) = 0;
virtual exit_t enter() = 0;
};

203
Mac/HVMac.cpp Normal file
View file

@ -0,0 +1,203 @@
#include "Zookeeper.hpp"
HV::~HV() {} // This has to be defined, but there's no use in making a new cpp file.
#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)
HVMac::HVMac() {
bailout(hv_vm_create(HV_VM_DEFAULT));
bailout(hv_vcpu_create(&vcpu, HV_VCPU_DEFAULT));
uint64_t vmx_cap_pinbased, vmx_cap_procbased, vmx_cap_procbased2, vmx_cap_entry;
bailout(hv_vmx_read_capability(HV_VMX_CAP_PINBASED, &vmx_cap_pinbased));
bailout(hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &vmx_cap_procbased));
bailout(hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &vmx_cap_procbased2));
bailout(hv_vmx_read_capability(HV_VMX_CAP_ENTRY, &vmx_cap_entry));
wvmcs(VMCS_CTRL_PIN_BASED, cap2ctrl(vmx_cap_pinbased, 0));
wvmcs(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));
wvmcs(VMCS_CTRL_CPU_BASED2, cap2ctrl(vmx_cap_procbased2, 0));
wvmcs(VMCS_CTRL_VMENTRY_CONTROLS, cap2ctrl(vmx_cap_entry, 0));
wvmcs(VMCS_CTRL_EXC_BITMAP, 0xffffffff);
wvmcs(VMCS_CTRL_CR0_MASK, 0xffffffff);
wvmcs(VMCS_CTRL_CR0_SHADOW, 0xffffffff);
wvmcs(VMCS_CTRL_CR4_MASK, 0xffffffff);
wvmcs(VMCS_CTRL_CR4_SHADOW, 0xffffffff);
wvmcs(VMCS_GUEST_CS, 1 << 3);
wvmcs(VMCS_GUEST_CS_AR, 0xc093);
wvmcs(VMCS_GUEST_CS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_CS_BASE, 0x0);
wvmcs(VMCS_GUEST_DS, 2 << 3);
wvmcs(VMCS_GUEST_DS_AR, 0xc093);
wvmcs(VMCS_GUEST_DS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_DS_BASE, 0);
wvmcs(VMCS_GUEST_ES, 2 << 3);
wvmcs(VMCS_GUEST_ES_AR, 0xc093);
wvmcs(VMCS_GUEST_ES_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_ES_BASE, 0);
wvmcs(VMCS_GUEST_FS, 2 << 3);
wvmcs(VMCS_GUEST_FS_AR, 0xc093);
wvmcs(VMCS_GUEST_FS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_FS_BASE, 0);
wvmcs(VMCS_GUEST_GS, 2 << 3);
wvmcs(VMCS_GUEST_GS_AR, 0xc093);
wvmcs(VMCS_GUEST_GS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_GS_BASE, 0);
wvmcs(VMCS_GUEST_SS, 2 << 3);
wvmcs(VMCS_GUEST_SS_AR, 0xc093);
wvmcs(VMCS_GUEST_SS_LIMIT, 0xffffffff);
wvmcs(VMCS_GUEST_SS_BASE, 0);
wvmcs(VMCS_GUEST_LDTR, 0);
wvmcs(VMCS_GUEST_LDTR_LIMIT, 0);
wvmcs(VMCS_GUEST_LDTR_AR, 0x10000);
wvmcs(VMCS_GUEST_LDTR_BASE, 0);
wvmcs(VMCS_GUEST_TR, 0);
wvmcs(VMCS_GUEST_TR_LIMIT, 0);
wvmcs(VMCS_GUEST_TR_AR, 0x83);
wvmcs(VMCS_GUEST_TR_BASE, 0);
}
HVMac::~HVMac() {
bailout(hv_vcpu_destroy(vcpu));
bailout(hv_vm_unmap(0, RAM_SIZE));
bailout(hv_vm_destroy());
}
void HVMac::map_phys(void *memory, uint32_t base, uint32_t size) {
bailout(hv_vm_map(memory, base, size, HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC));
}
void HVMac::invalidate_tlb() {
hv_vcpu_invalidate_tlb(vcpu);
}
#define REG_MAGIC() \
REG(EIP, RIP) \
REG(EFLAGS, RFLAGS) \
REG(EAX, RAX) \
REG(ECX, RCX) \
REG(EDX, RDX) \
REG(EBX, RBX) \
REG(ESI, RSI) \
REG(EDI, RDI) \
REG(ESP, RSP) \
REG(EBP, RBP) \
REG1(CS) \
REG1(SS) \
REG1(DS) \
REG1(ES) \
REG1(FS) \
REG1(GS) \
REG1(IDT_BASE) \
REG1(IDT_LIMIT) \
REG1(GDT_BASE) \
REG1(GDT_LIMIT) \
REG1(LDTR) \
REG1(LDT_BASE) \
REG1(LDT_LIMIT) \
REG1(LDT_AR) \
REG1(TR) \
REG1(TSS_BASE) \
REG1(TSS_LIMIT) \
REG1(TSS_AR) \
REG1(CR0) \
REG1(CR1) \
REG1(CR2) \
REG1(CR3) \
REG1(CR4) \
REG1(DR0) \
REG1(DR1) \
REG1(DR2) \
REG1(DR3) \
REG1(DR4) \
REG1(DR5) \
REG1(DR6) \
REG1(DR7) \
REG1(TPR) \
REG1(XCR0)
uint32_t HVMac::reg(HVReg reg) {
#define REG(a, b) case a: return rreg(HV_X86_##b);
#define REG1(a) case a: return rreg(HV_X86_##a);
switch(reg) {
REG_MAGIC()
}
#undef REG
#undef REG1
}
void HVMac::reg(HVReg reg, uint32_t val) {
#define REG(a, b) case a: wreg(HV_X86_##b, val); break;
#define REG1(a) case a: wreg(HV_X86_##a, val); break;
switch(reg) {
REG_MAGIC()
}
#undef REG
#undef REG1
}
exit_t HVMac::enter() {
exit_t _exit;
bailout(hv_vcpu_run(vcpu));
auto exit_reason = rvmcs(VMCS_RO_EXIT_REASON);
if(exit_reason & 0x80000000) {
_exit.reason = EntryFailed;
return _exit;
}
_exit.address = rvmcs(VMCS_RO_EXIT_QUALIFIC);
switch(exit_reason) {
case VMX_REASON_EXC_NMI: {
auto vec_val = rvmcs(VMCS_RO_VMEXIT_IRQ_INFO) & 0xFFFF;
switch((vec_val >> 8) & 7) {
case 6: {
_exit.reason = Interrupt;
_exit.interrupt_no = vec_val & 0xFF;
break;
}
case 3: {
_exit.reason = Exception;
_exit.interrupt_no = vec_val & 0xFF;
break;
}
default: {
cout << "Unknown NMI class. " << hex << vec_val << endl;
_exit.reason = Ignore;
}
}
break;
}
case VMX_REASON_VMCALL: {
_exit.reason = VmCall;
break;
}
case VMX_REASON_TRIPLE_FAULT: {
_exit.reason = TripleFault;
break;
}
case VMX_REASON_HLT: {
_exit.reason = Hlt;
break;
}
default: {
_exit.reason = Ignore;
}
}
return _exit;
}

34
Mac/HVMac.hpp Normal file
View file

@ -0,0 +1,34 @@
#include "Zookeeper.hpp"
class HVMac : public HV {
public:
HVMac();
~HVMac();
void map_phys(void *memory, uint32_t base, uint32_t size);
void invalidate_tlb();
uint32_t reg(HVReg reg);
void reg(HVReg reg, uint32_t val);
exit_t enter();
private:
uint32_t rreg(hv_x86_reg_t reg) {
uint64_t v;
bailout(hv_vcpu_read_register(vcpu, reg, &v));
return (uint32_t) v;
}
void wreg(hv_x86_reg_t reg, uint32_t v) {
bailout(hv_vcpu_write_register(vcpu, reg, (uint32_t) v));
}
uint64_t rvmcs(uint32_t field) {
uint64_t v;
bailout(hv_vmx_vcpu_read_vmcs(vcpu, field, &v));
return v;
}
void wvmcs(uint32_t field, uint64_t v) {
bailout(hv_vmx_vcpu_write_vmcs(vcpu, field, v));
}
hv_vcpuid_t vcpu;
};
#define HVImpl HVMac

View file

@ -1,6 +1,17 @@
CPP_FILES := $(wildcard *.cpp)
CC_FLAGS := -std=c++14 -I.
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
CC_FLAGS += -DLINUX
CPP_FILES += $(wildcard Linux/*.cpp)
endif
ifeq ($(UNAME_S),Darwin)
CC_FLAGS += -DMAC
CPP_FILES += $(wildcard Mac/*.cpp)
endif
OBJ_FILES := $(CPP_FILES:.cpp=.o)
CC_FLAGS := -std=c++14
all: NightBeliever zookeeper

View file

@ -58,16 +58,16 @@ uint32_t ThreadManager::current_thread() {
}
#define REGMAGIC() do {\
REG(RIP, eip); \
REG(RFLAGS, eflags); \
REG(RAX, eax); \
REG(RCX, ecx); \
REG(RDX, edx); \
REG(RBX, ebx); \
REG(RSI, esi); \
REG(RDI, edi); \
REG(RSP, esp); \
REG(RBP, ebp); \
REG(EIP, eip); \
REG(EFLAGS, eflags); \
REG(EAX, eax); \
REG(ECX, ecx); \
REG(EDX, edx); \
REG(EBX, ebx); \
REG(ESI, esi); \
REG(EDI, edi); \
REG(ESP, esp); \
REG(EBP, ebp); \
REG(CS, cs); \
REG(SS, ss); \
REG(DS, ds); \
@ -77,7 +77,7 @@ uint32_t ThreadManager::current_thread() {
} while(0)
void Thread::save() {
#define REG(reg, name) (name = (uint32_t) box->cpu->rreg(HV_X86_##reg))
#define REG(_reg, name) (name = box->cpu->hv->reg(_reg))
REGMAGIC();
#undef REG
#ifdef THREADDEBUG
@ -89,7 +89,7 @@ void Thread::save() {
}
void Thread::restore() {
#define REG(reg, name) (box->cpu->wreg(HV_X86_##reg, (uint64_t) name))
#define REG(_reg, name) (box->cpu->hv->reg(_reg, name))
REGMAGIC();
#undef REG
#ifdef THREADDEBUG

View file

@ -22,6 +22,11 @@ using namespace boost::algorithm;
#define RAM_SIZE 128*1024*1024
#define KRAM_SIZE 128*1024*1024
#include "HV.hpp"
#ifdef MAC
#include "Mac/HVMac.hpp"
#endif
#include "Hypercall.hpp"
#include "xbetypes.hpp"
#include "Xbe.hpp"

View file

@ -73,7 +73,7 @@ for i, (name, args) in enumerate(calls.items()):
print >>zhc, '\t\t\tauto sarg = box->cpu->read_memory<hypercall_%s_t>(addr);' % (name)
print >>zhc, '\t\t\t%sbox->hypercall->%s(%s);' % (ret, name, ', '.join('sarg.' + arg for arg, _, _ in args))
if rettype != 'void':
print >>zhc, '\t\t\tbox->cpu->wreg(HV_X86_RAX, ret);'
print >>zhc, '\t\t\tbox->cpu->hv->reg(EAX, ret);'
print >>zhl, '\t%s %s(%s);' % (typemap(rettype), name, ', '.join('%s %s' % (mapped, name) for name, _, mapped in args))
@ -89,7 +89,7 @@ for i, (name, args) in enumerate(calls.items()):
elif len(args) == 1:
print >>zhc, '\t\t\t%sbox->hypercall->%s(%saddr);' % (ret, name, cast('uint32_t', args[0][2]))
if rettype != 'void':
print >>zhc, '\t\t\tbox->cpu->wreg(HV_X86_RAX, ret);'
print >>zhc, '\t\t\tbox->cpu->hv->reg(EAX, ret);'
print >>zhl, '\t%s %s(%s %s);' % (typemap(rettype), name, args[0][2], args[0][0])
@ -102,7 +102,7 @@ for i, (name, args) in enumerate(calls.items()):
else:
print >>zhc, '\t\t\t%sbox->hypercall->%s();' % (ret, name)
if rettype != 'void':
print >>zhc, '\t\t\tbox->cpu->wreg(HV_X86_RAX, ret);'
print >>zhc, '\t\t\tbox->cpu->hv->reg(EAX, ret);'
print >>zhl, '\t%s %s();' % (typemap(rettype), name)