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.


added standard port write handler
[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
207         rep_num--;
208     }
209
210
211     info->rip = ctrl_area->exit_info2;
212
213     return 0;
214 }
215
216 int v3_handle_svm_io_out(struct guest_info * info) {
217     vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
218     //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
219     struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
220
221     struct v3_io_hook * hook = v3_get_io_hook(info, io_info->port);
222     int write_size = 0;
223
224     if (hook == NULL) {
225         PrintError("Hook Not present for out on port %x\n", io_info->port);
226         // error, we should not have exited on this port
227         return -1;
228     }
229
230
231     if (io_info->sz8) { 
232         write_size = 1;
233     } else if (io_info->sz16) {
234         write_size = 2;
235     } else if (io_info->sz32) {
236         write_size = 4;
237     }
238
239     PrintDebug("OUT of %d bytes on  port %d (0x%x)\n", write_size, io_info->port, io_info->port);
240
241     if (hook->write(io_info->port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) {
242         // not sure how we handle errors.....
243         PrintError("Write Failure for out on port %x\n", io_info->port);
244         return -1;
245     }
246
247     info->rip = ctrl_area->exit_info2;
248
249     return 0;
250 }
251
252
253 /* We might not handle wrap around of the RSI register correctly...
254  * In that if we do wrap around the effect will manifest in the higher bits of the register
255  */
256
257 int v3_handle_svm_io_outs(struct guest_info * info) {
258     vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
259     vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
260
261   
262     struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
263   
264     struct v3_io_hook * hook = v3_get_io_hook(info, io_info->port);
265     int write_size = 0;
266     addr_t dst_addr = 0;
267     uint_t rep_num = 1;
268     ullong_t mask = 0;
269     addr_t inst_ptr;
270     struct v3_segment * theseg = &(info->segments.es); // default is ES
271
272     // This is kind of hacky...
273     // direction can equal either 1 or -1
274     // We will multiply the final added offset by this value to go the correct direction
275     int direction = 1;
276     struct rflags * flags = (struct rflags *)&(guest_state->rflags);  
277
278     if (flags->df) {
279         direction = -1;
280     }
281
282
283     if (hook == NULL) {
284         PrintError("Hook Not present for outs on port %x\n", io_info->port);
285         // error, we should not have exited on this port
286         return -1;
287     }
288
289     PrintDebug("OUTS on  port %d (0x%x)\n", io_info->port, io_info->port);
290
291     if (io_info->sz8) { 
292         write_size = 1;
293     } else if (io_info->sz16) {
294         write_size = 2;
295     } else if (io_info->sz32) {
296         write_size = 4;
297     }
298
299
300     if (io_info->addr16) {
301         mask = 0xffff;
302     } else if (io_info->addr32) {
303         mask = 0xffffffff;
304     } else if (io_info->addr64) {
305         mask = 0xffffffffffffffffLL;
306     } else {
307         // This value should be set depending on the host register size...
308         mask = get_gpr_mask(info);
309
310         PrintDebug("OUTS io_info invalid address size, mask=0%p, io_info=0x%p\n",
311                    (void *)(addr_t)mask, (void *)(addr_t)io_info);
312         // PrintDebug("INS Aborted... Check implementation\n");
313         //return -1;
314         // should never happen
315         //PrintDebug("Invalid Address length\n");
316         //return -1;
317     }
318
319     if (io_info->rep) {
320         rep_num = info->vm_regs.rcx & mask;
321     }
322
323   
324
325
326     if (guest_va_to_host_va(info, get_addr_linear(info, info->rip, &(info->segments.cs)), &inst_ptr) == -1) {
327         PrintError("Can't access instruction\n");
328         return -1;
329     }
330
331     while (is_prefix_byte(*((char *)inst_ptr))) {
332         switch (*((char *)inst_ptr)) {
333             case PREFIX_CS_OVERRIDE:
334                 theseg = &(info->segments.cs);
335                 break;
336             case PREFIX_SS_OVERRIDE:
337                 theseg = &(info->segments.ss);
338                 break;
339             case PREFIX_DS_OVERRIDE:
340                 theseg = &(info->segments.ds);
341                 break;
342             case PREFIX_ES_OVERRIDE:
343                 theseg = &(info->segments.es);
344                 break;
345             case PREFIX_FS_OVERRIDE:
346                 theseg = &(info->segments.fs);
347                 break;
348             case PREFIX_GS_OVERRIDE:
349                 theseg = &(info->segments.gs);
350                 break;
351             default:
352                 break;
353         }
354         inst_ptr++;
355     }
356
357     PrintDebug("OUTS size=%d for %d steps\n", write_size, rep_num);
358
359     while (rep_num > 0) {
360         addr_t host_addr;
361
362         dst_addr = get_addr_linear(info, (info->vm_regs.rsi & mask), theseg);
363     
364         if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
365             // either page fault or gpf...
366         }
367
368         if (hook->write(io_info->port, (char*)host_addr, write_size, hook->priv_data) != write_size) {
369             // not sure how we handle errors.....
370             PrintError("Write Failure for outs on port %x\n", io_info->port);
371             return -1;
372         }
373
374         info->vm_regs.rsi += write_size * direction;
375
376         if (io_info->rep) {
377             info->vm_regs.rcx--;
378         }
379
380         rep_num--;
381     }
382
383
384     info->rip = ctrl_area->exit_info2;
385
386
387     return 0;
388 }