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.


Release 1.0
[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_va(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%p, io_info=0x%p\n",
174                (void *)mask, (void *)(io_info));
175     // PrintDebug("INS Aborted... Check implementation\n");
176     //return -1;
177   }
178
179   if (io_info->rep) {
180     //    rep_num = info->vm_regs.rcx & mask;
181     rep_num = info->vm_regs.rcx;
182   }
183
184
185   PrintDebug("INS size=%d for %d steps\n", read_size, rep_num);
186
187   while (rep_num > 0) {
188     addr_t host_addr;
189     dst_addr = get_addr_linear(info, info->vm_regs.rdi & mask, theseg);
190     
191     PrintDebug("Writing 0x%p\n", (void *)dst_addr);
192
193     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
194       // either page fault or gpf...
195       PrintError("Could not convert Guest VA to host VA\n");
196       return -1;
197     }
198
199     if (hook->read(io_info->port, (char*)host_addr, read_size, hook->priv_data) != read_size) {
200       // not sure how we handle errors.....
201       PrintError("Read Failure for ins on port %x\n", io_info->port);
202       return -1;
203     }
204
205     info->vm_regs.rdi += read_size * direction;
206
207     if (io_info->rep)
208       info->vm_regs.rcx--;
209     
210     rep_num--;
211   }
212
213
214   info->rip = ctrl_area->exit_info2;
215
216   return 0;
217 }
218
219 int v3_handle_svm_io_out(struct guest_info * info) {
220   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
221   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
222   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
223
224   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
225   int write_size = 0;
226
227   if (hook == NULL) {
228     PrintError("Hook Not present for out on port %x\n", io_info->port);
229     // error, we should not have exited on this port
230     return -1;
231   }
232
233
234   if (io_info->sz8) { 
235     write_size = 1;
236   } else if (io_info->sz16) {
237     write_size = 2;
238   } else if (io_info->sz32) {
239     write_size = 4;
240   }
241
242   PrintDebug("OUT of %d bytes on  port %d (0x%x)\n", write_size, io_info->port, io_info->port);
243
244   if (hook->write(io_info->port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) {
245     // not sure how we handle errors.....
246     PrintError("Write Failure for out on port %x\n", io_info->port);
247     return -1;
248   }
249
250   info->rip = ctrl_area->exit_info2;
251
252   return 0;
253 }
254
255
256 /* We might not handle wrap around of the RSI register correctly...
257  * In that if we do wrap around the effect will manifest in the higher bits of the register
258  */
259
260 int v3_handle_svm_io_outs(struct guest_info * info) {
261   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
262   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
263
264   
265   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
266   
267   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
268   int write_size = 0;
269
270   addr_t dst_addr = 0;
271   uint_t rep_num = 1;
272   ullong_t mask = 0;
273
274
275
276   // This is kind of hacky...
277   // direction can equal either 1 or -1
278   // We will multiply the final added offset by this value to go the correct direction
279   int direction = 1;
280   struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
281   if (flags->df) {
282     direction = -1;
283   }
284
285
286   if (hook == NULL) {
287     PrintError("Hook Not present for outs on port %x\n", io_info->port);
288     // error, we should not have exited on this port
289     return -1;
290   }
291
292   PrintDebug("OUTS on  port %d (0x%x)\n", io_info->port, io_info->port);
293
294   if (io_info->sz8) { 
295     write_size = 1;
296   } else if (io_info->sz16) {
297     write_size = 2;
298   } else if (io_info->sz32) {
299     write_size = 4;
300   }
301
302
303   if (io_info->addr16) {
304     mask = 0xffff;
305   } else if (io_info->addr32) {
306     mask = 0xffffffff;
307   } else if (io_info->addr64) {
308     mask = 0xffffffffffffffffLL;
309   } else {
310     // This value should be set depending on the host register size...
311     mask = get_gpr_mask(info);
312
313     PrintDebug("OUTS io_info invalid address size, mask=0%p, io_info=0x%p\n",
314                (void *)mask, (void *)io_info);
315     // PrintDebug("INS Aborted... Check implementation\n");
316     //return -1;
317     // should never happen
318     //PrintDebug("Invalid Address length\n");
319     //return -1;
320   }
321
322   if (io_info->rep) {
323     rep_num = info->vm_regs.rcx & mask;
324   }
325
326   struct v3_segment *theseg = &(info->segments.es); // default is ES
327   
328   addr_t inst_ptr;
329
330   if (guest_va_to_host_va(info,get_addr_linear(info,info->rip,&(info->segments.cs)),&inst_ptr)==-1) {
331     PrintError("Can't access instruction\n");
332     return -1;
333   }
334
335   while (is_prefix_byte(*((char*)inst_ptr))) {
336     switch (*((char*)inst_ptr)) { 
337     case PREFIX_CS_OVERRIDE:
338       theseg = &(info->segments.cs);
339       break;
340     case PREFIX_SS_OVERRIDE:
341       theseg = &(info->segments.ss);
342       break;
343     case PREFIX_DS_OVERRIDE:
344       theseg = &(info->segments.ds);
345       break;
346     case PREFIX_ES_OVERRIDE:
347       theseg = &(info->segments.es);
348       break;
349     case PREFIX_FS_OVERRIDE:
350       theseg = &(info->segments.fs);
351       break;
352     case PREFIX_GS_OVERRIDE:
353       theseg = &(info->segments.gs);
354       break;
355     default:
356       break;
357     }
358     inst_ptr++;
359   }
360
361   PrintDebug("OUTS size=%d for %d steps\n", write_size, rep_num);
362
363   while (rep_num > 0) {
364     addr_t host_addr;
365
366
367
368     dst_addr = get_addr_linear(info, (info->vm_regs.rsi & mask), theseg);
369     
370     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
371       // either page fault or gpf...
372     }
373
374     if (hook->write(io_info->port, (char*)host_addr, write_size, hook->priv_data) != write_size) {
375       // not sure how we handle errors.....
376       PrintError("Write Failure for outs on port %x\n", io_info->port);
377       return -1;
378     }
379
380     info->vm_regs.rsi += write_size * direction;
381
382     if (io_info->rep)
383       info->vm_regs.rcx--;
384     
385     rep_num--;
386   }
387
388
389   info->rip = ctrl_area->exit_info2;
390
391
392   return 0;
393 }