-/* Northwestern University */
-/* (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> */
+/*
+ * 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 <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Authors: Jack Lange <jarusl@cs.northwestern.edu>
+ * Peter Dinda <pdinda@northwestern.edu> (full hook/string ops)
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
#include <palacios/vmm.h>
#include <palacios/vmm_emulator.h>
-#include <palacios/vm_guest_mem.h>
#include <palacios/vmm_decoder.h>
-#include <palacios/vmm_debug.h>
-#include <palacios/vmcb.h>
+#include <palacios/vmm_instr_emulator.h>
#include <palacios/vmm_ctrl_regs.h>
-static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
-
-#ifndef DEBUG_EMULATOR
+#ifndef V3_CONFIG_DEBUG_EMULATOR
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
-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;
-
- emulator->tf_enabled = 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);
-
-#ifdef DEBUG_EMULATOR
- PrintDebug("New Instr Stream:\n");
- PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
- PrintDebug("rip =%x\n", info->rip);
+static int run_op(struct guest_info * info, v3_op_type_t op_type,
+ addr_t src_addr, addr_t dst_addr,
+ int src_op_size, int dst_op_size) {
+
+ if (src_op_size == 1) {
+ PrintDebug(info->vm_info, info, "Executing 8 bit instruction\n");
+
+ switch (op_type) {
+ case V3_OP_ADC:
+ adc8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_ADD:
+ add8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_AND:
+ and8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_OR:
+ or8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_XOR:
+ xor8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SUB:
+ sub8((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+
+ case V3_OP_MOV:
+ mov8((addr_t *)dst_addr, (addr_t *)src_addr);
+ break;
+
+ case V3_OP_MOVZX:
+ movzx8((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
+ break;
+ case V3_OP_MOVSX:
+ movsx8((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
+ break;
+
+ case V3_OP_NOT:
+ not8((addr_t *)dst_addr);
+ break;
+ case V3_OP_XCHG:
+ xchg8((addr_t *)dst_addr, (addr_t *)src_addr);
+ break;
+
+
+ case V3_OP_INC:
+ inc8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_DEC:
+ dec8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_NEG:
+ neg8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETB:
+ setb8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETBE:
+ setbe8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETL:
+ setl8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETLE:
+ setle8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETNB:
+ setnb8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETNBE:
+ setnbe8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETNL:
+ setnl8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETNLE:
+ setnle8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETNO:
+ setno8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETNP:
+ setnp8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETNS:
+ setns8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETNZ:
+ setnz8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETO:
+ seto8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETP:
+ setp8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETS:
+ sets8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SETZ:
+ setz8((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+
+ default:
+ PrintError(info->vm_info, info, "Unknown 8 bit instruction\n");
+ return -1;
+ }
+
+ } else if (src_op_size == 2) {
+ PrintDebug(info->vm_info, info, "Executing 16 bit instruction\n");
+
+ switch (op_type) {
+ case V3_OP_ADC:
+ adc16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_ADD:
+ add16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_AND:
+ and16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_OR:
+ or16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_XOR:
+ xor16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SUB:
+ sub16((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+
+
+ case V3_OP_INC:
+ inc16((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_DEC:
+ dec16((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_NEG:
+ neg16((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+
+ case V3_OP_MOV:
+ mov16((addr_t *)dst_addr, (addr_t *)src_addr);
+ break;
+ case V3_OP_MOVZX:
+ movzx16((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
+ break;
+ case V3_OP_MOVSX:
+ movsx16((addr_t *)dst_addr, (addr_t *)src_addr, dst_op_size);
+ break;
+ case V3_OP_NOT:
+ not16((addr_t *)dst_addr);
+ break;
+ case V3_OP_XCHG:
+ xchg16((addr_t *)dst_addr, (addr_t *)src_addr);
+ break;
+
+ default:
+ PrintError(info->vm_info, info, "Unknown 16 bit instruction\n");
+ return -1;
+ }
+
+ } else if (src_op_size == 4) {
+ PrintDebug(info->vm_info, info, "Executing 32 bit instruction\n");
+
+ switch (op_type) {
+ case V3_OP_ADC:
+ adc32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_ADD:
+ add32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_AND:
+ and32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_OR:
+ or32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_XOR:
+ xor32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SUB:
+ sub32((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+
+ case V3_OP_INC:
+ inc32((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_DEC:
+ dec32((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_NEG:
+ neg32((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+
+ case V3_OP_MOV:
+ mov32((addr_t *)dst_addr, (addr_t *)src_addr);
+ break;
+
+ case V3_OP_NOT:
+ not32((addr_t *)dst_addr);
+ break;
+ case V3_OP_XCHG:
+ xchg32((addr_t *)dst_addr, (addr_t *)src_addr);
+ break;
+
+ default:
+ PrintError(info->vm_info, info, "Unknown 32 bit instruction\n");
+ return -1;
+ }
+
+#ifdef __V3_64BIT__
+ } else if (src_op_size == 8) {
+ PrintDebug(info->vm_info, info, "Executing 64 bit instruction\n");
+
+ switch (op_type) {
+ case V3_OP_ADC:
+ adc64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_ADD:
+ add64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_AND:
+ and64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_OR:
+ or64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_XOR:
+ xor64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_SUB:
+ sub64((addr_t *)dst_addr, (addr_t *)src_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+
+ case V3_OP_INC:
+ inc64((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_DEC:
+ dec64((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+ case V3_OP_NEG:
+ neg64((addr_t *)dst_addr, (addr_t *)&(info->ctrl_regs.rflags));
+ break;
+
+ case V3_OP_MOV:
+ mov64((addr_t *)dst_addr, (addr_t *)src_addr);
+ break;
+
+ case V3_OP_NOT:
+ not64((addr_t *)dst_addr);
+ break;
+ case V3_OP_XCHG:
+ xchg64((addr_t *)dst_addr, (addr_t *)src_addr);
+ break;
+
+ default:
+ PrintError(info->vm_info, info, "Unknown 64 bit instruction\n");
+ return -1;
+ }
#endif
+ } else {
+ PrintError(info->vm_info, info, "Invalid Operation Size\n");
+ return -1;
+ }
-
- 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;
+ 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;
-}
+/* Returns the number of bytes written, or -1 if there is an error */
+static int run_str_op(struct guest_info * core, struct x86_instr * instr,
+ addr_t src_addr, addr_t dst_addr,
+ int op_size, int rep_cnt) {
-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;
+ addr_t tmp_rcx = rep_cnt;
+ int emulation_length = op_size * rep_cnt;
+ struct rflags * flags_reg = (struct rflags *)&(core->ctrl_regs.rflags);
- ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled;
- if (info->emulator.tf_enabled) {
- // Inject breakpoint exception into guest
- }
+ PrintDebug(core->vm_info, core, "Emulation_len=%d, tmp_rcx=%d\n", emulation_length, (uint_t)tmp_rcx);
- return 0;
+ if (instr->op_type == V3_OP_MOVS) {
+ if (op_size== 1) {
+ movs8((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(core->ctrl_regs.rflags));
+ } else if (op_size == 2) {
+ movs16((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(core->ctrl_regs.rflags));
+ } else if (op_size == 4) {
+ movs32((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(core->ctrl_regs.rflags));
+#ifdef __V3_64BIT__
+ } else if (op_size == 8) {
+ movs64((addr_t *)&dst_addr, &src_addr, &tmp_rcx, (addr_t *)&(core->ctrl_regs.rflags));
+#endif
+ } else {
+ PrintError(core->vm_info, core, "Invalid operand length\n");
+ return -1;
+ }
+
+ if (flags_reg->df == 0) {
+ core->vm_regs.rdi += emulation_length;
+ core->vm_regs.rsi += emulation_length;
+ } else {
+ core->vm_regs.rdi -= emulation_length;
+ core->vm_regs.rsi -= emulation_length;
+ }
+
+ // RCX is only modified if the rep prefix is present
+ if (instr->prefixes.rep == 1) {
+ core->vm_regs.rcx -= rep_cnt;
+ }
+
+ } else if (instr->op_type == V3_OP_STOS) {
+ if (op_size == 1) {
+ stos8((addr_t *)&dst_addr, (addr_t *)&(core->vm_regs.rax), &tmp_rcx, (addr_t *)&(core->ctrl_regs.rflags));
+ } else if (op_size == 2) {
+ stos16((addr_t *)&dst_addr, (addr_t *)&(core->vm_regs.rax), &tmp_rcx, (addr_t *)&(core->ctrl_regs.rflags));
+ } else if (op_size == 4) {
+ stos32((addr_t *)&dst_addr, (addr_t *)&(core->vm_regs.rax), &tmp_rcx, (addr_t *)&(core->ctrl_regs.rflags));
+#ifdef __V3_64BIT__
+ } else if (op_size == 8) {
+ stos64((addr_t *)&dst_addr, (addr_t *)&(core->vm_regs.rax), &tmp_rcx, (addr_t *)&(core->ctrl_regs.rflags));
+#endif
+ } else {
+ PrintError(core->vm_info, core, "Invalid operand length\n");
+ return -1;
+ }
+
+
+
+ if (flags_reg->df == 0) {
+ core->vm_regs.rdi += emulation_length;
+ } else {
+ core->vm_regs.rdi -= emulation_length;
+ }
+
+ // RCX is only modified if the rep prefix is present
+ if (instr->prefixes.rep == 1) {
+ core->vm_regs.rcx -= rep_cnt;
+ }
+ } else {
+ PrintError(core->vm_info, core, "Unimplemented String operation\n");
+ return -1;
+ }
+
+ return emulation_length;
}
-// 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);
- }
-
-#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(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++;
- }
+int v3_emulate(struct guest_info * core, struct x86_instr * instr,
+ int mem_op_size, addr_t mem_hva_src, addr_t mem_hva_dst) {
- // 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;
-}
+ addr_t src_hva = 0;
+ addr_t dst_hva = 0;
+ if (instr->src_operand.type == MEM_OPERAND) {
+ src_hva = mem_hva_src;
+ } else if (instr->src_operand.type == REG_OPERAND) {
+ src_hva = instr->src_operand.operand;
+ } else {
+ src_hva = (addr_t)&(instr->src_operand.operand);
+ }
-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) {
+ if (instr->dst_operand.type == MEM_OPERAND) {
+ dst_hva = mem_hva_dst;
+ } else if (instr->dst_operand.type == REG_OPERAND) {
+ dst_hva = instr->dst_operand.operand;
+ } else {
+ dst_hva = (addr_t)&(instr->dst_operand.operand);
+ }
+
- 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;
- int i;
+ if (instr->is_str_op == 0) {
+ int src_op_len = instr->src_operand.size;
+ int dst_op_len = instr->dst_operand.size;
+
+ run_op(core, instr->op_type, src_hva, dst_hva, src_op_len, dst_op_len);
- PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip);
+ return dst_op_len;
+ } else {
+ // String Operation
+ int rep_cnt = 0;
- 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);
- }
+ /* Both src and dst operand sizes should be identical */
+ rep_cnt = mem_op_size / instr->src_operand.size;
+ return run_str_op(core, instr, src_hva, dst_hva, instr->src_operand.size, rep_cnt);
+ }
- 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(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 *)(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;
}