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.


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