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 new copyright and license
[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 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_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   char 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 #ifdef DEBUG_EMULATOR
158   PrintDebug("Instr (15 bytes) at %x:\n", instr);
159   PrintTraceMemDump(instr, 15);
160 #endif  
161
162
163   if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
164     PrintError("Could not do a basic memory instruction decode\n");
165     V3_Free(data_page);
166     return -1;
167   }
168
169   /*
170   if (instr_info.has_rep == 1) {
171     PrintError("We currently don't handle rep* instructions\n");
172     V3_Free(data_page);
173     return -1;
174   }
175   */
176
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);
183
184
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));
189     V3_Free(data_page);
190     return -1;
191   }
192
193   v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
194
195
196   list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
197   info->emulator.num_emulated_pages++;
198
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);
203
204     list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
205     info->emulator.num_saved_pages++;
206   }
207
208
209   // setup_code_page(info, instr, &instr_info);
210   set_stepping(info);
211
212   info->emulator.running = 1;
213   info->run_state = VM_EMULATING;
214   info->emulator.instr_length = instr_info.instr_length;
215
216   return 0;
217 }
218
219
220
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) {
224
225   struct basic_instr_info instr_info;
226   char instr[15];
227   int ret;
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);
231   pte32_t saved_pte;
232   int i;
233
234   PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip);
235
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);
238   } else { 
239     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
240   }
241
242
243   PrintDebug("Instruction is");
244   for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); } 
245   PrintDebug("\n");
246   
247   if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
248     PrintError("Could not do a basic memory instruction decode\n");
249     V3_Free(write_op);
250     V3_Free(data_page);
251     return -1;
252   }
253
254   if (instr_info.has_rep==1) { 
255     PrintDebug("Emulated instruction has rep\n");
256   }
257
258   /*
259   if (instr_info.has_rep == 1) {
260     PrintError("We currently don't handle rep* instructions\n");
261     V3_Free(write_op);
262     V3_Free(data_page);
263     return -1;
264   }
265   */
266
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);
273
274
275
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;
280
281   write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
282
283   list_add(&(write_op->write_list), &(info->emulator.write_regions));
284   info->emulator.num_write_regions--;
285
286   v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
287
288
289   list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
290   info->emulator.num_emulated_pages++;
291
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);
296
297     list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
298     info->emulator.num_saved_pages++;
299   }
300
301
302   if (info->emulator.running == 0) {
303     //    setup_code_page(info, instr, &instr_info);
304     set_stepping(info);
305     info->emulator.running = 1;
306     info->run_state = VM_EMULATING;
307     info->emulator.instr_length = instr_info.instr_length;
308   }
309
310   return 0;
311 }
312
313
314 // end emulation
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;
319   pte32_t dummy_pte;
320
321   // Complete the writes
322   // delete writes
323   // swap out emulated pages with blank dummies
324   // swap in saved pages
325   // increment rip
326   
327   PrintDebug("V3 Emulation Exit Handler\n");
328
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");
332     
333     list_del(&(wr_reg->write_list));
334     V3_Free(wr_reg);
335
336   }
337   info->emulator.num_write_regions = 0;
338
339
340   *(uint_t *)&dummy_pte = 0;
341   
342   list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
343     pte32_t empte32_t;
344
345     PrintDebug("wiping page %x\n", empg->va); 
346
347     v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
348     V3_FreePage((void *)(empg->page_addr));
349
350     list_del(&(empg->page_list));
351     V3_Free(empg);
352   }
353   info->emulator.num_emulated_pages = 0;
354
355   list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
356
357     PrintDebug("Setting Saved page %x back\n", svpg->va); 
358     v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
359     
360     list_del(&(svpg->page_list));
361     V3_Free(svpg);
362   }
363   info->emulator.num_saved_pages = 0;
364
365   info->run_state = VM_RUNNING;
366   info->emulator.running = 0;
367   //info->rip += info->emulator.instr_length;
368
369
370   PrintDebug("Returning to rip: 0x%x\n", info->rip);
371
372   info->emulator.instr_length = 0;
373   
374   
375   unset_stepping(info);
376
377
378   PrintDebug("returning from emulation\n");
379
380   return 0;
381 }