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.


Now by default IO and MSR operations are dropped by Palacios unless they have been...
[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     uchar_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     vm->io_map.update_map = update_map;
51     
52     vm->io_map.arch_data = V3_VAddr(V3_AllocPages(2));
53     memset(vm->io_map.arch_data, 0xff, PAGE_SIZE_4KB * 2);
54
55     v3_refresh_io_map(vm);
56
57     return 0;
58 }
59
60 int v3_deinit_vmx_io_map(struct v3_vm_info * vm) {
61     V3_FreePages(V3_PAddr(vm->io_map.arch_data), 2);
62     return 0;
63 }
64
65
66 int v3_handle_vmx_io_in(struct guest_info * core, struct vmx_exit_info * exit_info) {
67     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);;
68     struct v3_io_hook * hook = NULL;
69     int read_size = 0;
70
71     hook = v3_get_io_hook(core->vm_info, io_qual.port);
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 == NULL) {
78         PrintDebug("IN operation on unhooked IO port 0x%x\n", io_qual.port);
79
80         /* What are the HW semantics for an IN on an invalid port? 
81          *  Do we need to clear the register value or leave it untouched??? 
82          */
83     } else {
84         if (hook->read(core, io_qual.port, &(core->vm_regs.rax), read_size, hook->priv_data) != read_size) {
85             PrintError("Read failure for IN on port %x\n", io_qual.port);
86             return -1;
87         }
88     }
89     
90
91     core->rip += exit_info->instr_len;
92
93     return 0;
94 }
95
96 int v3_handle_vmx_io_ins(struct guest_info * core, struct vmx_exit_info * exit_info) {
97     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);;
98     struct v3_io_hook * hook = NULL;
99     int read_size = 0;
100     addr_t guest_va = exit_info->guest_linear_addr;
101     addr_t host_addr = 0;
102     int rdi_change = 0;
103     ulong_t rep_num = 1;
104     struct rflags * flags = (struct rflags *)&(core->ctrl_regs.rflags);
105
106     hook = v3_get_io_hook(core->vm_info, io_qual.port);
107
108
109     PrintDebug("INS on port 0x%x\n", io_qual.port);
110
111     read_size = io_qual.access_size + 1;
112
113     if (io_qual.rep) {
114         struct vmx_exit_io_instr_info instr_info = *(struct vmx_exit_io_instr_info *)&(exit_info->instr_info);
115
116         if (instr_info.addr_size == 0) {
117             rep_num = core->vm_regs.rcx & 0xffff;
118         } else if(instr_info.addr_size == 1) {
119             rep_num = core->vm_regs.rcx & 0xffffffff;
120         } else if(instr_info.addr_size == 2) {
121             rep_num = core->vm_regs.rcx & 0xffffffffffffffffLL;
122         } else {
123             PrintDebug("Unknown INS address size!\n");
124             return -1;
125         }
126     }
127     
128     if (flags->df) {
129         rdi_change = -read_size;
130     } else {
131         rdi_change = read_size;
132     }
133
134     PrintDebug("INS size=%d for %ld steps\n", read_size, rep_num);
135
136
137
138     if (v3_gva_to_hva(core, guest_va, &host_addr) == -1) {
139         PrintError("Could not convert Guest VA to host VA\n");
140         return -1;
141     }
142
143     do {
144
145         if (hook == NULL) {
146             PrintDebug("INS operation on unhooked IO port 0x%x\n", io_qual.port);
147             
148             /* What are the HW semantics for an INS on an invalid port? 
149              *  Do we need to clear the memory region or leave it untouched??? 
150              */     
151         } else {
152             if (hook->read(core, 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         
158
159         host_addr += rdi_change;
160         core->vm_regs.rdi += rdi_change;
161
162         if (io_qual.rep) {
163             core->vm_regs.rcx--;
164         }
165         
166     } while (--rep_num > 0);
167
168
169     core->rip += exit_info->instr_len;
170
171     return 0;
172 }
173
174
175
176 int v3_handle_vmx_io_out(struct guest_info * core, struct vmx_exit_info * exit_info) {
177     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);
178     struct v3_io_hook * hook = NULL;
179     int write_size = 0;
180
181     hook =  v3_get_io_hook(core->vm_info, io_qual.port);
182
183
184     write_size = io_qual.access_size + 1;
185     
186     PrintDebug("OUT of %d bytes on port %d (0x%x)\n", write_size, io_qual.port, io_qual.port);
187
188     if (hook == NULL) {
189         PrintDebug("OUT operation on unhooked IO port 0x%x\n", io_qual.port);
190     } else {  
191         if (hook->write(core, io_qual.port, &(core->vm_regs.rax), write_size, hook->priv_data) != write_size) {
192             PrintError("Write failure for out on port %x\n",io_qual.port);
193             return -1;
194         }
195     }
196
197     core->rip += exit_info->instr_len;
198
199     return 0;
200 }
201
202
203
204 int v3_handle_vmx_io_outs(struct guest_info * core, struct vmx_exit_info * exit_info) {
205     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);
206     struct v3_io_hook * hook = NULL;
207     int write_size;
208     addr_t guest_va = exit_info->guest_linear_addr;
209     addr_t host_addr;
210     int rsi_change;
211     ulong_t rep_num = 1;
212     struct rflags * flags = (struct rflags *)&(core->ctrl_regs.rflags);
213
214     hook = v3_get_io_hook(core->vm_info, io_qual.port);
215
216     PrintDebug("OUTS on port 0x%x\n", io_qual.port);
217
218     write_size = io_qual.access_size + 1;
219
220     if (io_qual.rep) {
221         // Grab the address sized bits of rcx
222         struct vmx_exit_io_instr_info instr_info = *(struct vmx_exit_io_instr_info *)&(exit_info->instr_info);
223
224         if (instr_info.addr_size == 0) {
225             rep_num = core->vm_regs.rcx & 0xffff;
226         } else if(instr_info.addr_size == 1) {
227             rep_num = core->vm_regs.rcx & 0xffffffff;
228         } else if(instr_info.addr_size == 2) {
229             rep_num = core->vm_regs.rcx & 0xffffffffffffffffLL;
230         } else {
231             PrintDebug("Unknown INS address size!\n");
232             return -1;
233         }
234     }
235
236     if (flags->df) {
237         rsi_change = -write_size;
238     } else {
239         rsi_change = write_size;
240     }
241
242
243
244     PrintDebug("OUTS size=%d for %ld steps\n", write_size, rep_num);
245
246     if (v3_gva_to_hva(core, guest_va, &host_addr) == -1) {
247         PrintError("Could not convert guest VA to host VA\n");
248         return -1;
249     }
250
251     do {
252
253         if (hook == NULL) {
254             PrintDebug("OUTS operation on unhooked IO port 0x%x\n", io_qual.port);
255         } else {
256             if (hook->write(core, io_qual.port, (char *)host_addr, write_size, hook->priv_data) != write_size) {
257                 PrintError("Read failure for INS on port 0x%x\n", io_qual.port);
258                 return -1;
259             }
260         }
261         
262
263        host_addr += rsi_change;
264        core->vm_regs.rsi += rsi_change;
265
266        if (io_qual.rep) {
267            --core->vm_regs.rcx;
268        }
269
270     } while (--rep_num > 0);
271
272
273     core->rip += exit_info->instr_len;
274
275     return 0;
276 }
277