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.


VMX is working for a 32-bit Linux kernel. It should also work for a 64-bit kernel...
[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     return 0;
58 }
59
60 int v3_handle_vmx_io_in(struct guest_info * info) {
61     struct vmx_exit_io_qual io_qual;
62     struct v3_io_hook * hook = NULL;
63     int read_size = 0;
64     uint32_t instr_length = 0;
65
66     io_qual.value = 0;
67     vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value));
68     hook = v3_get_io_hook(info, io_qual.port);
69
70     if (hook == NULL) {
71         PrintError("Hook not present for IN on port %x\n", io_qual.port);
72         return -1;
73     }
74
75     read_size = io_qual.access_size + 1;
76
77     PrintDebug("IN of %d bytes on port %d (0x%x)\n", read_size, io_qual.port, io_qual.port);
78
79     if (hook->read(io_qual.port, &(info->vm_regs.rax), read_size, hook->priv_data) != read_size) {
80         PrintError("Read failure for IN on port %x\n", io_qual.port);
81         return -1;
82     }
83
84     if (vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_length) != VMX_SUCCESS) {
85         PrintError("Could not read instruction length\n");
86         return -1;
87     }
88
89     info->rip += instr_length;
90
91     return 0;
92 }
93
94 int v3_handle_vmx_io_ins(struct guest_info * info) {
95     struct vmx_exit_io_qual io_qual;
96     struct v3_io_hook * hook = NULL;
97     int read_size = 0;
98     addr_t guest_va = 0;
99     addr_t host_addr = 0;
100     int rdi_change = 0;
101     ulong_t rep_num = 1;
102     struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags);
103     int instr_len = 0;
104
105     io_qual.value = 0;
106     vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value));
107     hook = v3_get_io_hook(info, io_qual.port);
108
109     if (hook == NULL) {
110         PrintError("Hook not present for INS on port 0x%x\n", io_qual.port);
111         return -1;
112     }
113
114     PrintDebug("INS on port 0x%x\n", io_qual.port);
115
116     read_size = io_qual.access_size + 1;
117
118     if (io_qual.rep) {
119         struct vmx_exit_io_instr_info instr_info;
120
121         instr_info.value = 0;
122         vmcs_read(VMCS_EXIT_INSTR_INFO, &instr_info.value);
123
124         if (instr_info.addr_size == 0) {
125             rep_num = info->vm_regs.rcx & 0xffff;
126         } else if(instr_info.addr_size == 1) {
127             rep_num = info->vm_regs.rcx & 0xffffffff;
128         } else if(instr_info.addr_size == 2) {
129             rep_num = info->vm_regs.rcx & 0xffffffffffffffffLL;
130         } else {
131             PrintDebug("Unknown INS address size!\n");
132             return -1;
133         }
134     }
135     
136     if (flags->df) {
137         rdi_change = -read_size;
138     } else {
139         rdi_change = read_size;
140     }
141
142     PrintDebug("INS size=%d for %ld steps\n", read_size, rep_num);
143
144     vmcs_read(VMCS_GUEST_LINEAR_ADDR, &guest_va);
145
146     if (guest_va_to_host_va(info, guest_va, &host_addr) == -1) {
147         PrintError("Could not convert Guest VA to host VA\n");
148         return -1;
149     }
150
151     do {
152         if (hook->read(io_qual.port, (char *)host_addr, read_size, hook->priv_data) != read_size) {
153             PrintError("Read Failure for INS on port 0x%x\n", io_qual.port);
154             return -1;
155         }
156
157         host_addr += rdi_change;
158         info->vm_regs.rdi += rdi_change;
159
160         if (io_qual.rep) {
161             info->vm_regs.rcx--;
162         }
163         
164     } while (--rep_num > 0);
165
166
167     vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
168     info->rip += instr_len;
169
170     return 0;
171 }
172
173
174
175 int v3_handle_vmx_io_out(struct guest_info * info) {
176     struct vmx_exit_io_qual io_qual;
177     struct v3_io_hook * hook = NULL;
178     int write_size = 0;
179     uint32_t instr_length = 0;
180
181     vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value));
182     hook =  v3_get_io_hook(info, io_qual.port);
183
184     if (hook == NULL) {
185         PrintError("Hook not present for out on port %x\n", io_qual.port);
186         return -1;
187     }
188
189     write_size = io_qual.access_size + 1;
190     
191     PrintDebug("OUT of %d bytes on port %d (0x%x)\n", write_size, io_qual.port, io_qual.port);
192
193     if (hook->write(io_qual.port, &(info->vm_regs.rax), write_size, hook->priv_data) != write_size) {
194         PrintError("Write failure for out on port %x\n",io_qual.port);
195         return -1;
196     }
197
198
199     if (vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_length) != VMX_SUCCESS) {
200         PrintError("Could not read instruction length\n");
201         return -1;
202     } 
203
204     info->rip += instr_length;
205
206     return 0;
207 }
208
209
210
211 int v3_handle_vmx_io_outs(struct guest_info * info) {
212     struct vmx_exit_io_qual io_qual;
213     struct v3_io_hook * hook = NULL;
214     int write_size;
215     addr_t guest_va;
216     addr_t host_addr;
217     int rsi_change;
218     ulong_t rep_num = 1;
219     struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags);
220     int instr_len = 0;
221
222     vmcs_read(VMCS_EXIT_QUAL, &(io_qual.value));
223     hook = v3_get_io_hook(info, io_qual.port);
224
225     if (hook == NULL) {
226         PrintError("Hook not present for OUTS on port 0x%x\n", io_qual.port);
227         return -1;
228     }
229
230     PrintDebug("OUTS on port 0x%x\n", io_qual.port);
231
232     write_size = io_qual.access_size + 1;
233
234     if (io_qual.rep) {
235         // Grab the address sized bits of rcx
236         struct vmx_exit_io_instr_info instr_info;
237
238         instr_info.value = 0;
239         vmcs_read(VMCS_EXIT_INSTR_INFO, &instr_info.value);
240
241         if (instr_info.addr_size == 0) {
242             rep_num = info->vm_regs.rcx & 0xffff;
243         } else if(instr_info.addr_size == 1) {
244             rep_num = info->vm_regs.rcx & 0xffffffff;
245         } else if(instr_info.addr_size == 2) {
246             rep_num = info->vm_regs.rcx & 0xffffffffffffffffLL;
247         } else {
248             PrintDebug("Unknown INS address size!\n");
249             return -1;
250         }
251     }
252
253     if (flags->df) {
254         rsi_change = -write_size;
255     } else {
256         rsi_change = write_size;
257     }
258
259     vmcs_read(VMCS_GUEST_LINEAR_ADDR, &guest_va);
260
261     PrintDebug("OUTS size=%d for %ld steps\n", write_size, rep_num);
262
263     if (guest_va_to_host_va(info, guest_va, &host_addr) == -1) {
264         PrintError("Could not convert guest VA to host VA\n");
265         return -1;
266     }
267
268     do {
269        if (hook->write(io_qual.port, (char *)host_addr, write_size, hook->priv_data) != write_size) {
270            PrintError("Read failure for INS on port 0x%x\n", io_qual.port);
271            return -1;
272        }
273
274        host_addr += rsi_change;
275        info->vm_regs.rsi += rsi_change;
276
277        if (io_qual.rep) {
278            --info->vm_regs.rcx;
279        }
280
281     } while (--rep_num > 0);
282
283
284     vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
285     info->rip += instr_len;
286
287     return 0;
288 }
289