2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_emulator.h>
22 #include <palacios/vm_guest_mem.h>
23 #include <palacios/vmm_decoder.h>
24 #include <palacios/vmm_debug.h>
25 #include <palacios/vmcb.h>
26 #include <palacios/vmm_ctrl_regs.h>
28 static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
30 #ifndef DEBUG_EMULATOR
32 #define PrintDebug(fmt, args...)
36 int v3_init_emulator(struct guest_info * info) {
37 struct emulation_state * emulator = &(info->emulator);
39 emulator->num_emulated_pages = 0;
40 INIT_LIST_HEAD(&(emulator->emulated_pages));
43 emulator->num_saved_pages = 0;
44 INIT_LIST_HEAD(&(emulator->saved_pages));
46 emulator->num_write_regions = 0;
47 INIT_LIST_HEAD(&(emulator->write_regions));
49 emulator->running = 0;
50 emulator->instr_length = 0;
52 emulator->tf_enabled = 0;
57 static addr_t get_new_page() {
58 void * page = V3_VAddr(V3_AllocPages(1));
59 memset(page, 0, PAGE_SIZE);
65 static int setup_code_page(struct guest_info * info, char * instr, struct basic_instr_info * instr_info ) {
66 addr_t code_page_offset = PT32_PAGE_OFFSET(info->rip);
67 addr_t code_page = get_new_page();
68 struct emulated_page * new_code_page = V3_Malloc(sizeof(struct emulated_page));
69 struct saved_page * saved_code_page = V3_Malloc(sizeof(struct saved_page));
72 saved_code_page->va = PT32_PAGE_ADDR(info->rip);
74 new_code_page->page_addr = code_page;
75 new_code_page->va = PT32_PAGE_ADDR(info->rip);
77 new_code_page->pte.present = 1;
78 new_code_page->pte.writable = 0;
79 new_code_page->pte.user_page = 1;
80 new_code_page->pte.page_base_addr = PT32_BASE_ADDR(code_page);
82 memcpy((void *)(code_page + code_page_offset), instr, instr_info->instr_length);
83 memcpy((void *)(code_page + code_page_offset + instr_info->instr_length), VMMCALL, 3);
86 PrintDebug("New Instr Stream:\n");
87 PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
88 PrintDebug("rip =%x\n", info->rip);
93 v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte));
96 list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages));
97 info->emulator.num_emulated_pages++;
99 list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages));
100 info->emulator.num_saved_pages++;
107 static int set_stepping(struct guest_info * info) {
108 vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
109 ctrl_area->exceptions.db = 1;
111 info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf;
113 ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1;
119 static int unset_stepping(struct guest_info * info) {
120 vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
121 ctrl_area->exceptions.db = 0;
123 ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled;
125 if (info->emulator.tf_enabled) {
126 // Inject breakpoint exception into guest
134 // get the current instr
135 // check if rep + remove
136 // put into new page, vmexit after
137 // replace new page with current eip page
139 int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva,
140 int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data),
141 addr_t read_gpa, void * private_data) {
142 struct basic_instr_info instr_info;
145 struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
146 addr_t data_addr_offset = PT32_PAGE_OFFSET(read_gva);
149 PrintDebug("Emulating Read\n");
151 if (info->mem_mode == PHYSICAL_MEM) {
152 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
154 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
158 PrintError("Could not read guest memory\n");
162 #ifdef DEBUG_EMULATOR
163 PrintDebug("Instr (15 bytes) at %x:\n", instr);
164 PrintTraceMemDump(instr, 15);
168 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
169 PrintError("Could not do a basic memory instruction decode\n");
175 if (instr_info.has_rep == 1) {
176 PrintError("We currently don't handle rep* instructions\n");
182 data_page->page_addr = get_new_page();
183 data_page->va = PT32_PAGE_ADDR(read_gva);
184 data_page->pte.present = 1;
185 data_page->pte.writable = 0;
186 data_page->pte.user_page = 1;
187 data_page->pte.page_base_addr = PT32_BASE_ADDR((addr_t)V3_PAddr((void *)(addr_t)(data_page->page_addr)));
190 // Read the data directly onto the emulated page
191 ret = read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data);
192 if ((ret == -1) || ((uint_t)ret != instr_info.op_size)) {
193 PrintError("Read error in emulator\n");
194 V3_FreePage((void *)V3_PAddr((void *)(data_page->page_addr)));
199 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
202 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
203 info->emulator.num_emulated_pages++;
205 if (saved_pte.present == 1) {
206 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
207 saved_data_page->pte = saved_pte;
208 saved_data_page->va = PT32_PAGE_ADDR(read_gva);
210 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
211 info->emulator.num_saved_pages++;
215 // setup_code_page(info, instr, &instr_info);
218 info->emulator.running = 1;
219 info->run_state = VM_EMULATING;
220 info->emulator.instr_length = instr_info.instr_length;
227 int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
228 int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data),
229 addr_t write_gpa, void * private_data) {
231 struct basic_instr_info instr_info;
234 struct write_region * write_op = V3_Malloc(sizeof(struct write_region ));
235 struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
236 addr_t data_addr_offset = PT32_PAGE_OFFSET(write_gva);
240 PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip);
242 if (info->mem_mode == PHYSICAL_MEM) {
243 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
245 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
249 PrintDebug("Instruction is");
250 for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); }
253 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
254 PrintError("Could not do a basic memory instruction decode\n");
260 if (instr_info.has_rep==1) {
261 PrintDebug("Emulated instruction has rep\n");
265 if (instr_info.has_rep == 1) {
266 PrintError("We currently don't handle rep* instructions\n");
273 data_page->page_addr = get_new_page();
274 data_page->va = PT32_PAGE_ADDR(write_gva);
275 data_page->pte.present = 1;
276 data_page->pte.writable = 1;
277 data_page->pte.user_page = 1;
278 data_page->pte.page_base_addr = PT32_BASE_ADDR((addr_t)V3_PAddr((void *)(addr_t)(data_page->page_addr)));
282 write_op->write = write;
283 write_op->write_addr = write_gpa;
284 write_op->length = instr_info.op_size;
285 write_op->private_data = private_data;
287 write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
289 list_add(&(write_op->write_list), &(info->emulator.write_regions));
290 info->emulator.num_write_regions--;
292 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
295 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
296 info->emulator.num_emulated_pages++;
298 if (saved_pte.present == 1) {
299 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
300 saved_data_page->pte = saved_pte;
301 saved_data_page->va = PT32_PAGE_ADDR(write_gva);
303 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
304 info->emulator.num_saved_pages++;
308 if (info->emulator.running == 0) {
309 // setup_code_page(info, instr, &instr_info);
311 info->emulator.running = 1;
312 info->run_state = VM_EMULATING;
313 info->emulator.instr_length = instr_info.instr_length;
321 int v3_emulation_exit_handler(struct guest_info * info) {
322 struct saved_page * svpg, * p_svpg;
323 struct emulated_page * empg, * p_empg;
324 struct write_region * wr_reg, * p_wr_reg;
327 // Complete the writes
329 // swap out emulated pages with blank dummies
330 // swap in saved pages
333 PrintDebug("V3 Emulation Exit Handler\n");
335 list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) {
336 wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data);
337 PrintDebug("Writing \n");
339 list_del(&(wr_reg->write_list));
343 info->emulator.num_write_regions = 0;
346 *(uint_t *)&dummy_pte = 0;
348 list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
351 PrintDebug("wiping page %x\n", empg->va);
353 v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
354 V3_FreePage((void *)(V3_PAddr((void *)(empg->page_addr))));
356 list_del(&(empg->page_list));
359 info->emulator.num_emulated_pages = 0;
361 list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
363 PrintDebug("Setting Saved page %x back\n", svpg->va);
364 v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
366 list_del(&(svpg->page_list));
369 info->emulator.num_saved_pages = 0;
371 info->run_state = VM_RUNNING;
372 info->emulator.running = 0;
373 //info->rip += info->emulator.instr_length;
376 PrintDebug("Returning to rip: 0x%x\n", info->rip);
378 info->emulator.instr_length = 0;
381 unset_stepping(info);
384 PrintDebug("returning from emulation\n");