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.


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