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.


modified copyright tags
[palacios.git] / palacios / src / palacios / svm_io.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/svm_io.h>
6 #include <palacios/vmm_io.h>
7 #include <palacios/vmm_ctrl_regs.h>
8 #include <palacios/vmm_decoder.h>
9 #include <palacios/vm_guest_mem.h>
10
11 #ifndef DEBUG_IO
12 #undef PrintDebug
13 #define PrintDebug(fmt, args...)
14 #endif
15
16
17 // This should package up an IO request and call vmm_handle_io
18 int handle_svm_io_in(struct guest_info * info) {
19   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
20   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
21   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
22
23   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
24   uint_t read_size = 0;
25
26   if (hook == NULL) {
27     PrintError("Hook Not present for in on port %x\n", io_info->port);
28     // error, we should not have exited on this port
29     return -1;
30   }
31
32
33   if (io_info->sz8) { 
34     read_size = 1;
35   } else if (io_info->sz16) {
36     read_size = 2;
37   } else if (io_info->sz32) {
38     read_size = 4;
39   }
40
41   PrintDebug("IN of %d bytes on port %d (0x%x)\n", read_size, io_info->port, io_info->port);
42
43   if (hook->read(io_info->port, &(info->vm_regs.rax), read_size, hook->priv_data) != read_size) {
44     // not sure how we handle errors.....
45     PrintError("Read Failure for in on port %x\n", io_info->port);
46     return -1;
47   }
48
49   info->rip = ctrl_area->exit_info2;
50
51   return 0;
52 }
53
54
55
56
57
58 /* We might not handle wrap around of the RDI register correctly...
59  * In that if we do wrap around the effect will manifest in the higher bits of the register
60  */
61 int handle_svm_io_ins(struct guest_info * info) {
62   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
63   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
64   
65   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
66   
67   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
68   uint_t read_size = 0;
69
70   addr_t dst_addr = 0;
71   uint_t rep_num = 1;
72   ullong_t mask = 0;
73
74
75
76   // This is kind of hacky...
77   // direction can equal either 1 or -1
78   // We will multiply the final added offset by this value to go the correct direction
79   int direction = 1;
80   struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
81   if (flags->df) {
82     direction = -1;
83   }
84
85
86   if (hook == NULL) {
87    PrintError("Hook Not present for ins on port %x\n", io_info->port);
88     // error, we should not have exited on this port
89     return -1;
90   }
91
92    struct v3_segment *theseg = &(info->segments.es); // default is ES
93   
94   addr_t inst_ptr;
95
96   if (guest_va_to_host_pa(info,get_addr_linear(info,info->rip,&(info->segments.cs)),&inst_ptr)==-1) {
97     PrintError("Can't access instruction\n");
98     return -1;
99   }
100
101   while (is_prefix_byte(*((char*)inst_ptr))) {
102     switch (*((char*)inst_ptr)) { 
103     case PREFIX_CS_OVERRIDE:
104       theseg = &(info->segments.cs);
105       break;
106     case PREFIX_SS_OVERRIDE:
107       theseg = &(info->segments.ss);
108       break;
109     case PREFIX_DS_OVERRIDE:
110       theseg = &(info->segments.ds);
111       break;
112     case PREFIX_ES_OVERRIDE:
113       theseg = &(info->segments.es);
114       break;
115     case PREFIX_FS_OVERRIDE:
116       theseg = &(info->segments.fs);
117       break;
118     case PREFIX_GS_OVERRIDE:
119       theseg = &(info->segments.gs);
120       break;
121     default:
122       break;
123     }
124     inst_ptr++;
125   }
126
127
128   PrintDebug("INS on  port %d (0x%x)\n", io_info->port, io_info->port);
129
130   if (io_info->sz8) {
131     read_size = 1;
132   } else if (io_info->sz16) {
133     read_size = 2;
134   } else if (io_info->sz32) {
135     read_size = 4;
136   } else {
137     PrintError("io_info Invalid Size\n");
138     return -1;
139   }
140
141   
142   if (io_info->addr16) {
143     mask = 0xffff;
144   } else if (io_info->addr32) {
145     mask = 0xffffffff;
146   } else if (io_info->addr64) {
147     mask = 0xffffffffffffffffLL;
148   } else {
149     // This value should be set depending on the host register size...
150     mask = get_gpr_mask(info);
151
152     PrintDebug("INS io_info invalid address size, mask=0x%x, io_info=0x%x\n",mask,*((uint_t*)(io_info)));
153     // PrintDebug("INS Aborted... Check implementation\n");
154     //return -1;
155   }
156
157   if (io_info->rep) {
158     //    rep_num = info->vm_regs.rcx & mask;
159     rep_num = info->vm_regs.rcx;
160   }
161
162
163   PrintDebug("INS size=%d for %d steps\n", read_size, rep_num);
164
165   while (rep_num > 0) {
166     addr_t host_addr;
167     dst_addr = get_addr_linear(info, info->vm_regs.rdi & mask, theseg);
168     
169     PrintDebug("Writing 0x%x\n", dst_addr);
170
171     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
172       // either page fault or gpf...
173       PrintError("Could not convert Guest VA to host VA\n");
174       return -1;
175     }
176
177     if (hook->read(io_info->port, (char*)host_addr, read_size, hook->priv_data) != read_size) {
178       // not sure how we handle errors.....
179       PrintError("Read Failure for ins on port %x\n", io_info->port);
180       return -1;
181     }
182
183     info->vm_regs.rdi += read_size * direction;
184
185     if (io_info->rep)
186       info->vm_regs.rcx--;
187     
188     rep_num--;
189   }
190
191
192   info->rip = ctrl_area->exit_info2;
193
194   return 0;
195 }
196
197 int handle_svm_io_out(struct guest_info * info) {
198   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
199   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
200   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
201
202   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
203   uint_t write_size = 0;
204
205   if (hook == NULL) {
206     PrintError("Hook Not present for out on port %x\n", io_info->port);
207     // error, we should not have exited on this port
208     return -1;
209   }
210
211
212   if (io_info->sz8) { 
213     write_size = 1;
214   } else if (io_info->sz16) {
215     write_size = 2;
216   } else if (io_info->sz32) {
217     write_size = 4;
218   }
219
220   PrintDebug("OUT of %d bytes on  port %d (0x%x)\n", write_size, io_info->port, io_info->port);
221
222   if (hook->write(io_info->port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) {
223     // not sure how we handle errors.....
224     PrintError("Write Failure for out on port %x\n", io_info->port);
225     return -1;
226   }
227
228   info->rip = ctrl_area->exit_info2;
229
230   return 0;
231 }
232
233
234 /* We might not handle wrap around of the RSI register correctly...
235  * In that if we do wrap around the effect will manifest in the higher bits of the register
236  */
237
238 int handle_svm_io_outs(struct guest_info * info) {
239   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
240   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
241
242   
243   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
244   
245   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
246   uint_t write_size = 0;
247
248   addr_t dst_addr = 0;
249   uint_t rep_num = 1;
250   ullong_t mask = 0;
251
252
253
254   // This is kind of hacky...
255   // direction can equal either 1 or -1
256   // We will multiply the final added offset by this value to go the correct direction
257   int direction = 1;
258   struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
259   if (flags->df) {
260     direction = -1;
261   }
262
263
264   if (hook == NULL) {
265     PrintError("Hook Not present for outs on port %x\n", io_info->port);
266     // error, we should not have exited on this port
267     return -1;
268   }
269
270   PrintDebug("OUTS on  port %d (0x%x)\n", io_info->port, io_info->port);
271
272   if (io_info->sz8) { 
273     write_size = 1;
274   } else if (io_info->sz16) {
275     write_size = 2;
276   } else if (io_info->sz32) {
277     write_size = 4;
278   }
279
280
281   if (io_info->addr16) {
282     mask = 0xffff;
283   } else if (io_info->addr32) {
284     mask = 0xffffffff;
285   } else if (io_info->addr64) {
286     mask = 0xffffffffffffffffLL;
287   } else {
288     // This value should be set depending on the host register size...
289     mask = get_gpr_mask(info);
290
291     PrintDebug("OUTS io_info invalid address size, mask=0x%, io_info=0x%x\n",mask,*((uint_t*)(io_info)));
292     // PrintDebug("INS Aborted... Check implementation\n");
293     //return -1;
294     // should never happen
295     //PrintDebug("Invalid Address length\n");
296     //return -1;
297   }
298
299   if (io_info->rep) {
300     rep_num = info->vm_regs.rcx & mask;
301   }
302
303   struct v3_segment *theseg = &(info->segments.es); // default is ES
304   
305   addr_t inst_ptr;
306
307   if (guest_va_to_host_pa(info,get_addr_linear(info,info->rip,&(info->segments.cs)),&inst_ptr)==-1) {
308     PrintError("Can't access instruction\n");
309     return -1;
310   }
311
312   while (is_prefix_byte(*((char*)inst_ptr))) {
313     switch (*((char*)inst_ptr)) { 
314     case PREFIX_CS_OVERRIDE:
315       theseg = &(info->segments.cs);
316       break;
317     case PREFIX_SS_OVERRIDE:
318       theseg = &(info->segments.ss);
319       break;
320     case PREFIX_DS_OVERRIDE:
321       theseg = &(info->segments.ds);
322       break;
323     case PREFIX_ES_OVERRIDE:
324       theseg = &(info->segments.es);
325       break;
326     case PREFIX_FS_OVERRIDE:
327       theseg = &(info->segments.fs);
328       break;
329     case PREFIX_GS_OVERRIDE:
330       theseg = &(info->segments.gs);
331       break;
332     default:
333       break;
334     }
335     inst_ptr++;
336   }
337
338   PrintDebug("OUTS size=%d for %d steps\n", write_size, rep_num);
339
340   while (rep_num > 0) {
341     addr_t host_addr;
342
343
344
345     dst_addr = get_addr_linear(info, (info->vm_regs.rsi & mask), theseg);
346     
347     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
348       // either page fault or gpf...
349     }
350
351     if (hook->write(io_info->port, (char*)host_addr, write_size, hook->priv_data) != write_size) {
352       // not sure how we handle errors.....
353       PrintError("Write Failure for outs on port %x\n", io_info->port);
354       return -1;
355     }
356
357     info->vm_regs.rsi += write_size * direction;
358
359     if (io_info->rep)
360       info->vm_regs.rcx--;
361     
362     rep_num--;
363   }
364
365
366   info->rip = ctrl_area->exit_info2;
367
368
369   return 0;
370 }