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.


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