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.


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