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.


Have unregistered hypercalls fail to guest
[palacios.git] / palacios / src / palacios / vmx_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, Andy Gocke <agocke@gmail.com>
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Andy Gocke <agocke@gmail.com>
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/vmx_io.h>
21 #include <palacios/vmm_io.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vmx_handler.h>
24 #include <palacios/vmm_ctrl_regs.h>
25 #include <palacios/vm_guest_mem.h>
26 #include <palacios/vmm_decoder.h>
27
28 #ifndef V3_CONFIG_DEBUG_IO
29 #undef PrintDebug
30 #define PrintDebug(fmt, args...)
31 #endif
32
33
34 /* Same as SVM */
35 static int update_map(struct v3_vm_info * vm, uint16_t port, int hook_read, int hook_write) {
36     uint8_t * bitmap = (uint8_t *)(vm->io_map.arch_data);
37     int major = port / 8;
38     int minor = port % 8;
39
40     if ((hook_read == 0) && (hook_write == 0)) {
41         *(bitmap + major) &= ~(0x1 << minor);
42     } else {
43         *(bitmap + major) |= (0x1 << minor);
44     }
45
46     return 0;
47 }
48
49 int v3_init_vmx_io_map(struct v3_vm_info * vm) {
50     void *temp;
51
52     vm->io_map.update_map = update_map;
53
54     temp = V3_AllocPages(2);  // need not be shadow-safe, not exposed to guest
55     if (!temp) {
56         PrintError(vm, VCORE_NONE, "Cannot allocate io bitmap\n");
57         return -1;
58     }
59                    
60     vm->io_map.arch_data = V3_VAddr(temp);
61     memset(vm->io_map.arch_data, 0xff, PAGE_SIZE_4KB * 2);
62
63     v3_refresh_io_map(vm);
64
65     return 0;
66 }
67
68 int v3_deinit_vmx_io_map(struct v3_vm_info * vm) {
69     V3_FreePages(V3_PAddr(vm->io_map.arch_data), 2);
70     return 0;
71 }
72
73
74 int v3_handle_vmx_io_in(struct guest_info * core, struct vmx_exit_info * exit_info) {
75     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);;
76     struct v3_io_hook * hook = NULL;
77     int read_size = 0;
78
79     hook = v3_get_io_hook(core->vm_info, io_qual.port);
80
81     read_size = io_qual.access_size + 1;
82
83     PrintDebug(core->vm_info, core, "IN of %d bytes on port %d (0x%x)\n", read_size, io_qual.port, io_qual.port);
84
85     if (hook == NULL) {
86         PrintDebug(core->vm_info, core, "IN operation on unhooked IO port 0x%x - returning zeros\n", io_qual.port);
87         core->vm_regs.rax >>= 8*read_size;
88         core->vm_regs.rax <<= 8*read_size;
89
90     } else {
91         if (hook->read(core, io_qual.port, &(core->vm_regs.rax), read_size, hook->priv_data) != read_size) {
92             PrintError(core->vm_info, core, "Read failure for IN on port %x\n", io_qual.port);
93             return -1;
94         }
95     }
96     
97
98     core->rip += exit_info->instr_len;
99
100     return 0;
101 }
102
103 int v3_handle_vmx_io_ins(struct guest_info * core, struct vmx_exit_info * exit_info) {
104     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);;
105     struct v3_io_hook * hook = NULL;
106     int read_size = 0;
107     addr_t guest_va = exit_info->guest_linear_addr;
108     addr_t host_addr = 0;
109     int rdi_change = 0;
110     uint32_t rep_num = 1;
111     struct rflags * flags = (struct rflags *)&(core->ctrl_regs.rflags);
112
113     hook = v3_get_io_hook(core->vm_info, io_qual.port);
114
115
116     PrintDebug(core->vm_info, core, "INS on port 0x%x\n", io_qual.port);
117
118     read_size = io_qual.access_size + 1;
119
120     if (io_qual.rep) {
121         struct vmx_exit_io_instr_info instr_info = *(struct vmx_exit_io_instr_info *)&(exit_info->instr_info);
122
123         if (instr_info.addr_size == 0) {
124             rep_num = core->vm_regs.rcx & 0xffff;
125         } else if(instr_info.addr_size == 1) {
126             rep_num = core->vm_regs.rcx & 0xffffffff;
127         } else if(instr_info.addr_size == 2) {
128             rep_num = core->vm_regs.rcx & 0xffffffffffffffffLL;
129         } else {
130             PrintDebug(core->vm_info, core, "Unknown INS address size!\n");
131             return -1;
132         }
133     }
134     
135     if (flags->df) {
136         rdi_change = -read_size;
137     } else {
138         rdi_change = read_size;
139     }
140
141     PrintDebug(core->vm_info, core, "INS size=%d for %u steps\n", read_size, rep_num);
142
143
144
145     if (v3_gva_to_hva(core, guest_va, &host_addr) == -1) {
146         PrintError(core->vm_info, core, "Could not convert Guest VA to host VA\n");
147         return -1;
148     }
149
150     do {
151
152         if (hook == NULL) {
153             PrintDebug(core->vm_info, core, "INS operation on unhooked IO port 0x%x - returning zeros\n", io_qual.port);
154             
155             memset((char*)host_addr,0,read_size);
156
157         } else {
158             if (hook->read(core, io_qual.port, (char *)host_addr, read_size, hook->priv_data) != read_size) {
159                 PrintError(core->vm_info, core, "Read Failure for INS on port 0x%x\n", io_qual.port);
160                 return -1;
161             }
162         }
163         
164
165         host_addr += rdi_change;
166         core->vm_regs.rdi += rdi_change;
167
168         if (io_qual.rep) {
169             core->vm_regs.rcx--;
170         }
171         
172     } while (--rep_num > 0);
173
174
175     core->rip += exit_info->instr_len;
176
177     return 0;
178 }
179
180
181
182 int v3_handle_vmx_io_out(struct guest_info * core, struct vmx_exit_info * exit_info) {
183     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);
184     struct v3_io_hook * hook = NULL;
185     int write_size = 0;
186
187     hook =  v3_get_io_hook(core->vm_info, io_qual.port);
188
189
190     write_size = io_qual.access_size + 1;
191     
192     PrintDebug(core->vm_info, core, "OUT of %d bytes on port %d (0x%x)\n", write_size, io_qual.port, io_qual.port);
193
194     if (hook == NULL) {
195         PrintDebug(core->vm_info, core, "OUT operation on unhooked IO port 0x%x - ignored\n", io_qual.port);
196     } else {  
197         if (hook->write(core, io_qual.port, &(core->vm_regs.rax), write_size, hook->priv_data) != write_size) {
198             PrintError(core->vm_info, core, "Write failure for out on port %x\n",io_qual.port);
199             return -1;
200         }
201     }
202
203     core->rip += exit_info->instr_len;
204
205     return 0;
206 }
207
208
209
210 int v3_handle_vmx_io_outs(struct guest_info * core, struct vmx_exit_info * exit_info) {
211     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);
212     struct v3_io_hook * hook = NULL;
213     int write_size;
214     addr_t guest_va = exit_info->guest_linear_addr;
215     addr_t host_addr;
216     int rsi_change;
217     uint32_t rep_num = 1;
218     struct rflags * flags = (struct rflags *)&(core->ctrl_regs.rflags);
219
220     hook = v3_get_io_hook(core->vm_info, io_qual.port);
221
222     PrintDebug(core->vm_info, core, "OUTS on port 0x%x\n", io_qual.port);
223
224     write_size = io_qual.access_size + 1;
225
226     if (io_qual.rep) {
227         // Grab the address sized bits of rcx
228         struct vmx_exit_io_instr_info instr_info = *(struct vmx_exit_io_instr_info *)&(exit_info->instr_info);
229
230         if (instr_info.addr_size == 0) {
231             rep_num = core->vm_regs.rcx & 0xffff;
232         } else if(instr_info.addr_size == 1) {
233             rep_num = core->vm_regs.rcx & 0xffffffff;
234         } else if(instr_info.addr_size == 2) {
235             rep_num = core->vm_regs.rcx & 0xffffffffffffffffLL;
236         } else {
237             PrintDebug(core->vm_info, core, "Unknown INS address size!\n");
238             return -1;
239         }
240     }
241
242     if (flags->df) {
243         rsi_change = -write_size;
244     } else {
245         rsi_change = write_size;
246     }
247
248
249
250     PrintDebug(core->vm_info, core, "OUTS size=%d for %u steps\n", write_size, rep_num);
251
252     if (v3_gva_to_hva(core, guest_va, &host_addr) == -1) {
253         PrintError(core->vm_info, core, "Could not convert guest VA to host VA\n");
254         return -1;
255     }
256
257     do {
258
259         if (hook == NULL) {
260             PrintDebug(core->vm_info, core, "OUTS operation on unhooked IO port 0x%x - ignored\n", io_qual.port);
261         } else {
262             if (hook->write(core, io_qual.port, (char *)host_addr, write_size, hook->priv_data) != write_size) {
263                 PrintError(core->vm_info, core, "Read failure for INS on port 0x%x\n", io_qual.port);
264                 return -1;
265             }
266         }
267         
268
269        host_addr += rsi_change;
270        core->vm_regs.rsi += rsi_change;
271
272        if (io_qual.rep) {
273            --core->vm_regs.rcx;
274        }
275
276     } while (--rep_num > 0);
277
278
279     core->rip += exit_info->instr_len;
280
281     return 0;
282 }
283