X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=blobdiff_plain;f=palacios%2Fsrc%2Fpalacios%2Fvmm_emulator.c;fp=palacios%2Fsrc%2Fpalacios%2Fvmm_emulator.c;h=db53ca8c8fd78fc3f11d13e53c9da68c12e1b295;hp=0000000000000000000000000000000000000000;hb=ddc16b0737cf58f7aa90a69c6652cdf4090aec51;hpb=626595465a2c6987606a6bc697df65130ad8c2d3 diff --git a/palacios/src/palacios/vmm_emulator.c b/palacios/src/palacios/vmm_emulator.c new file mode 100644 index 0000000..db53ca8 --- /dev/null +++ b/palacios/src/palacios/vmm_emulator.c @@ -0,0 +1,387 @@ +/* + * This file is part of the Palacios Virtual Machine Monitor developed + * by the V3VEE Project with funding from the United States National + * Science Foundation and the Department of Energy. + * + * The V3VEE Project is a joint project between Northwestern University + * and the University of New Mexico. You can find out more at + * http://www.v3vee.org + * + * Copyright (c) 2008, Jack Lange + * Copyright (c) 2008, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + +#include +#include +#include +#include +#include +#include +#include + +static const char VMMCALL[3] = {0x0f, 0x01, 0xd9}; + +#ifndef DEBUG_EMULATOR +#undef PrintDebug +#define PrintDebug(fmt, args...) +#endif + + +int v3_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; + + emulator->tf_enabled = 0; + + return 0; +} + +static addr_t get_new_page() { + void * page = V3_VAddr(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); + +#ifdef DEBUG_EMULATOR + PrintDebug("New Instr Stream:\n"); + PrintTraceMemDump((void *)(code_page + code_page_offset), 32); + PrintDebug("rip =%x\n", info->rip); +#endif + + + + 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; +} +*/ + + +static int set_stepping(struct guest_info * info) { + vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); + ctrl_area->exceptions.db = 1; + + info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf; + + ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1; + + return 0; +} + + +static int unset_stepping(struct guest_info * info) { + vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data)); + ctrl_area->exceptions.db = 0; + + ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled; + + if (info->emulator.tf_enabled) { + // Inject breakpoint exception into guest + } + + 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; + uchar_t 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); + } + + if (ret == -1) { + PrintError("Could not read guest memory\n"); + return -1; + } + +#ifdef DEBUG_EMULATOR + PrintDebug("Instr (15 bytes) at %x:\n", instr); + PrintTraceMemDump(instr, 15); +#endif + + + 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((addr_t)V3_PAddr((void *)(addr_t)(data_page->page_addr))); + + + // Read the data directly onto the emulated page + ret = read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data); + if ((ret == -1) || ((uint_t)ret != instr_info.op_size)) { + PrintError("Read error in emulator\n"); + V3_FreePage((void *)V3_PAddr((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); + set_stepping(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; + uchar_t 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; + int i; + + PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip); + + 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("Instruction is"); + for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); } + PrintDebug("\n"); + + 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) { + PrintDebug("Emulated instruction has rep\n"); + } + + /* + 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((addr_t)V3_PAddr((void *)(addr_t)(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); + set_stepping(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 *)(V3_PAddr((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; + + + PrintDebug("Returning to rip: 0x%x\n", info->rip); + + info->emulator.instr_length = 0; + + + unset_stepping(info); + + + PrintDebug("returning from emulation\n"); + + return 0; +}