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.


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