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.


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