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 new copyright and license
[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
22
23 #include <palacios/svm_io.h>
24 #include <palacios/vmm_io.h>
25 #include <palacios/vmm_ctrl_regs.h>
26 #include <palacios/vmm_decoder.h>
27 #include <palacios/vm_guest_mem.h>
28
29 #ifndef DEBUG_IO
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34
35 // This should package up an IO request and call vmm_handle_io
36 int 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 vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
42   uint_t 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 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 vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
86   uint_t read_size = 0;
87
88   addr_t dst_addr = 0;
89   uint_t rep_num = 1;
90   ullong_t mask = 0;
91
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   if (flags->df) {
100     direction = -1;
101   }
102
103
104   if (hook == NULL) {
105    PrintError("Hook Not present for ins on port %x\n", io_info->port);
106     // error, we should not have exited on this port
107     return -1;
108   }
109
110    struct v3_segment *theseg = &(info->segments.es); // default is ES
111   
112   addr_t inst_ptr;
113
114   if (guest_va_to_host_pa(info,get_addr_linear(info,info->rip,&(info->segments.cs)),&inst_ptr)==-1) {
115     PrintError("Can't access instruction\n");
116     return -1;
117   }
118
119   while (is_prefix_byte(*((char*)inst_ptr))) {
120     switch (*((char*)inst_ptr)) { 
121     case PREFIX_CS_OVERRIDE:
122       theseg = &(info->segments.cs);
123       break;
124     case PREFIX_SS_OVERRIDE:
125       theseg = &(info->segments.ss);
126       break;
127     case PREFIX_DS_OVERRIDE:
128       theseg = &(info->segments.ds);
129       break;
130     case PREFIX_ES_OVERRIDE:
131       theseg = &(info->segments.es);
132       break;
133     case PREFIX_FS_OVERRIDE:
134       theseg = &(info->segments.fs);
135       break;
136     case PREFIX_GS_OVERRIDE:
137       theseg = &(info->segments.gs);
138       break;
139     default:
140       break;
141     }
142     inst_ptr++;
143   }
144
145
146   PrintDebug("INS on  port %d (0x%x)\n", io_info->port, io_info->port);
147
148   if (io_info->sz8) {
149     read_size = 1;
150   } else if (io_info->sz16) {
151     read_size = 2;
152   } else if (io_info->sz32) {
153     read_size = 4;
154   } else {
155     PrintError("io_info Invalid Size\n");
156     return -1;
157   }
158
159   
160   if (io_info->addr16) {
161     mask = 0xffff;
162   } else if (io_info->addr32) {
163     mask = 0xffffffff;
164   } else if (io_info->addr64) {
165     mask = 0xffffffffffffffffLL;
166   } else {
167     // This value should be set depending on the host register size...
168     mask = get_gpr_mask(info);
169
170     PrintDebug("INS io_info invalid address size, mask=0x%x, io_info=0x%x\n",mask,*((uint_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%x\n", 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     rep_num--;
207   }
208
209
210   info->rip = ctrl_area->exit_info2;
211
212   return 0;
213 }
214
215 int handle_svm_io_out(struct guest_info * info) {
216   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
217   //  vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
218   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
219
220   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
221   uint_t write_size = 0;
222
223   if (hook == NULL) {
224     PrintError("Hook Not present for out on port %x\n", io_info->port);
225     // error, we should not have exited on this port
226     return -1;
227   }
228
229
230   if (io_info->sz8) { 
231     write_size = 1;
232   } else if (io_info->sz16) {
233     write_size = 2;
234   } else if (io_info->sz32) {
235     write_size = 4;
236   }
237
238   PrintDebug("OUT of %d bytes on  port %d (0x%x)\n", write_size, io_info->port, io_info->port);
239
240   if (hook->write(io_info->port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) {
241     // not sure how we handle errors.....
242     PrintError("Write Failure for out on port %x\n", io_info->port);
243     return -1;
244   }
245
246   info->rip = ctrl_area->exit_info2;
247
248   return 0;
249 }
250
251
252 /* We might not handle wrap around of the RSI register correctly...
253  * In that if we do wrap around the effect will manifest in the higher bits of the register
254  */
255
256 int handle_svm_io_outs(struct guest_info * info) {
257   vmcb_ctrl_t * ctrl_area = GET_VMCB_CTRL_AREA((vmcb_t *)(info->vmm_data));
258   vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data));
259
260   
261   struct svm_io_info * io_info = (struct svm_io_info *)&(ctrl_area->exit_info1);
262   
263   struct vmm_io_hook * hook = v3_get_io_hook(&(info->io_map), io_info->port);
264   uint_t write_size = 0;
265
266   addr_t dst_addr = 0;
267   uint_t rep_num = 1;
268   ullong_t mask = 0;
269
270
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   if (flags->df) {
278     direction = -1;
279   }
280
281
282   if (hook == NULL) {
283     PrintError("Hook Not present for outs on port %x\n", io_info->port);
284     // error, we should not have exited on this port
285     return -1;
286   }
287
288   PrintDebug("OUTS on  port %d (0x%x)\n", io_info->port, io_info->port);
289
290   if (io_info->sz8) { 
291     write_size = 1;
292   } else if (io_info->sz16) {
293     write_size = 2;
294   } else if (io_info->sz32) {
295     write_size = 4;
296   }
297
298
299   if (io_info->addr16) {
300     mask = 0xffff;
301   } else if (io_info->addr32) {
302     mask = 0xffffffff;
303   } else if (io_info->addr64) {
304     mask = 0xffffffffffffffffLL;
305   } else {
306     // This value should be set depending on the host register size...
307     mask = get_gpr_mask(info);
308
309     PrintDebug("OUTS io_info invalid address size, mask=0x%, io_info=0x%x\n",mask,*((uint_t*)(io_info)));
310     // PrintDebug("INS Aborted... Check implementation\n");
311     //return -1;
312     // should never happen
313     //PrintDebug("Invalid Address length\n");
314     //return -1;
315   }
316
317   if (io_info->rep) {
318     rep_num = info->vm_regs.rcx & mask;
319   }
320
321   struct v3_segment *theseg = &(info->segments.es); // default is ES
322   
323   addr_t inst_ptr;
324
325   if (guest_va_to_host_pa(info,get_addr_linear(info,info->rip,&(info->segments.cs)),&inst_ptr)==-1) {
326     PrintError("Can't access instruction\n");
327     return -1;
328   }
329
330   while (is_prefix_byte(*((char*)inst_ptr))) {
331     switch (*((char*)inst_ptr)) { 
332     case PREFIX_CS_OVERRIDE:
333       theseg = &(info->segments.cs);
334       break;
335     case PREFIX_SS_OVERRIDE:
336       theseg = &(info->segments.ss);
337       break;
338     case PREFIX_DS_OVERRIDE:
339       theseg = &(info->segments.ds);
340       break;
341     case PREFIX_ES_OVERRIDE:
342       theseg = &(info->segments.es);
343       break;
344     case PREFIX_FS_OVERRIDE:
345       theseg = &(info->segments.fs);
346       break;
347     case PREFIX_GS_OVERRIDE:
348       theseg = &(info->segments.gs);
349       break;
350     default:
351       break;
352     }
353     inst_ptr++;
354   }
355
356   PrintDebug("OUTS size=%d for %d steps\n", write_size, rep_num);
357
358   while (rep_num > 0) {
359     addr_t host_addr;
360
361
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 %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     rep_num--;
381   }
382
383
384   info->rip = ctrl_area->exit_info2;
385
386
387   return 0;
388 }