--- /dev/null
+#ifndef __VMM_EMULATOR_H__
+#define __VMM_EMULATOR_H__
+
+#ifdef __V3VEE__
+
+#include <palacios/vmm_list.h>
+#include <palacios/vmm_shadow_paging.h>
+#include <palacios/vmm_paging.h>
+
+
+
+
+
+struct emulated_page {
+ addr_t page_addr;
+ addr_t va;
+ pte32_t pte;
+ struct list_head page_list;
+};
+
+struct saved_page {
+ addr_t va;
+ pte32_t pte;
+ struct list_head page_list;
+};
+
+
+struct write_region {
+ void * write_data;
+
+ uint_t length;
+ int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data);
+ addr_t write_addr;
+ void * private_data;
+
+ struct list_head write_list;
+};
+
+
+struct emulation_state {
+ uint_t num_emulated_pages;
+ struct list_head emulated_pages;
+
+ uint_t num_saved_pages;
+ struct list_head saved_pages;
+
+ uint_t num_write_regions;
+ struct list_head write_regions;
+
+ uint_t running : 1;
+ uint_t instr_length;
+};
+
+
+int init_emulator(struct guest_info * info);
+
+
+int v3_emulation_exit_handler(struct guest_info * info);
+
+int v3_emulate_memory_write(struct guest_info * info, addr_t fault_gva,
+ int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data),
+ addr_t write_addr, void * private_data);
+int v3_emulate_memory_read(struct guest_info * info, addr_t fault_gva,
+ int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data),
+ addr_t read_addr, void * private_data);
+
+
+#endif // !__V3VEE__
+
+#endif
int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
int handle_shadow_invlpg(struct guest_info * info);
+
+
+
+int v3_replace_shdw_page(struct guest_info * info, addr_t location, void * new_page, void* old_page);
+int v3_replace_shdw_page32(struct guest_info * info, addr_t location, pte32_t * new_page, pte32_t * old_page);
+
#endif // ! __V3VEE__
#endif
#include <geekos/io.h>
-#define GENERIC_DEBUG 1
-#if GENERIC_DEBUG
-#define GENERIC_DEBUG_PRINT(first, rest...) PrintDebug(first, ##rest)
-#else
-#define GENERIC_DEBUG_PRINT(first, rest...)
+#ifndef DEBUG_GENERIC
+#undef PrintDebug
+#define PrintDebug(fmt, args...)
#endif
int generic_reset_device(struct vm_device * dev)
{
- GENERIC_DEBUG_PRINT("generic: reset device\n");
+ PrintDebug("generic: reset device\n");
return 0;
int generic_start_device(struct vm_device *dev)
{
- GENERIC_DEBUG_PRINT("generic: start device\n");
+ PrintDebug("generic: start device\n");
return 0;
}
int generic_stop_device(struct vm_device *dev)
{
- GENERIC_DEBUG_PRINT("generic: stop device\n");
+ PrintDebug("generic: stop device\n");
return 0;
}
{
uint_t i;
- GENERIC_DEBUG_PRINT("generic: writing 0x");
+ PrintDebug("generic: writing 0x");
for (i = 0; i < length; i++) {
- GENERIC_DEBUG_PRINT("%x", ((uchar_t*)src)[i]);
+ PrintDebug("%x", ((uchar_t*)src)[i]);
}
- GENERIC_DEBUG_PRINT(" to port 0x%x ... ", port);
+ PrintDebug(" to port 0x%x ... ", port);
switch (length) {
case 1:
}
}
- GENERIC_DEBUG_PRINT(" done\n");
+ PrintDebug(" done\n");
return length;
}
{
uint_t i;
- GENERIC_DEBUG_PRINT("generic: reading 0x%x bytes from port 0x%x ...", length, port);
+ PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
switch (length) {
case 1:
}
}
- GENERIC_DEBUG_PRINT(" done ... read 0x");
+ PrintDebug(" done ... read 0x");
for (i = 0; i < length; i++) {
- GENERIC_DEBUG_PRINT("%x", ((uchar_t*)src)[i]);
+ PrintDebug("%x", ((uchar_t*)src)[i]);
}
- GENERIC_DEBUG_PRINT("\n");
+ PrintDebug("\n");
return length;
}
{
uint_t i;
- GENERIC_DEBUG_PRINT("generic: writing 0x");
+ PrintDebug("generic: writing 0x");
for (i = 0; i < length; i++) {
- GENERIC_DEBUG_PRINT("%x", ((uchar_t*)src)[i]);
+ PrintDebug("%x", ((uchar_t*)src)[i]);
}
- GENERIC_DEBUG_PRINT(" to port 0x%x ... ", port);
+ PrintDebug(" to port 0x%x ... ", port);
- GENERIC_DEBUG_PRINT(" ignored\n");
+ PrintDebug(" ignored\n");
return length;
}
struct vm_device * dev)
{
- GENERIC_DEBUG_PRINT("generic: reading 0x%x bytes from port 0x%x ...", length, port);
+ PrintDebug("generic: reading 0x%x bytes from port 0x%x ...", length, port);
memset((char*)src,0,length);
- GENERIC_DEBUG_PRINT(" ignored (return zeroed buffer)\n");
+ PrintDebug(" ignored (return zeroed buffer)\n");
return length;
}
struct generic_internal *state = (struct generic_internal *)(dev->private_data);
uint_t i, j;
- GENERIC_DEBUG_PRINT("generic: init_device\n");
+ PrintDebug("generic: init_device\n");
// Would read state here
generic_reset_device(dev);
for (i = 0; i < state->num_port_ranges; i++) {
- GENERIC_DEBUG_PRINT("generic: hooking ports 0x%x to 0x%x as %x\n", state->port_ranges[i][0], state->port_ranges[i][1], state->port_ranges[i][2]==GENERIC_PRINT_AND_PASSTHROUGH ? "print-and-passthrough" : "print-and-ignore");
+ PrintDebug("generic: hooking ports 0x%x to 0x%x as %x\n", state->port_ranges[i][0], state->port_ranges[i][1], state->port_ranges[i][2]==GENERIC_PRINT_AND_PASSTHROUGH ? "print-and-passthrough" : "print-and-ignore");
#if PORT_HOOKS
for (j = state->port_ranges[i][0]; j <= state->port_ranges[i][1]; j++) {
if (state->port_ranges[i][2]==GENERIC_PRINT_AND_PASSTHROUGH) {
if (dev_hook_io(dev, j, &generic_read_port_passthrough, &generic_write_port_passthrough)) {
- GENERIC_DEBUG_PRINT("generic: can't hook port 0x%x (already hooked?)\n", j);
+ PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", j);
}
} else if (state->port_ranges[i][2]==GENERIC_PRINT_AND_IGNORE) {
if (dev_hook_io(dev, j, &generic_read_port_ignore, &generic_write_port_ignore)) {
- GENERIC_DEBUG_PRINT("generic: can't hook port 0x%x (already hooked?)\n", j);
+ PrintDebug("generic: can't hook port 0x%x (already hooked?)\n", j);
}
}
}
#else
- GENERIC_DEBUG_PRINT("generic: hooking ports not supported\n");
+ PrintDebug("generic: hooking ports not supported\n");
#endif
}
for (i = 0; i < state->num_address_ranges; i++) {
- GENERIC_DEBUG_PRINT("generic: hooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]);
+ PrintDebug("generic: hooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]);
#if MEM_HOOKS
if (dev_hook_mem(dev, state->address_ranges[i][0], state->address_ranges[i][1])) {
- GENERIC_DEBUG_PRINT("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
+ PrintDebug("generic: Can't hook addresses 0x%x to 0x%x (already hooked?)\n",
state->address_ranges[i][0], state->address_ranges[i][1]);
}
#else
- GENERIC_DEBUG_PRINT("generic: hooking addresses not supported\n");
+ PrintDebug("generic: hooking addresses not supported\n");
#endif
}
for (i = 0; i < state->num_irq_ranges; i++) {
- GENERIC_DEBUG_PRINT("generic: hooking irqs 0x%x to 0x%x\n",state->irq_ranges[i][0],state->irq_ranges[i][1]);
+ PrintDebug("generic: hooking irqs 0x%x to 0x%x\n",state->irq_ranges[i][0],state->irq_ranges[i][1]);
#if IRQ_HOOKS
for (j = state->irq_ranges[i][0]; j <= state->irq_ranges[i][1]; j++) {
if (dev_hook_irq(dev, j, &generic_interrupt)) {
- GENERIC_DEBUG_PRINT("generic: can't hook irq 0x%x (already hooked?)\n", j);
+ PrintDebug("generic: can't hook irq 0x%x (already hooked?)\n", j);
}
}
#else
- GENERIC_DEBUG_PRINT("generic: hooking irqs not supported\n");
+ PrintDebug("generic: hooking irqs not supported\n");
#endif
}
struct generic_internal *state = (struct generic_internal *)(dev->private_data);
uint_t i, j;
- GENERIC_DEBUG_PRINT("generic: deinit_device\n");
+ PrintDebug("generic: deinit_device\n");
for (i = 0; i < state->num_irq_ranges; i++) {
- GENERIC_DEBUG_PRINT("generic: unhooking irqs 0x%x to 0x%x\n", state->irq_ranges[i][0], state->irq_ranges[i][1]);
+ PrintDebug("generic: unhooking irqs 0x%x to 0x%x\n", state->irq_ranges[i][0], state->irq_ranges[i][1]);
#if IRQ_HOOKS
for (j = state->irq_ranges[i][0]; j <= state->irq_ranges[i][1]; j++) {
if (dev_unhook_irq(dev, j)) {
- GENERIC_DEBUG_PRINT("generic: can't unhook irq 0x%x (already unhooked?)\n",j);
+ PrintDebug("generic: can't unhook irq 0x%x (already unhooked?)\n",j);
}
}
#else
- GENERIC_DEBUG_PRINT("generic: unhooking irqs not supported\n");
+ PrintDebug("generic: unhooking irqs not supported\n");
#endif
}
for (i = 0; i < state->num_address_ranges; i++) {
- GENERIC_DEBUG_PRINT("generic: unhooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]);
+ PrintDebug("generic: unhooking addresses 0x%x to 0x%x\n",state->address_ranges[i][0],state->address_ranges[i][1]);
#if MEM_HOOKS
if (dev_unhook_mem(dev, state->address_ranges[i][0], state->address_ranges[i][1])) {
- GENERIC_DEBUG_PRINT("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
+ PrintDebug("generic: Can't unhook addresses 0x%x to 0x%x (already unhooked?)\n",
state->address_ranges[i][0], state->address_ranges[i][1]);
}
#else
- GENERIC_DEBUG_PRINT("generic: unhooking addresses not supported\n");
+ PrintDebug("generic: unhooking addresses not supported\n");
#endif
}
for (i = 0; i < state->num_port_ranges; i++) {
- GENERIC_DEBUG_PRINT("generic: unhooking ports 0x%x to 0x%x\n",state->port_ranges[i][0],state->port_ranges[i][1]);
+ PrintDebug("generic: unhooking ports 0x%x to 0x%x\n",state->port_ranges[i][0],state->port_ranges[i][1]);
#if PORT_HOOKS
for (j = state->port_ranges[i][0]; j <= state->port_ranges[i][1]; j++) {
if (dev_unhook_io(dev, j)) {
- GENERIC_DEBUG_PRINT("generic: can't unhook port 0x%x (already unhooked?)\n", j);
+ PrintDebug("generic: can't unhook port 0x%x (already unhooked?)\n", j);
}
}
#else
- GENERIC_DEBUG_PRINT("generic: unhooking ports not supported\n");
+ PrintDebug("generic: unhooking ports not supported\n");
#endif
}
/*
* Trap handlers
* Copyright (c) 2001,2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
- * $Revision: 1.2 $
+ * $Revision: 1.3 $
*
* This is free software. You are permitted to use,
* redistribute, and modify it as specified in the file "COPYING".
static void GPF_Handler(struct Interrupt_State* state)
{
/* Send the thread to the reaper... */
- SerialPrintLevel(1000,"Exception %d received, killing thread %p\n",state->intNum, g_currentThread);
+ SerialPrintLevel(1000,"VMM: Exception %d received, killing thread %p\n",state->intNum, g_currentThread);
Dump_Interrupt_State(state);
Exit(-1);
}
-
+/*
int passthrough_mem_read(void * guest_addr, void * dst, uint_t length, void * priv_data) {
memcpy(dst, (void*)guest_addr, length);
return length;
memcpy((void*)guest_addr, src, length);
return length;
}
-
+*/
/* We need a configuration mechanism, so we can wrap this completely inside the VMM code,
guest_state->efer |= EFER_MSR_svm_enable;
guest_state->rflags = 0x00000002; // The reserved bit is always 1
ctrl_area->svm_instrs.VMRUN = 1;
+ ctrl_area->svm_instrs.VMMCALL = 1;
+ ctrl_area->svm_instrs.VMLOAD = 1;
+ ctrl_area->svm_instrs.VMSAVE = 1;
+ ctrl_area->svm_instrs.STGI = 1;
+ ctrl_area->svm_instrs.CLGI = 1;
+ ctrl_area->svm_instrs.SKINIT = 1;
+ ctrl_area->svm_instrs.RDTSCP = 1;
+ ctrl_area->svm_instrs.ICEBP = 1;
+ ctrl_area->svm_instrs.WBINVD = 1;
+ ctrl_area->svm_instrs.MONITOR = 1;
+ ctrl_area->svm_instrs.MWAIT_always = 1;
+ ctrl_area->svm_instrs.MWAIT_if_armed = 1;
+
+
ctrl_area->instrs.HLT = 1;
// guest_state->cr0 = 0x00000001; // PE
ctrl_area->guest_ASID = 1;
#include <palacios/svm_halt.h>
#include <palacios/svm_pause.h>
#include <palacios/vmm_intr.h>
-
+#include <palacios/vmm_emulator.h>
int handle_svm_exit(struct guest_info * info) {
vmcb_ctrl_t * guest_ctrl = 0;
if (handle_svm_pause(info) == -1) {
return -1;
}
+ } else if (exit_code == VMEXIT_VMMCALL) {
+ PrintDebug("VMMCALL\n");
+ if (info->run_state == VM_EMULATING) {
+ if (v3_emulation_exit_handler(info) == -1) {
+ return -1;
+ }
+ } else {
+ PrintError("VMMCALL with not emulator...\n");
+ return -1;
+ }
+
} else {
addr_t rip_addr;
char buf[15];
#include <devices/generic.h>
+static int passthrough_mem_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
+ // memcpy(dst, (void*)guest_addr, length);
+ int foo = 20;
+
+
+ memcpy(dst, &foo, length);
+
+ PrintDebug("Passthrough mem read returning: %d (length=%d)\n", foo + (guest_addr & 0xfff), length);
+ return length;
+}
+
+static int passthrough_mem_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
+ memcpy((void*)guest_addr, src, length);
+ return length;
+}
+
+
int config_guest(struct guest_info * info, void * config_ptr) {
}
- //add_shadow_region_passthrough(info, 0x100000, 0x2000000, (addr_t)Allocate_VMM_Pages(8192));
- add_shadow_region_passthrough(info, 0x100000, 0x1000000, (addr_t)V3_AllocPages(4096));
-
- add_shadow_region_passthrough(info, 0x1000000, 0x8000000, (addr_t)V3_AllocPages(32768));
-
+
+ // add_shadow_region_passthrough(info, 0x100000, 0x1000000, (addr_t)V3_AllocPages(4096));
+ {
+ /* MEMORY HOOK TEST */
+ add_shadow_region_passthrough(info, 0x100000, 0xa00000, (addr_t)V3_AllocPages(2304));
+ hook_guest_mem(info, 0xa00000, 0xa01000, passthrough_mem_read, passthrough_mem_write, NULL);
+
+ add_shadow_region_passthrough(info, 0xa01000, 0x1000000, (addr_t)V3_AllocPages(1791));
+
+ }
+ add_shadow_region_passthrough(info, 0x1000000, 0x8000000, (addr_t)V3_AllocPages(32768));
+
// test - give linux accesss to PCI space - PAD
add_shadow_region_passthrough(info, 0xc0000000,0xffffffff,0xc0000000);
#endif
-#if 1
+#if 0
// Make the Serial ports invisible
{0x3f8, 0x3f8+7, GENERIC_PRINT_AND_IGNORE}, // COM 1
ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
}
- if (ret != 15) {
+ /* The IFetch will already have faulted in the necessary bytes for the full instruction
+ if (ret != 15) {
// I think we should inject a GPF into the guest
PrintError("Could not read instruction (ret=%d)\n", ret);
return -1;
- }
+ }
+ */
if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
PrintError("Could not decode instruction\n");
ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
}
- if (ret != 15) {
- // I think we should inject a GPF into the guest
- PrintError("Could not read instruction (ret=%d)\n", ret);
- return -1;
- }
+ /* The IFetch will already have faulted in the necessary bytes for the full instruction
+ if (ret != 15) {
+ // I think we should inject a GPF into the guest
+ PrintError("Could not read instruction (ret=%d)\n", ret);
+ return -1;
+ }
+ */
if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
PrintError("Could not decode instruction\n");
ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
}
- if (ret != 15) {
- // I think we should inject a GPF into the guest
- PrintError("Could not read instruction (ret=%d)\n", ret);
- return -1;
- }
+ /* The IFetch will already have faulted in the necessary bytes for the full instruction
+ if (ret != 15) {
+ // I think we should inject a GPF into the guest
+ PrintError("Could not read instruction (ret=%d)\n", ret);
+ return -1;
+ }
+ */
if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
PrintError("Could not decode instruction\n");
ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
}
- if (ret != 15) {
- // I think we should inject a GPF into the guest
- PrintError("Could not read instruction (ret=%d)\n", ret);
- return -1;
- }
+ /* The IFetch will already have faulted in the necessary bytes for the full instruction
+ if (ret != 15) {
+ // I think we should inject a GPF into the guest
+ PrintError("Could not read instruction (ret=%d)\n", ret);
+ return -1;
+ }
+ */
if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
PrintError("Could not decode instruction\n");
--- /dev/null
+#include <palacios/vmm.h>
+#include <palacios/vmm_emulator.h>
+#include <palacios/vm_guest_mem.h>
+#include <palacios/vmm_decoder.h>
+
+static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
+
+int init_emulator(struct guest_info * info) {
+ struct emulation_state * emulator = &(info->emulator);
+
+ emulator->num_emulated_pages = 0;
+ INIT_LIST_HEAD(&(emulator->emulated_pages));
+
+
+ emulator->num_saved_pages = 0;
+ INIT_LIST_HEAD(&(emulator->saved_pages));
+
+ emulator->num_write_regions = 0;
+ INIT_LIST_HEAD(&(emulator->write_regions));
+
+ emulator->running = 0;
+ emulator->instr_length = 0;
+
+ return 0;
+}
+
+static addr_t get_new_page() {
+ void * page = V3_AllocPages(1);
+ memset(page, 0, PAGE_SIZE);
+
+ return (addr_t)page;
+}
+
+
+static int setup_code_page(struct guest_info * info, char * instr, struct basic_instr_info * instr_info ) {
+ addr_t code_page_offset = PT32_PAGE_OFFSET(info->rip);
+ addr_t code_page = get_new_page();
+ struct emulated_page * new_code_page = V3_Malloc(sizeof(struct emulated_page));
+ struct saved_page * saved_code_page = V3_Malloc(sizeof(struct saved_page));
+
+
+ saved_code_page->va = PT32_PAGE_ADDR(info->rip);
+
+ new_code_page->page_addr = code_page;
+ new_code_page->va = PT32_PAGE_ADDR(info->rip);
+
+ new_code_page->pte.present = 1;
+ new_code_page->pte.writable = 0;
+ new_code_page->pte.user_page = 1;
+ new_code_page->pte.page_base_addr = PT32_BASE_ADDR(code_page);
+
+ memcpy((void *)(code_page + code_page_offset), instr, instr_info->instr_length);
+ memcpy((void *)(code_page + code_page_offset + instr_info->instr_length), VMMCALL, 3);
+
+ PrintDebug("New Instr Stream:\n");
+ PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
+ PrintDebug("rip =%x\n", info->rip);
+
+
+
+
+ v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte));
+
+
+ list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages));
+ info->emulator.num_emulated_pages++;
+
+ list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages));
+ info->emulator.num_saved_pages++;
+
+ return 0;
+}
+
+
+// get the current instr
+// check if rep + remove
+// put into new page, vmexit after
+// replace new page with current eip page
+//
+int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva,
+ int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data),
+ addr_t read_gpa, void * private_data) {
+ struct basic_instr_info instr_info;
+ char instr[15];
+ int ret;
+ struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
+ addr_t data_addr_offset = PT32_PAGE_OFFSET(read_gva);
+ pte32_t saved_pte;
+
+ PrintDebug("Emulating Read\n");
+
+ if (info->mem_mode == PHYSICAL_MEM) {
+ ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ } else {
+ ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ }
+
+ PrintDebug("Instr (15 bytes) at %x:\n", instr);
+ PrintTraceMemDump(instr, 15);
+
+ if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
+ PrintError("Could not do a basic memory instruction decode\n");
+ V3_Free(data_page);
+ return -1;
+ }
+
+ if (instr_info.has_rep == 1) {
+ PrintError("We currently don't handle rep* instructions\n");
+ V3_Free(data_page);
+ return -1;
+ }
+
+
+ data_page->page_addr = get_new_page();
+ data_page->va = PT32_PAGE_ADDR(read_gva);
+ data_page->pte.present = 1;
+ data_page->pte.writable = 0;
+ data_page->pte.user_page = 1;
+ data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
+
+
+ // Read the data directly onto the emulated page
+ if (read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data) != instr_info.op_size) {
+ PrintError("Read error in emulator\n");
+ V3_FreePage((void *)(data_page->page_addr));
+ V3_Free(data_page);
+ return -1;
+ }
+
+ v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
+
+
+ list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
+ info->emulator.num_emulated_pages++;
+
+ if (saved_pte.present == 1) {
+ struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
+ saved_data_page->pte = saved_pte;
+ saved_data_page->va = PT32_PAGE_ADDR(read_gva);
+
+ list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
+ info->emulator.num_saved_pages++;
+ }
+
+
+ setup_code_page(info, instr, &instr_info);
+
+ info->emulator.running = 1;
+ info->run_state = VM_EMULATING;
+ info->emulator.instr_length = instr_info.instr_length;
+
+ return 0;
+}
+
+
+
+int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
+ int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data),
+ addr_t write_gpa, void * private_data) {
+
+ struct basic_instr_info instr_info;
+ char instr[15];
+ int ret;
+ struct write_region * write_op = V3_Malloc(sizeof(struct write_region ));
+ struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
+ addr_t data_addr_offset = PT32_PAGE_OFFSET(write_gva);
+ pte32_t saved_pte;
+
+ PrintDebug("Emulating Write\n");
+
+ if (info->mem_mode == PHYSICAL_MEM) {
+ ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ } else {
+ ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ }
+
+ if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
+ PrintError("Could not do a basic memory instruction decode\n");
+ V3_Free(write_op);
+ V3_Free(data_page);
+ return -1;
+ }
+
+ if (instr_info.has_rep == 1) {
+ PrintError("We currently don't handle rep* instructions\n");
+ V3_Free(write_op);
+ V3_Free(data_page);
+ return -1;
+ }
+
+
+ data_page->page_addr = get_new_page();
+ data_page->va = PT32_PAGE_ADDR(write_gva);
+ data_page->pte.present = 1;
+ data_page->pte.writable = 1;
+ data_page->pte.user_page = 1;
+ data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
+
+
+
+ write_op->write = write;
+ write_op->write_addr = write_gpa;
+ write_op->length = instr_info.op_size;
+ write_op->private_data = private_data;
+
+ write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
+
+ list_add(&(write_op->write_list), &(info->emulator.write_regions));
+ info->emulator.num_write_regions--;
+
+ v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
+
+
+ list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
+ info->emulator.num_emulated_pages++;
+
+ if (saved_pte.present == 1) {
+ struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
+ saved_data_page->pte = saved_pte;
+ saved_data_page->va = PT32_PAGE_ADDR(write_gva);
+
+ list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
+ info->emulator.num_saved_pages++;
+ }
+
+
+ if (info->emulator.running == 0) {
+ setup_code_page(info, instr, &instr_info);
+ info->emulator.running = 1;
+ info->run_state = VM_EMULATING;
+ info->emulator.instr_length = instr_info.instr_length;
+ }
+
+ return 0;
+}
+
+
+// end emulation
+int v3_emulation_exit_handler(struct guest_info * info) {
+ struct saved_page * svpg, * p_svpg;
+ struct emulated_page * empg, * p_empg;
+ struct write_region * wr_reg, * p_wr_reg;
+ pte32_t dummy_pte;
+
+ // Complete the writes
+ // delete writes
+ // swap out emulated pages with blank dummies
+ // swap in saved pages
+ // increment rip
+
+ PrintDebug("V3 Emulation Exit Handler\n");
+
+ list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) {
+ wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data);
+ PrintDebug("Writing \n");
+
+ list_del(&(wr_reg->write_list));
+ V3_Free(wr_reg);
+
+ }
+ info->emulator.num_write_regions = 0;
+
+
+ *(uint_t *)&dummy_pte = 0;
+
+ list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
+ pte32_t empte32_t;
+
+ PrintDebug("wiping page %x\n", empg->va);
+
+ v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
+ V3_FreePage((void *)(empg->page_addr));
+
+ list_del(&(empg->page_list));
+ V3_Free(empg);
+ }
+ info->emulator.num_emulated_pages = 0;
+
+ list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
+
+ PrintDebug("Setting Saved page %x back\n", svpg->va);
+ v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
+
+ list_del(&(svpg->page_list));
+ V3_Free(svpg);
+ }
+ info->emulator.num_saved_pages = 0;
+
+ info->run_state = VM_RUNNING;
+ info->emulator.running = 0;
+ //info->rip += info->emulator.instr_length;
+
+ info->emulator.instr_length = 0;
+
+ PrintDebug("returning from emulation\n");
+
+ return 0;
+}
/* mem_addr is the guest physical memory address */
-static int mem_hook_dispatch(struct guest_info * info, addr_t fault_addr, addr_t guest_phys_page, pf_error_t access_info, struct vmm_mem_hook * hook) {
+static int mem_hook_dispatch(struct guest_info * info,
+ addr_t fault_gva, addr_t fault_gpa,
+ pf_error_t access_info, struct vmm_mem_hook * hook)
+{
// emulate and then dispatch
// or dispatch and emulate
if (access_info.write == 1) {
- void * src = NULL;
- uint_t length = 0;
-
- PrintDebug("Memory hook write\n");
- return -1;
-
- if (hook->write(fault_addr, src, length, hook->priv_data) != length) {
+ if (v3_emulate_memory_write(info, fault_gva, hook->write, fault_gpa, hook->priv_data) == -1) {
+ PrintError("Memory write emulation failed\n");
return -1;
}
+
} else {
- PrintDebug("Memory hook read\n");
- return -1;
+ if (v3_emulate_memory_read(info, fault_gva, hook->read, fault_gpa, hook->priv_data) == -1) {
+ PrintError("Memory read emulation failed\n");
+ return -1;
+ }
}
- return -1;
+ return 0;
}
-int handle_special_page_fault(struct guest_info * info, addr_t fault_addr, addr_t guest_phys_page, pf_error_t access_info) {
- struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), guest_phys_page);
+int handle_special_page_fault(struct guest_info * info,
+ addr_t fault_gva, addr_t fault_gpa,
+ pf_error_t access_info)
+{
+ struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), fault_gpa);
switch (reg->host_type) {
case HOST_REGION_HOOK:
- return mem_hook_dispatch(info, fault_addr, guest_phys_page, access_info, (struct vmm_mem_hook *)(reg->host_addr));
+ return mem_hook_dispatch(info, fault_gva, fault_gpa, access_info, (struct vmm_mem_hook *)(reg->host_addr));
default:
return -1;
}
-
static int handle_shadow_pte32_fault(struct guest_info* info,
addr_t fault_addr,
pf_error_t error_code,
return 0;
}
+
+
+
+
+
+int v3_replace_shdw_page32(struct guest_info * info, addr_t location, pte32_t * new_page, pte32_t * old_page) {
+ pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
+ pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(location)]);
+
+ if (shadow_pde->large_page == 0) {
+ pte32_t * shadow_pt = (pte32_t *)PDE32_T_ADDR((*shadow_pde));
+ pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(location)]);
+
+ //if (shadow_pte->present == 1) {
+ *(uint_t *)old_page = *(uint_t *)shadow_pte;
+ //}
+
+ *(uint_t *)shadow_pte = *(uint_t *)new_page;
+
+ } else {
+ // currently unhandled
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
if (info->mem_mode == PHYSICAL_MEM) {
} else {
// Handle hooked pages as well as other special pages
- if (handle_special_page_fault(info, fault_addr, PT32_PAGE_ADDR(guest_fault_pa), error_code) == -1) {
+ if (handle_special_page_fault(info, fault_addr, guest_fault_pa, error_code) == -1) {
PrintError("Special Page Fault handler returned error for address: %x\n", fault_addr);
return -1;
}
if (shadow_pte_access == PT_ENTRY_NOT_PRESENT) {
- addr_t guest_pa = PTE32_T_ADDR((*guest_pte));
+ addr_t guest_pa = PTE32_T_ADDR((*guest_pte)) + PT32_PAGE_OFFSET(fault_addr);
// Page Table Entry Not Present