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.


changed the emulator to use single step break points instead of page insertion
[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
214   PrintDebug("Emulating Write\n");
215
216   if (info->mem_mode == PHYSICAL_MEM) { 
217     ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
218   } else { 
219     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
220   }
221   
222   if (v3_basic_mem_decode(info, (addr_t)instr, &instr_info) == -1) {
223     PrintError("Could not do a basic memory instruction decode\n");
224     V3_Free(write_op);
225     V3_Free(data_page);
226     return -1;
227   }
228
229   /*
230   if (instr_info.has_rep == 1) {
231     PrintError("We currently don't handle rep* instructions\n");
232     V3_Free(write_op);
233     V3_Free(data_page);
234     return -1;
235   }
236   */
237
238   data_page->page_addr = get_new_page();
239   data_page->va = PT32_PAGE_ADDR(write_gva);
240   data_page->pte.present = 1;
241   data_page->pte.writable = 1;
242   data_page->pte.user_page = 1;
243   data_page->pte.page_base_addr = PT32_BASE_ADDR(data_page->page_addr);
244
245
246
247   write_op->write = write;
248   write_op->write_addr = write_gpa;
249   write_op->length = instr_info.op_size;
250   write_op->private_data = private_data;
251
252   write_op->write_data = (void *)(data_page->page_addr + data_addr_offset);
253
254   list_add(&(write_op->write_list), &(info->emulator.write_regions));
255   info->emulator.num_write_regions--;
256
257   v3_replace_shdw_page32(info, data_page->va, &(data_page->pte), &saved_pte);
258
259
260   list_add(&(data_page->page_list), &(info->emulator.emulated_pages));
261   info->emulator.num_emulated_pages++;
262
263   if (saved_pte.present == 1) {
264     struct saved_page * saved_data_page = V3_Malloc(sizeof(struct saved_page));
265     saved_data_page->pte = saved_pte;
266     saved_data_page->va = PT32_PAGE_ADDR(write_gva);
267
268     list_add(&(saved_data_page->page_list), &(info->emulator.saved_pages));
269     info->emulator.num_saved_pages++;
270   }
271
272
273   if (info->emulator.running == 0) {
274     //    setup_code_page(info, instr, &instr_info);
275     set_stepping(info);
276     info->emulator.running = 1;
277     info->run_state = VM_EMULATING;
278     info->emulator.instr_length = instr_info.instr_length;
279   }
280
281   return 0;
282 }
283
284
285 // end emulation
286 int v3_emulation_exit_handler(struct guest_info * info) {
287   struct saved_page * svpg, * p_svpg;
288   struct emulated_page * empg, * p_empg;
289   struct write_region * wr_reg, * p_wr_reg;
290   pte32_t dummy_pte;
291
292   // Complete the writes
293   // delete writes
294   // swap out emulated pages with blank dummies
295   // swap in saved pages
296   // increment rip
297   
298   PrintDebug("V3 Emulation Exit Handler\n");
299
300   list_for_each_entry_safe(wr_reg, p_wr_reg, &(info->emulator.write_regions), write_list) {
301     wr_reg->write(wr_reg->write_addr, wr_reg->write_data, wr_reg->length, wr_reg->private_data);
302     PrintDebug("Writing \n");
303     
304     list_del(&(wr_reg->write_list));
305     V3_Free(wr_reg);
306
307   }
308   info->emulator.num_write_regions = 0;
309
310
311   *(uint_t *)&dummy_pte = 0;
312   
313   list_for_each_entry_safe(empg, p_empg, &(info->emulator.emulated_pages), page_list) {
314     pte32_t empte32_t;
315
316     PrintDebug("wiping page %x\n", empg->va); 
317
318     v3_replace_shdw_page32(info, empg->va, &dummy_pte, &empte32_t);
319     V3_FreePage((void *)(empg->page_addr));
320
321     list_del(&(empg->page_list));
322     V3_Free(empg);
323   }
324   info->emulator.num_emulated_pages = 0;
325
326   list_for_each_entry_safe(svpg, p_svpg, &(info->emulator.saved_pages), page_list) {
327
328     PrintDebug("Setting Saved page %x back\n", svpg->va); 
329     v3_replace_shdw_page32(info, empg->va, &(svpg->pte), &dummy_pte);
330     
331     list_del(&(svpg->page_list));
332     V3_Free(svpg);
333   }
334   info->emulator.num_saved_pages = 0;
335
336   info->run_state = VM_RUNNING;
337   info->emulator.running = 0;
338   //info->rip += info->emulator.instr_length;
339
340
341   PrintDebug("Returning to rip: 0x%x\n", info->rip);
342
343   info->emulator.instr_length = 0;
344   
345   
346   unset_stepping(info);
347
348
349   PrintDebug("returning from emulation\n");
350
351   return 0;
352 }