From: Jack Lange Date: Sun, 3 Aug 2008 01:21:43 +0000 (+0000) Subject: added emulator X-Git-Tag: vmmhack1-ramdisk-boot-iso-puppy~27 X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=bf0d677f3d92f5949c3a73dad30aaf330201da44 added emulator --- diff --git a/palacios/include/palacios/vmm_emulator.h b/palacios/include/palacios/vmm_emulator.h new file mode 100644 index 0000000..3780d1c --- /dev/null +++ b/palacios/include/palacios/vmm_emulator.h @@ -0,0 +1,70 @@ +#ifndef __VMM_EMULATOR_H__ +#define __VMM_EMULATOR_H__ + +#ifdef __V3VEE__ + +#include +#include +#include + + + + + +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 diff --git a/palacios/include/palacios/vmm_shadow_paging.h b/palacios/include/palacios/vmm_shadow_paging.h index 779f323..853f851 100644 --- a/palacios/include/palacios/vmm_shadow_paging.h +++ b/palacios/include/palacios/vmm_shadow_paging.h @@ -40,6 +40,12 @@ addr_t create_new_shadow_pt32(); 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 diff --git a/palacios/src/devices/generic.c b/palacios/src/devices/generic.c index 8d329f5..13d9b9c 100644 --- a/palacios/src/devices/generic.c +++ b/palacios/src/devices/generic.c @@ -4,12 +4,10 @@ #include -#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 @@ -35,7 +33,7 @@ struct generic_internal { int generic_reset_device(struct vm_device * dev) { - GENERIC_DEBUG_PRINT("generic: reset device\n"); + PrintDebug("generic: reset device\n"); return 0; @@ -47,14 +45,14 @@ int generic_reset_device(struct vm_device * dev) 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; } @@ -68,13 +66,13 @@ int generic_write_port_passthrough(ushort_t port, { 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: @@ -92,7 +90,7 @@ int generic_write_port_passthrough(ushort_t port, } } - GENERIC_DEBUG_PRINT(" done\n"); + PrintDebug(" done\n"); return length; } @@ -104,7 +102,7 @@ int generic_read_port_passthrough(ushort_t port, { 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: @@ -122,13 +120,13 @@ int generic_read_port_passthrough(ushort_t port, } } - 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; } @@ -140,15 +138,15 @@ int generic_write_port_ignore(ushort_t port, { 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; } @@ -159,10 +157,10 @@ int generic_read_port_ignore(ushort_t port, 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; } @@ -186,58 +184,58 @@ int generic_init_device(struct vm_device * dev) 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 } @@ -250,48 +248,48 @@ int generic_deinit_device(struct vm_device *dev) 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 } diff --git a/palacios/src/geekos/trap.c b/palacios/src/geekos/trap.c index f1bbf28..6b8629d 100644 --- a/palacios/src/geekos/trap.c +++ b/palacios/src/geekos/trap.c @@ -1,7 +1,7 @@ /* * Trap handlers * Copyright (c) 2001,2003,2004 David H. Hovemeyer - * $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". @@ -25,7 +25,7 @@ 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); diff --git a/palacios/src/geekos/vm.c b/palacios/src/geekos/vm.c index a46bc76..70da496 100644 --- a/palacios/src/geekos/vm.c +++ b/palacios/src/geekos/vm.c @@ -164,7 +164,7 @@ void BuzzVM() } - +/* int passthrough_mem_read(void * guest_addr, void * dst, uint_t length, void * priv_data) { memcpy(dst, (void*)guest_addr, length); return length; @@ -174,7 +174,7 @@ int passthrough_mem_write(void * guest_addr, void * src, uint_t length, void * p memcpy((void*)guest_addr, src, length); return length; } - +*/ /* We need a configuration mechanism, so we can wrap this completely inside the VMM code, diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 121da9f..9d6fdab 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -68,6 +68,20 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info *vm_info) { 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; diff --git a/palacios/src/palacios/svm_handler.c b/palacios/src/palacios/svm_handler.c index 73f154a..96ab5fb 100644 --- a/palacios/src/palacios/svm_handler.c +++ b/palacios/src/palacios/svm_handler.c @@ -7,7 +7,7 @@ #include #include #include - +#include int handle_svm_exit(struct guest_info * info) { vmcb_ctrl_t * guest_ctrl = 0; @@ -192,6 +192,17 @@ int handle_svm_exit(struct guest_info * info) { 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]; diff --git a/palacios/src/palacios/vmm_config.c b/palacios/src/palacios/vmm_config.c index 8e80bfd..1e3e2f3 100644 --- a/palacios/src/palacios/vmm_config.c +++ b/palacios/src/palacios/vmm_config.c @@ -11,6 +11,23 @@ #include +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) { @@ -94,11 +111,18 @@ 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); @@ -138,7 +162,7 @@ int config_guest(struct guest_info * info, void * config_ptr) { #endif -#if 1 +#if 0 // Make the Serial ports invisible {0x3f8, 0x3f8+7, GENERIC_PRINT_AND_IGNORE}, // COM 1 diff --git a/palacios/src/palacios/vmm_ctrl_regs.c b/palacios/src/palacios/vmm_ctrl_regs.c index 2e566ef..152a7c0 100644 --- a/palacios/src/palacios/vmm_ctrl_regs.c +++ b/palacios/src/palacios/vmm_ctrl_regs.c @@ -45,11 +45,13 @@ int handle_cr0_write(struct guest_info * info) { 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"); @@ -157,11 +159,13 @@ int handle_cr0_read(struct guest_info * info) { 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"); @@ -220,11 +224,13 @@ int handle_cr3_write(struct guest_info * info) { 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"); @@ -297,11 +303,13 @@ int handle_cr3_read(struct guest_info * info) { 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"); diff --git a/palacios/src/palacios/vmm_emulator.c b/palacios/src/palacios/vmm_emulator.c new file mode 100644 index 0000000..fcce7c3 --- /dev/null +++ b/palacios/src/palacios/vmm_emulator.c @@ -0,0 +1,298 @@ +#include +#include +#include +#include + +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; +} diff --git a/palacios/src/palacios/vmm_mem.c b/palacios/src/palacios/vmm_mem.c index 7480da7..752ae2b 100644 --- a/palacios/src/palacios/vmm_mem.c +++ b/palacios/src/palacios/vmm_mem.c @@ -71,37 +71,41 @@ struct vmm_mem_hook * get_mem_hook(struct guest_info * info, addr_t guest_addr) /* 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; } diff --git a/palacios/src/palacios/vmm_shadow_paging.c b/palacios/src/palacios/vmm_shadow_paging.c index 9e70bb2..bc5441b 100644 --- a/palacios/src/palacios/vmm_shadow_paging.c +++ b/palacios/src/palacios/vmm_shadow_paging.c @@ -17,7 +17,6 @@ - static int handle_shadow_pte32_fault(struct guest_info* info, addr_t fault_addr, pf_error_t error_code, @@ -37,6 +36,38 @@ int init_shadow_page_state(struct guest_info * info) { 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) { @@ -164,7 +195,7 @@ static int handle_large_pagefault32(struct guest_info * info, } 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; } @@ -361,7 +392,7 @@ static int handle_shadow_pte32_fault(struct guest_info * info, 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