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.


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