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 io_map implementation to use red-black trees instead of linked list
[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
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_va(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%p, io_info=0x%p\n",
171                (void *)(addr_t)mask, (void *)(addr_t)(io_info));
172     // PrintDebug("INS Aborted... Check implementation\n");
173     //return -1;
174   }
175
176   if (io_info->rep) {
177     //    rep_num = info->vm_regs.rcx & mask;
178     rep_num = info->vm_regs.rcx;
179   }
180
181
182   PrintDebug("INS size=%d for %d steps\n", read_size, rep_num);
183
184   while (rep_num > 0) {
185     addr_t host_addr;
186     dst_addr = get_addr_linear(info, info->vm_regs.rdi & mask, theseg);
187     
188     PrintDebug("Writing 0x%p\n", (void *)dst_addr);
189
190     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
191       // either page fault or gpf...
192       PrintError("Could not convert Guest VA to host VA\n");
193       return -1;
194     }
195
196     if (hook->read(io_info->port, (char*)host_addr, read_size, hook->priv_data) != read_size) {
197       // not sure how we handle errors.....
198       PrintError("Read Failure for ins on port %x\n", io_info->port);
199       return -1;
200     }
201
202     info->vm_regs.rdi += read_size * direction;
203
204     if (io_info->rep)
205       info->vm_regs.rcx--;
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
267   addr_t dst_addr = 0;
268   uint_t rep_num = 1;
269   ullong_t mask = 0;
270
271
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 *)&(guest_state->rflags);  
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   struct v3_segment *theseg = &(info->segments.es); // default is ES
324   
325   addr_t inst_ptr;
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
364
365     dst_addr = get_addr_linear(info, (info->vm_regs.rsi & mask), theseg);
366     
367     if (guest_va_to_host_va(info, dst_addr, &host_addr) == -1) {
368       // either page fault or gpf...
369     }
370
371     if (hook->write(io_info->port, (char*)host_addr, write_size, hook->priv_data) != write_size) {
372       // not sure how we handle errors.....
373       PrintError("Write Failure for outs on port %x\n", io_info->port);
374       return -1;
375     }
376
377     info->vm_regs.rsi += write_size * direction;
378
379     if (io_info->rep)
380       info->vm_regs.rcx--;
381     
382     rep_num--;
383   }
384
385
386   info->rip = ctrl_area->exit_info2;
387
388
389   return 0;
390 }