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.


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