1 /* Northwestern University */
2 /* (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> */
4 #include <palacios/vmm.h>
5 #include <palacios/vmm_emulator.h>
6 #include <palacios/vm_guest_mem.h>
7 #include <palacios/vmm_decoder.h>
8 #include <palacios/vmm_debug.h>
9 #include <palacios/vmcb.h>
10 #include <palacios/vmm_ctrl_regs.h>
12 static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
14 #ifndef DEBUG_EMULATOR
16 #define PrintDebug(fmt, args...)
20 int init_emulator(struct guest_info * info) {
21 struct emulation_state * emulator = &(info->emulator);
23 emulator->num_emulated_pages = 0;
24 INIT_LIST_HEAD(&(emulator->emulated_pages));
27 emulator->num_saved_pages = 0;
28 INIT_LIST_HEAD(&(emulator->saved_pages));
30 emulator->num_write_regions = 0;
31 INIT_LIST_HEAD(&(emulator->write_regions));
33 emulator->running = 0;
34 emulator->instr_length = 0;
36 emulator->tf_enabled = 0;
41 static addr_t get_new_page() {
42 void * page = V3_AllocPages(1);
43 memset(page, 0, PAGE_SIZE);
49 static int setup_code_page(struct guest_info * info, char * instr, struct basic_instr_info * instr_info ) {
50 addr_t code_page_offset = PT32_PAGE_OFFSET(info->rip);
51 addr_t code_page = get_new_page();
52 struct emulated_page * new_code_page = V3_Malloc(sizeof(struct emulated_page));
53 struct saved_page * saved_code_page = V3_Malloc(sizeof(struct saved_page));
56 saved_code_page->va = PT32_PAGE_ADDR(info->rip);
58 new_code_page->page_addr = code_page;
59 new_code_page->va = PT32_PAGE_ADDR(info->rip);
61 new_code_page->pte.present = 1;
62 new_code_page->pte.writable = 0;
63 new_code_page->pte.user_page = 1;
64 new_code_page->pte.page_base_addr = PT32_BASE_ADDR(code_page);
66 memcpy((void *)(code_page + code_page_offset), instr, instr_info->instr_length);
67 memcpy((void *)(code_page + code_page_offset + instr_info->instr_length), VMMCALL, 3);
70 PrintDebug("New Instr Stream:\n");
71 PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
72 PrintDebug("rip =%x\n", info->rip);
77 v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte));
80 list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages));
81 info->emulator.num_emulated_pages++;
83 list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages));
84 info->emulator.num_saved_pages++;
91 static int set_stepping(struct guest_info * info) {
92 vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
93 ctrl_area->exceptions.db = 1;
95 info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf;
97 ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1;
103 static int unset_stepping(struct guest_info * info) {
104 vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
105 ctrl_area->exceptions.db = 0;
107 ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled;
109 if (info->emulator.tf_enabled) {
110 // Inject breakpoint exception into guest
118 // get the current instr
119 // check if rep + remove
120 // put into new page, vmexit after
121 // replace new page with current eip page
123 int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva,
124 int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data),
125 addr_t read_gpa, void * private_data) {
126 struct basic_instr_info instr_info;
129 struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
130 addr_t data_addr_offset = PT32_PAGE_OFFSET(read_gva);
133 PrintDebug("Emulating Read\n");
135 if (info->mem_mode == PHYSICAL_MEM) {
136 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
138 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
141 #ifdef DEBUG_EMULATOR
142 PrintDebug("Instr (15 bytes) at %x:\n", instr);
143 PrintTraceMemDump(instr, 15);
147 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
148 PrintError("Could not do a basic memory instruction decode\n");
154 if (instr_info.has_rep == 1) {
155 PrintError("We currently don't handle rep* instructions\n");
161 data_page->page_addr = get_new_page();
162 data_page->va = PT32_PAGE_ADDR(read_gva);
163 data_page->pte.present = 1;
164 data_page->pte.writable = 0;
165 data_page->pte.user_page = 1;
166 data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
169 // Read the data directly onto the emulated page
170 if (read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data) != instr_info.op_size) {
171 PrintError("Read error in emulator\n");
172 V3_FreePage((void *)(data_page->page_addr));
177 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
180 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
181 info->emulator.num_emulated_pages++;
183 if (saved_pte.present == 1) {
184 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
185 saved_data_page->pte = saved_pte;
186 saved_data_page->va = PT32_PAGE_ADDR(read_gva);
188 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
189 info->emulator.num_saved_pages++;
193 // setup_code_page(info, instr, &instr_info);
196 info->emulator.running = 1;
197 info->run_state = VM_EMULATING;
198 info->emulator.instr_length = instr_info.instr_length;
205 int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
206 int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data),
207 addr_t write_gpa, void * private_data) {
209 struct basic_instr_info instr_info;
212 struct write_region * write_op = V3_Malloc(sizeof(struct write_region ));
213 struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
214 addr_t data_addr_offset = PT32_PAGE_OFFSET(write_gva);
218 PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip);
220 if (info->mem_mode == PHYSICAL_MEM) {
221 ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
223 ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
227 PrintDebug("Instruction is");
228 for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); }
231 if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
232 PrintError("Could not do a basic memory instruction decode\n");
238 if (instr_info.has_rep==1) {
239 PrintDebug("Emulated instruction has rep\n");
243 if (instr_info.has_rep == 1) {
244 PrintError("We currently don't handle rep* instructions\n");
251 data_page->page_addr = get_new_page();
252 data_page->va = PT32_PAGE_ADDR(write_gva);
253 data_page->pte.present = 1;
254 data_page->pte.writable = 1;
255 data_page->pte.user_page = 1;
256 data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
260 write_op->write = write;
261 write_op->write_addr = write_gpa;
262 write_op->length = instr_info.op_size;
263 write_op->private_data = private_data;
265 write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
267 list_add(&(write_op->write_list), &(info->emulator.write_regions));
268 info->emulator.num_write_regions--;
270 v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
273 list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
274 info->emulator.num_emulated_pages++;
276 if (saved_pte.present == 1) {
277 struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
278 saved_data_page->pte = saved_pte;
279 saved_data_page->va = PT32_PAGE_ADDR(write_gva);
281 list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
282 info->emulator.num_saved_pages++;
286 if (info->emulator.running == 0) {
287 // setup_code_page(info, instr, &instr_info);
289 info->emulator.running = 1;
290 info->run_state = VM_EMULATING;
291 info->emulator.instr_length = instr_info.instr_length;
299 int v3_emulation_exit_handler(struct guest_info * info) {
300 struct saved_page * svpg, * p_svpg;
301 struct emulated_page * empg, * p_empg;
302 struct write_region * wr_reg, * p_wr_reg;
305 // Complete the writes
307 // swap out emulated pages with blank dummies
308 // swap in saved pages
311 PrintDebug("V3 Emulation Exit Handler\n");
313 list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) {
314 wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data);
315 PrintDebug("Writing \n");
317 list_del(&(wr_reg->write_list));
321 info->emulator.num_write_regions = 0;
324 *(uint_t *)&dummy_pte = 0;
326 list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
329 PrintDebug("wiping page %x\n", empg->va);
331 v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
332 V3_FreePage((void *)(empg->page_addr));
334 list_del(&(empg->page_list));
337 info->emulator.num_emulated_pages = 0;
339 list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
341 PrintDebug("Setting Saved page %x back\n", svpg->va);
342 v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
344 list_del(&(svpg->page_list));
347 info->emulator.num_saved_pages = 0;
349 info->run_state = VM_RUNNING;
350 info->emulator.running = 0;
351 //info->rip += info->emulator.instr_length;
354 PrintDebug("Returning to rip: 0x%x\n", info->rip);
356 info->emulator.instr_length = 0;
359 unset_stepping(info);
362 PrintDebug("returning from emulation\n");