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.


fb9af1a84389167d81430aee6494321385dc3296
[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/vmcs.h>
23 #include <palacios/vmx_lowlevel.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmx_handler.h>
26 #include <palacios/vmm_ctrl_regs.h>
27 #include <palacios/vm_guest_mem.h>
28 #include <palacios/vmm_decoder.h>
29
30 #ifndef CONFIG_DEBUG_IO
31 #undef PrintDebug
32 #define PrintDebug(fmt, args...)
33 #endif
34
35
36 /* Same as SVM */
37 static int update_map(struct guest_info * info, uint16_t port, int hook_read, int hook_write) {
38     uchar_t * bitmap = (uint8_t *)(info->io_map.arch_data);
39     int major = port / 8;
40     int minor = port % 8;
41
42     if ((hook_read == 0) && (hook_write == 0)) {
43         *(bitmap + major) &= ~(0x1 << minor);
44     } else {
45         *(bitmap + major) |= (0x1 << minor);
46     }
47
48     return 0;
49 }
50
51 int v3_init_vmx_io_map(struct guest_info * info) {
52     info->io_map.update_map = update_map;
53     
54     info->io_map.arch_data = V3_VAddr(V3_AllocPages(2));
55     memset(info->io_map.arch_data, 0, PAGE_SIZE_4KB * 2);
56
57     v3_refresh_io_map(info);
58
59     return 0;
60 }
61
62 int v3_handle_vmx_io_in(struct guest_info * info) {
63     struct vmx_exit_io_qual io_qual;
64     struct v3_io_hook * hook = NULL;
65     int read_size = 0;
66     uint32_t instr_length = 0;
67
68     io_qual.value = 0;
69     vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value));
70     hook = v3_get_io_hook(info, io_qual.port);
71
72     if (hook == NULL) {
73         PrintError("Hook not present for IN on port %x\n", io_qual.port);
74         return -1;
75     }
76
77     read_size = io_qual.access_size + 1;
78
79     PrintDebug("IN of %d bytes on port %d (0x%x)\n", read_size, io_qual.port, io_qual.port);
80
81     if (hook->read(io_qual.port, &(info->vm_regs.rax), read_size, hook->priv_data) != read_size) {
82         PrintError("Read failure for IN on port %x\n", io_qual.port);
83         return -1;
84     }
85
86     if (vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_length) != VMX_SUCCESS) {
87         PrintError("Could not read instruction length\n");
88         return -1;
89     }
90
91     info->rip += instr_length;
92
93     return 0;
94 }
95
96 int v3_handle_vmx_io_ins(struct guest_info * info) {
97     struct vmx_exit_io_qual io_qual;
98     struct v3_io_hook * hook = NULL;
99     int read_size = 0;
100     addr_t guest_va = 0;
101     addr_t host_addr = 0;
102     int rdi_change = 0;
103     ulong_t rep_num = 1;
104     struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags);
105     int instr_len = 0;
106
107     io_qual.value = 0;
108     vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value));
109     hook = v3_get_io_hook(info, io_qual.port);
110
111     if (hook == NULL) {
112         PrintError("Hook not present for INS on port 0x%x\n", io_qual.port);
113         return -1;
114     }
115
116     PrintDebug("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;
122
123         instr_info.value = 0;
124         vmcs_read(VMCS_EXIT_INSTR_INFO, &instr_info.value);
125
126         if (instr_info.addr_size == 0) {
127             rep_num = info->vm_regs.rcx & 0xffff;
128         } else if(instr_info.addr_size == 1) {
129             rep_num = info->vm_regs.rcx & 0xffffffff;
130         } else if(instr_info.addr_size == 2) {
131             rep_num = info->vm_regs.rcx & 0xffffffffffffffffLL;
132         } else {
133             PrintDebug("Unknown INS address size!\n");
134             return -1;
135         }
136     }
137     
138     if (flags->df) {
139         rdi_change = -read_size;
140     } else {
141         rdi_change = read_size;
142     }
143
144     PrintDebug("INS size=%d for %ld steps\n", read_size, rep_num);
145
146     vmcs_read(VMCS_GUEST_LINEAR_ADDR, &guest_va);
147
148     if (guest_va_to_host_va(info, guest_va, &host_addr) == -1) {
149         PrintError("Could not convert Guest VA to host VA\n");
150         return -1;
151     }
152
153     do {
154         if (hook->read(io_qual.port, (char *)host_addr, read_size, hook->priv_data) != read_size) {
155             PrintError("Read Failure for INS on port 0x%x\n", io_qual.port);
156             return -1;
157         }
158
159         host_addr += rdi_change;
160         info->vm_regs.rdi += rdi_change;
161
162         if (io_qual.rep) {
163             info->vm_regs.rcx--;
164         }
165         
166     } while (--rep_num > 0);
167
168
169     vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
170     info->rip += instr_len;
171
172     return 0;
173 }
174
175
176
177 int v3_handle_vmx_io_out(struct guest_info * info) {
178     struct vmx_exit_io_qual io_qual;
179     struct v3_io_hook * hook = NULL;
180     int write_size = 0;
181     uint32_t instr_length = 0;
182
183     vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value));
184     hook =  v3_get_io_hook(info, io_qual.port);
185
186     if (hook == NULL) {
187         PrintError("Hook not present for out on port %x\n", io_qual.port);
188         return -1;
189     }
190
191     write_size = io_qual.access_size + 1;
192     
193     PrintDebug("OUT of %d bytes on port %d (0x%x)\n", write_size, io_qual.port, io_qual.port);
194
195     if (hook->write(io_qual.port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) {
196         PrintError("Write failure for out on port %x\n",io_qual.port);
197         return -1;
198     }
199
200
201     if (vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_length) != VMX_SUCCESS) {
202         PrintError("Could not read instruction length\n");
203         return -1;
204     } 
205
206     info->rip += instr_length;
207
208     return 0;
209 }
210
211
212
213 int v3_handle_vmx_io_outs(struct guest_info * info) {
214     struct vmx_exit_io_qual io_qual;
215     struct v3_io_hook * hook = NULL;
216     int write_size;
217     addr_t guest_va;
218     addr_t host_addr;
219     int rsi_change;
220     ulong_t rep_num = 1;
221     struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags);
222     int instr_len = 0;
223
224     vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value));
225     hook = v3_get_io_hook(info, io_qual.port);
226
227     if (hook == NULL) {
228         PrintError("Hook not present for OUTS on port 0x%x\n", io_qual.port);
229         return -1;
230     }
231
232     PrintDebug("OUTS on port 0x%x\n", io_qual.port);
233
234     write_size = io_qual.access_size + 1;
235
236     if (io_qual.rep) {
237         // Grab the address sized bits of rcx
238         struct vmx_exit_io_instr_info instr_info;
239
240         instr_info.value = 0;
241         vmcs_read(VMCS_EXIT_INSTR_INFO, &instr_info.value);
242
243         if (instr_info.addr_size == 0) {
244             rep_num = info->vm_regs.rcx & 0xffff;
245         } else if(instr_info.addr_size == 1) {
246             rep_num = info->vm_regs.rcx & 0xffffffff;
247         } else if(instr_info.addr_size == 2) {
248             rep_num = info->vm_regs.rcx & 0xffffffffffffffffLL;
249         } else {
250             PrintDebug("Unknown INS address size!\n");
251             return -1;
252         }
253     }
254
255     if (flags->df) {
256         rsi_change = -write_size;
257     } else {
258         rsi_change = write_size;
259     }
260
261     vmcs_read(VMCS_GUEST_LINEAR_ADDR, &guest_va);
262
263     PrintDebug("OUTS size=%d for %ld steps\n", write_size, rep_num);
264
265     if (guest_va_to_host_va(info, guest_va, &host_addr) == -1) {
266         PrintError("Could not convert guest VA to host VA\n");
267         return -1;
268     }
269
270     do {
271        if (hook->write(io_qual.port, (char *)host_addr, write_size, hook->priv_data) != write_size) {
272            PrintError("Read failure for INS on port 0x%x\n", io_qual.port);
273            return -1;
274        }
275
276        host_addr += rsi_change;
277        info->vm_regs.rsi += rsi_change;
278
279        if (io_qual.rep) {
280            --info->vm_regs.rcx;
281        }
282
283     } while (--rep_num > 0);
284
285
286     vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
287     info->rip += instr_len;
288
289     return 0;
290 }
291