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