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 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_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);
157 #ifdef DEBUG_EMULATOR
158 PrintDebug("Instr (15 bytes) at %x:\n", instr);
159 PrintTraceMemDump(instr, 15);
163 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
164 PrintError("Could not do a basic memory instruction decode\n");
170 if (instr_info.has_rep == 1) {
171 PrintError("We currently don't handle rep* instructions\n");
177 data_page->page_addr = get_new_page();
178 data_page->va = PT32_PAGE_ADDR(read_gva);
179 data_page->pte.present = 1;
180 data_page->pte.writable = 0;
181 data_page->pte.user_page = 1;
182 data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
185 // Read the data directly onto the emulated page
186 if (read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data) != instr_info.op_size) {
187 PrintError("Read error in emulator\n");
188 V3_FreePage((void *)(data_page->page_addr));
193 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
196 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
197 info->emulator.num_emulated_pages++;
199 if (saved_pte.present == 1) {
200 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
201 saved_data_page->pte = saved_pte;
202 saved_data_page->va = PT32_PAGE_ADDR(read_gva);
204 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
205 info->emulator.num_saved_pages++;
209 // setup_code_page(info, instr, &instr_info);
212 info->emulator.running = 1;
213 info->run_state = VM_EMULATING;
214 info->emulator.instr_length = instr_info.instr_length;
221 int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
222 int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data),
223 addr_t write_gpa, void * private_data) {
225 struct basic_instr_info instr_info;
228 struct write_region * write_op = V3_Malloc(sizeof(struct write_region ));
229 struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
230 addr_t data_addr_offset = PT32_PAGE_OFFSET(write_gva);
234 PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip);
236 if (info->mem_mode == PHYSICAL_MEM) {
237 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
239 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
243 PrintDebug("Instruction is");
244 for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); }
247 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
248 PrintError("Could not do a basic memory instruction decode\n");
254 if (instr_info.has_rep==1) {
255 PrintDebug("Emulated instruction has rep\n");
259 if (instr_info.has_rep == 1) {
260 PrintError("We currently don't handle rep* instructions\n");
267 data_page->page_addr = get_new_page();
268 data_page->va = PT32_PAGE_ADDR(write_gva);
269 data_page->pte.present = 1;
270 data_page->pte.writable = 1;
271 data_page->pte.user_page = 1;
272 data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
276 write_op->write = write;
277 write_op->write_addr = write_gpa;
278 write_op->length = instr_info.op_size;
279 write_op->private_data = private_data;
281 write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
283 list_add(&(write_op->write_list), &(info->emulator.write_regions));
284 info->emulator.num_write_regions--;
286 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
289 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
290 info->emulator.num_emulated_pages++;
292 if (saved_pte.present == 1) {
293 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
294 saved_data_page->pte = saved_pte;
295 saved_data_page->va = PT32_PAGE_ADDR(write_gva);
297 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
298 info->emulator.num_saved_pages++;
302 if (info->emulator.running == 0) {
303 // setup_code_page(info, instr, &instr_info);
305 info->emulator.running = 1;
306 info->run_state = VM_EMULATING;
307 info->emulator.instr_length = instr_info.instr_length;
315 int v3_emulation_exit_handler(struct guest_info * info) {
316 struct saved_page * svpg, * p_svpg;
317 struct emulated_page * empg, * p_empg;
318 struct write_region * wr_reg, * p_wr_reg;
321 // Complete the writes
323 // swap out emulated pages with blank dummies
324 // swap in saved pages
327 PrintDebug("V3 Emulation Exit Handler\n");
329 list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) {
330 wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data);
331 PrintDebug("Writing \n");
333 list_del(&(wr_reg->write_list));
337 info->emulator.num_write_regions = 0;
340 *(uint_t *)&dummy_pte = 0;
342 list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
345 PrintDebug("wiping page %x\n", empg->va);
347 v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
348 V3_FreePage((void *)(empg->page_addr));
350 list_del(&(empg->page_list));
353 info->emulator.num_emulated_pages = 0;
355 list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
357 PrintDebug("Setting Saved page %x back\n", svpg->va);
358 v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
360 list_del(&(svpg->page_list));
363 info->emulator.num_saved_pages = 0;
365 info->run_state = VM_RUNNING;
366 info->emulator.running = 0;
367 //info->rip += info->emulator.instr_length;
370 PrintDebug("Returning to rip: 0x%x\n", info->rip);
372 info->emulator.instr_length = 0;
375 unset_stepping(info);
378 PrintDebug("returning from emulation\n");