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.


added copyright tags
[palacios.git] / palacios / src / palacios / vmm_emulator.c
1 /* Northwestern University */
2 /* (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> */
3
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>
11
12 static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
13
14 #ifndef DEBUG_EMULATOR
15 #undef PrintDebug
16 #define PrintDebug(fmt, args...)
17 #endif
18
19
20 int init_emulator(struct guest_info * info) {
21   struct emulation_state * emulator = &(info->emulator);
22
23   emulator->num_emulated_pages = 0;
24   INIT_LIST_HEAD(&(emulator->emulated_pages));
25
26
27   emulator->num_saved_pages = 0;
28   INIT_LIST_HEAD(&(emulator->saved_pages));
29   
30   emulator->num_write_regions = 0;
31   INIT_LIST_HEAD(&(emulator->write_regions));
32
33   emulator->running = 0;
34   emulator->instr_length = 0;
35
36   emulator->tf_enabled = 0;
37
38   return 0;
39 }
40
41 static addr_t get_new_page() {
42   void * page = V3_AllocPages(1);
43   memset(page, 0, PAGE_SIZE);
44
45   return (addr_t)page;
46 }
47
48 /*
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));
54
55
56   saved_code_page->va = PT32_PAGE_ADDR(info->rip);
57
58   new_code_page->page_addr = code_page; 
59   new_code_page->va = PT32_PAGE_ADDR(info->rip);
60
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);
65
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);
68
69 #ifdef DEBUG_EMULATOR
70   PrintDebug("New Instr Stream:\n");
71   PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
72   PrintDebug("rip =%x\n", info->rip);
73 #endif
74
75
76
77   v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte));
78
79
80   list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages));
81   info->emulator.num_emulated_pages++;
82
83   list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages));
84   info->emulator.num_saved_pages++;
85
86   return 0;
87 }
88 */
89
90
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;
94
95   info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf;
96
97   ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1;
98
99   return 0;
100 }
101
102
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;
106
107   ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled;
108
109   if (info->emulator.tf_enabled) {
110     // Inject breakpoint exception into guest
111   }
112
113   return 0;
114
115 }
116
117
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
122 // 
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;
127   char instr[15];
128   int ret;
129   struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
130   addr_t data_addr_offset = PT32_PAGE_OFFSET(read_gva);
131   pte32_t saved_pte;
132
133   PrintDebug("Emulating Read\n");
134
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);
137   } else { 
138     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
139   }
140
141 #ifdef DEBUG_EMULATOR
142   PrintDebug("Instr (15 bytes) at %x:\n", instr);
143   PrintTraceMemDump(instr, 15);
144 #endif  
145
146
147   if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
148     PrintError("Could not do a basic memory instruction decode\n");
149     V3_Free(data_page);
150     return -1;
151   }
152
153   /*
154   if (instr_info.has_rep == 1) {
155     PrintError("We currently don't handle rep* instructions\n");
156     V3_Free(data_page);
157     return -1;
158   }
159   */
160
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);
167
168
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));
173     V3_Free(data_page);
174     return -1;
175   }
176
177   v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
178
179
180   list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
181   info->emulator.num_emulated_pages++;
182
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);
187
188     list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
189     info->emulator.num_saved_pages++;
190   }
191
192
193   // setup_code_page(info, instr, &instr_info);
194   set_stepping(info);
195
196   info->emulator.running = 1;
197   info->run_state = VM_EMULATING;
198   info->emulator.instr_length = instr_info.instr_length;
199
200   return 0;
201 }
202
203
204
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) {
208
209   struct basic_instr_info instr_info;
210   char instr[15];
211   int ret;
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);
215   pte32_t saved_pte;
216   int i;
217
218   PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip);
219
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);
222   } else { 
223     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
224   }
225
226
227   PrintDebug("Instruction is");
228   for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); } 
229   PrintDebug("\n");
230   
231   if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
232     PrintError("Could not do a basic memory instruction decode\n");
233     V3_Free(write_op);
234     V3_Free(data_page);
235     return -1;
236   }
237
238   if (instr_info.has_rep==1) { 
239     PrintDebug("Emulated instruction has rep\n");
240   }
241
242   /*
243   if (instr_info.has_rep == 1) {
244     PrintError("We currently don't handle rep* instructions\n");
245     V3_Free(write_op);
246     V3_Free(data_page);
247     return -1;
248   }
249   */
250
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);
257
258
259
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;
264
265   write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
266
267   list_add(&(write_op->write_list), &(info->emulator.write_regions));
268   info->emulator.num_write_regions--;
269
270   v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
271
272
273   list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
274   info->emulator.num_emulated_pages++;
275
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);
280
281     list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
282     info->emulator.num_saved_pages++;
283   }
284
285
286   if (info->emulator.running == 0) {
287     //    setup_code_page(info, instr, &instr_info);
288     set_stepping(info);
289     info->emulator.running = 1;
290     info->run_state = VM_EMULATING;
291     info->emulator.instr_length = instr_info.instr_length;
292   }
293
294   return 0;
295 }
296
297
298 // end emulation
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;
303   pte32_t dummy_pte;
304
305   // Complete the writes
306   // delete writes
307   // swap out emulated pages with blank dummies
308   // swap in saved pages
309   // increment rip
310   
311   PrintDebug("V3 Emulation Exit Handler\n");
312
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");
316     
317     list_del(&(wr_reg->write_list));
318     V3_Free(wr_reg);
319
320   }
321   info->emulator.num_write_regions = 0;
322
323
324   *(uint_t *)&dummy_pte = 0;
325   
326   list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
327     pte32_t empte32_t;
328
329     PrintDebug("wiping page %x\n", empg->va); 
330
331     v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
332     V3_FreePage((void *)(empg->page_addr));
333
334     list_del(&(empg->page_list));
335     V3_Free(empg);
336   }
337   info->emulator.num_emulated_pages = 0;
338
339   list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
340
341     PrintDebug("Setting Saved page %x back\n", svpg->va); 
342     v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
343     
344     list_del(&(svpg->page_list));
345     V3_Free(svpg);
346   }
347   info->emulator.num_saved_pages = 0;
348
349   info->run_state = VM_RUNNING;
350   info->emulator.running = 0;
351   //info->rip += info->emulator.instr_length;
352
353
354   PrintDebug("Returning to rip: 0x%x\n", info->rip);
355
356   info->emulator.instr_length = 0;
357   
358   
359   unset_stepping(info);
360
361
362   PrintDebug("returning from emulation\n");
363
364   return 0;
365 }