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.


73a3565a562e3c41ecc706a60eeba6495b91d862
[palacios.git] / palacios / src / palacios / vmm_emulator.c
1 #include <palacios/vmm.h>
2 #include <palacios/vmm_emulator.h>
3 #include <palacios/vm_guest_mem.h>
4 #include <palacios/vmm_decoder.h>
5 #include <palacios/vmm_debug.h>
6 #include <palacios/vmcb.h>
7 #include <palacios/vmm_ctrl_regs.h>
8
9 static const char VMMCALL[3] = {0x0f, 0x01, 0xd9};
10
11 #ifndef DEBUG_EMULATOR
12 #undef PrintDebug
13 #define PrintDebug(fmt, args...)
14 #endif
15
16
17 int init_emulator(struct guest_info * info) {
18   struct emulation_state * emulator = &(info->emulator);
19
20   emulator->num_emulated_pages = 0;
21   INIT_LIST_HEAD(&(emulator->emulated_pages));
22
23
24   emulator->num_saved_pages = 0;
25   INIT_LIST_HEAD(&(emulator->saved_pages));
26   
27   emulator->num_write_regions = 0;
28   INIT_LIST_HEAD(&(emulator->write_regions));
29
30   emulator->running = 0;
31   emulator->instr_length = 0;
32
33   emulator->tf_enabled = 0;
34
35   return 0;
36 }
37
38 static addr_t get_new_page() {
39   void * page = V3_AllocPages(1);
40   memset(page, 0, PAGE_SIZE);
41
42   return (addr_t)page;
43 }
44
45 /*
46 static int setup_code_page(struct guest_info * info, char * instr, struct basic_instr_info * instr_info ) {
47   addr_t code_page_offset = PT32_PAGE_OFFSET(info->rip);
48   addr_t code_page = get_new_page();
49   struct emulated_page * new_code_page = V3_Malloc(sizeof(struct emulated_page));
50   struct saved_page * saved_code_page = V3_Malloc(sizeof(struct saved_page));
51
52
53   saved_code_page->va = PT32_PAGE_ADDR(info->rip);
54
55   new_code_page->page_addr = code_page; 
56   new_code_page->va = PT32_PAGE_ADDR(info->rip);
57
58   new_code_page->pte.present = 1;
59   new_code_page->pte.writable = 0;
60   new_code_page->pte.user_page = 1;
61   new_code_page->pte.page_base_addr = PT32_BASE_ADDR(code_page);
62
63   memcpy((void *)(code_page + code_page_offset), instr, instr_info->instr_length);
64   memcpy((void *)(code_page + code_page_offset + instr_info->instr_length), VMMCALL, 3);
65
66 #ifdef DEBUG_EMULATOR
67   PrintDebug("New Instr Stream:\n");
68   PrintTraceMemDump((void *)(code_page + code_page_offset), 32);
69   PrintDebug("rip =%x\n", info->rip);
70 #endif
71
72
73
74   v3_replace_shdw_page32(info, new_code_page->va, &(new_code_page->pte), &(saved_code_page->pte));
75
76
77   list_add(&(new_code_page->page_list), &(info->emulator.emulated_pages));
78   info->emulator.num_emulated_pages++;
79
80   list_add(&(saved_code_page->page_list), &(info->emulator.saved_pages));
81   info->emulator.num_saved_pages++;
82
83   return 0;
84 }
85 */
86
87
88 static int set_stepping(struct guest_info * info) {
89   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
90   ctrl_area->exceptions.db = 1;
91
92   info->emulator.tf_enabled = ((struct rflags *)&(info->ctrl_regs.rflags))->tf;
93
94   ((struct rflags *)&(info->ctrl_regs.rflags))->tf = 1;
95
96   return 0;
97 }
98
99
100 static int unset_stepping(struct guest_info * info) {
101   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t*)(info->vmm_data));
102   ctrl_area->exceptions.db = 0;
103
104   ((struct rflags *)&(info->ctrl_regs.rflags))->tf = info->emulator.tf_enabled;
105
106   if (info->emulator.tf_enabled) {
107     // Inject breakpoint exception into guest
108   }
109
110   return 0;
111
112 }
113
114
115 // get the current instr
116 // check if rep + remove
117 // put into new page, vmexit after
118 // replace new page with current eip page
119 // 
120 int v3_emulate_memory_read(struct guest_info * info, addr_t read_gva, 
121                            int (*read)(addr_t read_addr, void * dst, uint_t length, void * priv_data), 
122                            addr_t read_gpa, void * private_data) {
123   struct basic_instr_info instr_info;
124   char instr[15];
125   int ret;
126   struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
127   addr_t data_addr_offset = PT32_PAGE_OFFSET(read_gva);
128   pte32_t saved_pte;
129
130   PrintDebug("Emulating Read\n");
131
132   if (info->mem_mode == PHYSICAL_MEM) { 
133     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
134   } else { 
135     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
136   }
137
138 #ifdef DEBUG_EMULATOR
139   PrintDebug("Instr (15 bytes) at %x:\n", instr);
140   PrintTraceMemDump(instr, 15);
141 #endif  
142
143
144   if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
145     PrintError("Could not do a basic memory instruction decode\n");
146     V3_Free(data_page);
147     return -1;
148   }
149
150   /*
151   if (instr_info.has_rep == 1) {
152     PrintError("We currently don't handle rep* instructions\n");
153     V3_Free(data_page);
154     return -1;
155   }
156   */
157
158   data_page->page_addr = get_new_page();
159   data_page->va = PT32_PAGE_ADDR(read_gva);
160   data_page->pte.present = 1;
161   data_page->pte.writable = 0;
162   data_page->pte.user_page = 1;
163   data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
164
165
166   // Read the data directly onto the emulated page
167   if (read(read_gpa, (void *)(data_page->page_addr + data_addr_offset), instr_info.op_size, private_data) != instr_info.op_size) {
168     PrintError("Read error in emulator\n");
169     V3_FreePage((void *)(data_page->page_addr));
170     V3_Free(data_page);
171     return -1;
172   }
173
174   v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
175
176
177   list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
178   info->emulator.num_emulated_pages++;
179
180   if (saved_pte.present == 1) {
181     struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
182     saved_data_page->pte = saved_pte;
183     saved_data_page->va = PT32_PAGE_ADDR(read_gva);
184
185     list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
186     info->emulator.num_saved_pages++;
187   }
188
189
190   // setup_code_page(info, instr, &instr_info);
191   set_stepping(info);
192
193   info->emulator.running = 1;
194   info->run_state = VM_EMULATING;
195   info->emulator.instr_length = instr_info.instr_length;
196
197   return 0;
198 }
199
200
201
202 int v3_emulate_memory_write(struct guest_info * info, addr_t write_gva,
203                             int (*write)(addr_t write_addr, void * src, uint_t length, void * priv_data), 
204                             addr_t write_gpa, void * private_data) {
205
206   struct basic_instr_info instr_info;
207   char instr[15];
208   int ret;
209   struct write_region * write_op = V3_Malloc(sizeof(struct write_region ));
210   struct emulated_page * data_page = V3_Malloc(sizeof(struct emulated_page));
211   addr_t data_addr_offset = PT32_PAGE_OFFSET(write_gva);
212   pte32_t saved_pte;
213   int i;
214
215   PrintDebug("Emulating Write for instruction at 0x%x\n",info->rip);
216
217   if (info->mem_mode == PHYSICAL_MEM) { 
218     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
219   } else { 
220     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
221   }
222
223
224   PrintDebug("Instruction is");
225   for (i=0;i<15;i++) { PrintDebug(" 0x%x",instr[i]); } 
226   PrintDebug("\n");
227   
228   if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
229     PrintError("Could not do a basic memory instruction decode\n");
230     V3_Free(write_op);
231     V3_Free(data_page);
232     return -1;
233   }
234
235   if (instr_info.has_rep==1) { 
236     PrintDebug("Emulated instruction has rep\n");
237   }
238
239   /*
240   if (instr_info.has_rep == 1) {
241     PrintError("We currently don't handle rep* instructions\n");
242     V3_Free(write_op);
243     V3_Free(data_page);
244     return -1;
245   }
246   */
247
248   data_page->page_addr = get_new_page();
249   data_page->va = PT32_PAGE_ADDR(write_gva);
250   data_page->pte.present = 1;
251   data_page->pte.writable = 1;
252   data_page->pte.user_page = 1;
253   data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
254
255
256
257   write_op->write = write;
258   write_op->write_addr = write_gpa;
259   write_op->length = instr_info.op_size;
260   write_op->private_data = private_data;
261
262   write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
263
264   list_add(&(write_op->write_list), &(info->emulator.write_regions));
265   info->emulator.num_write_regions--;
266
267   v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
268
269
270   list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
271   info->emulator.num_emulated_pages++;
272
273   if (saved_pte.present == 1) {
274     struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
275     saved_data_page->pte = saved_pte;
276     saved_data_page->va = PT32_PAGE_ADDR(write_gva);
277
278     list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
279     info->emulator.num_saved_pages++;
280   }
281
282
283   if (info->emulator.running == 0) {
284     //    setup_code_page(info, instr, &instr_info);
285     set_stepping(info);
286     info->emulator.running = 1;
287     info->run_state = VM_EMULATING;
288     info->emulator.instr_length = instr_info.instr_length;
289   }
290
291   return 0;
292 }
293
294
295 // end emulation
296 int v3_emulation_exit_handler(struct guest_info * info) {
297   struct saved_page * svpg, * p_svpg;
298   struct emulated_page * empg, * p_empg;
299   struct write_region * wr_reg, * p_wr_reg;
300   pte32_t dummy_pte;
301
302   // Complete the writes
303   // delete writes
304   // swap out emulated pages with blank dummies
305   // swap in saved pages
306   // increment rip
307   
308   PrintDebug("V3 Emulation Exit Handler\n");
309
310   list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) {
311     wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data);
312     PrintDebug("Writing \n");
313     
314     list_del(&(wr_reg->write_list));
315     V3_Free(wr_reg);
316
317   }
318   info->emulator.num_write_regions = 0;
319
320
321   *(uint_t *)&dummy_pte = 0;
322   
323   list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
324     pte32_t empte32_t;
325
326     PrintDebug("wiping page %x\n", empg->va); 
327
328     v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
329     V3_FreePage((void *)(empg->page_addr));
330
331     list_del(&(empg->page_list));
332     V3_Free(empg);
333   }
334   info->emulator.num_emulated_pages = 0;
335
336   list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
337
338     PrintDebug("Setting Saved page %x back\n", svpg->va); 
339     v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
340     
341     list_del(&(svpg->page_list));
342     V3_Free(svpg);
343   }
344   info->emulator.num_saved_pages = 0;
345
346   info->run_state = VM_RUNNING;
347   info->emulator.running = 0;
348   //info->rip += info->emulator.instr_length;
349
350
351   PrintDebug("Returning to rip: 0x%x\n", info->rip);
352
353   info->emulator.instr_length = 0;
354   
355   
356   unset_stepping(info);
357
358
359   PrintDebug("returning from emulation\n");
360
361   return 0;
362 }