1 /* (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> */
2 /* (c) 2008, The V3VEE Project <http://www.v3vee.org> */
5 #include <palacios/vmm.h>
6 #include <palacios/vmm_emulator.h>
7 #include <palacios/vm_guest_mem.h>
8 #include <palacios/vmm_decoder.h>
9 #include <palacios/vmm_debug.h>
10 #include <palacios/vmcb.h>
11 #include <palacios/vmm_ctrl_regs.h>
13 static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
15 #ifndef DEBUG_EMULATOR
17 #define PrintDebug(fmt, args...)
21 int init_emulator(struct guest_info * info) {
22 struct emulation_state * emulator = &(info->emulator);
24 emulator->num_emulated_pages = 0;
25 INIT_LIST_HEAD(&(emulator->emulated_pages));
28 emulator->num_saved_pages = 0;
29 INIT_LIST_HEAD(&(emulator->saved_pages));
31 emulator->num_write_regions = 0;
32 INIT_LIST_HEAD(&(emulator->write_regions));
34 emulator->running = 0;
35 emulator->instr_length = 0;
37 emulator->tf_enabled = 0;
42 static addr_t get_new_page() {
43 void * page = V3_AllocPages(1);
44 memset(page, 0, PAGE_SIZE);
50 static int setup_code_page(struct guest_info * info, char * instr, struct basic_instr_info * instr_info ) {
51 addr_t code_page_offset = PT32_PAGE_OFFSET(info->rip);
52 addr_t code_page = get_new_page();
53 struct emulated_page * new_code_page = V3_Malloc(sizeof(struct emulated_page));
54 struct saved_page * saved_code_page = V3_Malloc(sizeof(struct saved_page));
57 saved_code_page->va = PT32_PAGE_ADDR(info->rip);
59 new_code_page->page_addr = code_page;
60 new_code_page->va = PT32_PAGE_ADDR(info->rip);
62 new_code_page->pte.present = 1;
63 new_code_page->pte.writable = 0;
64 new_code_page->pte.user_page = 1;
65 new_code_page->pte.page_base_addr = PT32_BASE_ADDR(code_page);
67 memcpy((void *)(code_page + code_page_offset), instr, instr_info->instr_length);
68 memcpy((void *)(code_page + code_page_offset + instr_info->instr_length), VMMCALL, 3);
71 PrintDebug("New Instr Stream:\n");
72 PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
73 PrintDebug("rip =%x\n", info->rip);
78 v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte));
81 list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages));
82 info->emulator.num_emulated_pages++;
84 list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages));
85 info->emulator.num_saved_pages++;
92 static int set_stepping(struct guest_info * info) {
93 vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
94 ctrl_area->exceptions.db = 1;
96 info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf;
98 ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1;
104 static int unset_stepping(struct guest_info * info) {
105 vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
106 ctrl_area->exceptions.db = 0;
108 ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled;
110 if (info->emulator.tf_enabled) {
111 // Inject breakpoint exception into guest
119 // get the current instr
120 // check if rep + remove
121 // put into new page, vmexit after
122 // replace new page with current eip page
124 int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva,
125 int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data),
126 addr_t read_gpa, void * private_data) {
127 struct basic_instr_info instr_info;
130 struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
131 addr_t data_addr_offset = PT32_PAGE_OFFSET(read_gva);
134 PrintDebug("Emulating Read\n");
136 if (info->mem_mode == PHYSICAL_MEM) {
137 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
139 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
142 #ifdef DEBUG_EMULATOR
143 PrintDebug("Instr (15 bytes) at %x:\n", instr);
144 PrintTraceMemDump(instr, 15);
148 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
149 PrintError("Could not do a basic memory instruction decode\n");
155 if (instr_info.has_rep == 1) {
156 PrintError("We currently don't handle rep* instructions\n");
162 data_page->page_addr = get_new_page();
163 data_page->va = PT32_PAGE_ADDR(read_gva);
164 data_page->pte.present = 1;
165 data_page->pte.writable = 0;
166 data_page->pte.user_page = 1;
167 data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
170 // Read the data directly onto the emulated page
171 if (read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data) != instr_info.op_size) {
172 PrintError("Read error in emulator\n");
173 V3_FreePage((void *)(data_page->page_addr));
178 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
181 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
182 info->emulator.num_emulated_pages++;
184 if (saved_pte.present == 1) {
185 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
186 saved_data_page->pte = saved_pte;
187 saved_data_page->va = PT32_PAGE_ADDR(read_gva);
189 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
190 info->emulator.num_saved_pages++;
194 // setup_code_page(info, instr, &instr_info);
197 info->emulator.running = 1;
198 info->run_state = VM_EMULATING;
199 info->emulator.instr_length = instr_info.instr_length;
206 int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
207 int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data),
208 addr_t write_gpa, void * private_data) {
210 struct basic_instr_info instr_info;
213 struct write_region * write_op = V3_Malloc(sizeof(struct write_region ));
214 struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
215 addr_t data_addr_offset = PT32_PAGE_OFFSET(write_gva);
219 PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip);
221 if (info->mem_mode == PHYSICAL_MEM) {
222 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
224 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
228 PrintDebug("Instruction is");
229 for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); }
232 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
233 PrintError("Could not do a basic memory instruction decode\n");
239 if (instr_info.has_rep==1) {
240 PrintDebug("Emulated instruction has rep\n");
244 if (instr_info.has_rep == 1) {
245 PrintError("We currently don't handle rep* instructions\n");
252 data_page->page_addr = get_new_page();
253 data_page->va = PT32_PAGE_ADDR(write_gva);
254 data_page->pte.present = 1;
255 data_page->pte.writable = 1;
256 data_page->pte.user_page = 1;
257 data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
261 write_op->write = write;
262 write_op->write_addr = write_gpa;
263 write_op->length = instr_info.op_size;
264 write_op->private_data = private_data;
266 write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
268 list_add(&(write_op->write_list), &(info->emulator.write_regions));
269 info->emulator.num_write_regions--;
271 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
274 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
275 info->emulator.num_emulated_pages++;
277 if (saved_pte.present == 1) {
278 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
279 saved_data_page->pte = saved_pte;
280 saved_data_page->va = PT32_PAGE_ADDR(write_gva);
282 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
283 info->emulator.num_saved_pages++;
287 if (info->emulator.running == 0) {
288 // setup_code_page(info, instr, &instr_info);
290 info->emulator.running = 1;
291 info->run_state = VM_EMULATING;
292 info->emulator.instr_length = instr_info.instr_length;
300 int v3_emulation_exit_handler(struct guest_info * info) {
301 struct saved_page * svpg, * p_svpg;
302 struct emulated_page * empg, * p_empg;
303 struct write_region * wr_reg, * p_wr_reg;
306 // Complete the writes
308 // swap out emulated pages with blank dummies
309 // swap in saved pages
312 PrintDebug("V3 Emulation Exit Handler\n");
314 list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) {
315 wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data);
316 PrintDebug("Writing \n");
318 list_del(&(wr_reg->write_list));
322 info->emulator.num_write_regions = 0;
325 *(uint_t *)&dummy_pte = 0;
327 list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
330 PrintDebug("wiping page %x\n", empg->va);
332 v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
333 V3_FreePage((void *)(empg->page_addr));
335 list_del(&(empg->page_list));
338 info->emulator.num_emulated_pages = 0;
340 list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
342 PrintDebug("Setting Saved page %x back\n", svpg->va);
343 v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
345 list_del(&(svpg->page_list));
348 info->emulator.num_saved_pages = 0;
350 info->run_state = VM_RUNNING;
351 info->emulator.running = 0;
352 //info->rip += info->emulator.instr_length;
355 PrintDebug("Returning to rip: 0x%x\n", info->rip);
357 info->emulator.instr_length = 0;
360 unset_stepping(info);
363 PrintDebug("returning from emulation\n");