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.


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