Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / palacios / src / palacios / vmm_emulator.c
1 /* 
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.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
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.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
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>
27
28 static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
29
30 #ifndef DEBUG_EMULATOR
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35
36 int v3_init_emulator(struct guest_info * info) {
37   struct emulation_state * emulator = &(info->emulator);
38
39   emulator->num_emulated_pages = 0;
40   INIT_LIST_HEAD(&(emulator->emulated_pages));
41
42
43   emulator->num_saved_pages = 0;
44   INIT_LIST_HEAD(&(emulator->saved_pages));
45   
46   emulator->num_write_regions = 0;
47   INIT_LIST_HEAD(&(emulator->write_regions));
48
49   emulator->running = 0;
50   emulator->instr_length = 0;
51
52   emulator->tf_enabled = 0;
53
54   return 0;
55 }
56
57 static addr_t get_new_page() {
58   void * page = V3_VAddr(V3_AllocPages(1));
59   memset(page, 0, PAGE_SIZE);
60
61   return (addr_t)page;
62 }
63
64 /*
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));
70
71
72   saved_code_page->va = PT32_PAGE_ADDR(info->rip);
73
74   new_code_page->page_addr = code_page; 
75   new_code_page->va = PT32_PAGE_ADDR(info->rip);
76
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);
81
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);
84
85 #ifdef DEBUG_EMULATOR
86   PrintDebug("New Instr Stream:\n");
87   PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
88   PrintDebug("rip =%x\n", info->rip);
89 #endif
90
91
92
93   v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte));
94
95
96   list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages));
97   info->emulator.num_emulated_pages++;
98
99   list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages));
100   info->emulator.num_saved_pages++;
101
102   return 0;
103 }
104 */
105
106
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;
110
111   info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf;
112
113   ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1;
114
115   return 0;
116 }
117
118
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;
122
123   ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled;
124
125   if (info->emulator.tf_enabled) {
126     // Inject breakpoint exception into guest
127   }
128
129   return 0;
130
131 }
132
133
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
138 // 
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;
143   uchar_t instr[15];
144   int ret;
145   struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
146   addr_t data_addr_offset = PT32_PAGE_OFFSET(read_gva);
147   pte32_t saved_pte;
148
149   PrintDebug("Emulating Read\n");
150
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);
153   } else { 
154     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
155   }
156
157   if (ret == -1) {
158     PrintError("Could not read guest memory\n");
159     return -1;
160   }
161
162 #ifdef DEBUG_EMULATOR
163   PrintDebug("Instr (15 bytes) at %x:\n", instr);
164   PrintTraceMemDump(instr, 15);
165 #endif  
166
167
168   if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
169     PrintError("Could not do a basic memory instruction decode\n");
170     V3_Free(data_page);
171     return -1;
172   }
173
174   /*
175   if (instr_info.has_rep == 1) {
176     PrintError("We currently don't handle rep* instructions\n");
177     V3_Free(data_page);
178     return -1;
179   }
180   */
181
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)));
188
189
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)));
195     V3_Free(data_page);
196     return -1;
197   }
198
199   v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
200
201
202   list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
203   info->emulator.num_emulated_pages++;
204
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);
209
210     list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
211     info->emulator.num_saved_pages++;
212   }
213
214
215   // setup_code_page(info, instr, &instr_info);
216   set_stepping(info);
217
218   info->emulator.running = 1;
219   info->run_state = VM_EMULATING;
220   info->emulator.instr_length = instr_info.instr_length;
221
222   return 0;
223 }
224
225
226
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) {
230
231   struct basic_instr_info instr_info;
232   uchar_t instr[15];
233   int ret;
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);
237   pte32_t saved_pte;
238   int i;
239
240   PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip);
241
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);
244   } else { 
245     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
246   }
247
248
249   PrintDebug("Instruction is");
250   for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); } 
251   PrintDebug("\n");
252   
253   if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
254     PrintError("Could not do a basic memory instruction decode\n");
255     V3_Free(write_op);
256     V3_Free(data_page);
257     return -1;
258   }
259
260   if (instr_info.has_rep==1) { 
261     PrintDebug("Emulated instruction has rep\n");
262   }
263
264   /*
265   if (instr_info.has_rep == 1) {
266     PrintError("We currently don't handle rep* instructions\n");
267     V3_Free(write_op);
268     V3_Free(data_page);
269     return -1;
270   }
271   */
272
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)));
279
280
281
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;
286
287   write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
288
289   list_add(&(write_op->write_list), &(info->emulator.write_regions));
290   info->emulator.num_write_regions--;
291
292   v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
293
294
295   list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
296   info->emulator.num_emulated_pages++;
297
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);
302
303     list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
304     info->emulator.num_saved_pages++;
305   }
306
307
308   if (info->emulator.running == 0) {
309     //    setup_code_page(info, instr, &instr_info);
310     set_stepping(info);
311     info->emulator.running = 1;
312     info->run_state = VM_EMULATING;
313     info->emulator.instr_length = instr_info.instr_length;
314   }
315
316   return 0;
317 }
318
319
320 // end emulation
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;
325   pte32_t dummy_pte;
326
327   // Complete the writes
328   // delete writes
329   // swap out emulated pages with blank dummies
330   // swap in saved pages
331   // increment rip
332   
333   PrintDebug("V3 Emulation Exit Handler\n");
334
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");
338     
339     list_del(&(wr_reg->write_list));
340     V3_Free(wr_reg);
341
342   }
343   info->emulator.num_write_regions = 0;
344
345
346   *(uint_t *)&dummy_pte = 0;
347   
348   list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
349     pte32_t empte32_t;
350
351     PrintDebug("wiping page %x\n", empg->va); 
352
353     v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
354     V3_FreePage((void *)(V3_PAddr((void *)(empg->page_addr))));
355
356     list_del(&(empg->page_list));
357     V3_Free(empg);
358   }
359   info->emulator.num_emulated_pages = 0;
360
361   list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
362
363     PrintDebug("Setting Saved page %x back\n", svpg->va); 
364     v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
365     
366     list_del(&(svpg->page_list));
367     V3_Free(svpg);
368   }
369   info->emulator.num_saved_pages = 0;
370
371   info->run_state = VM_RUNNING;
372   info->emulator.running = 0;
373   //info->rip += info->emulator.instr_length;
374
375
376   PrintDebug("Returning to rip: 0x%x\n", info->rip);
377
378   info->emulator.instr_length = 0;
379   
380   
381   unset_stepping(info);
382
383
384   PrintDebug("returning from emulation\n");
385
386   return 0;
387 }