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.


Assure that unhandled IO reads get back zeros
[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 - returning zeros\n", io_qual.port);
79         core->vm_regs.rax >>= 8*read_size;
80         core->vm_regs.rax <<= 8*read_size;
81
82     } else {
83         if (hook->read(core, io_qual.port, &(core->vm_regs.rax), read_size, hook->priv_data) != read_size) {
84             PrintError("Read failure for IN on port %x\n", io_qual.port);
85             return -1;
86         }
87     }
88     
89
90     core->rip += exit_info->instr_len;
91
92     return 0;
93 }
94
95 int v3_handle_vmx_io_ins(struct guest_info * core, struct vmx_exit_info * exit_info) {
96     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);;
97     struct v3_io_hook * hook = NULL;
98     int read_size = 0;
99     addr_t guest_va = exit_info->guest_linear_addr;
100     addr_t host_addr = 0;
101     int rdi_change = 0;
102     ulong_t rep_num = 1;
103     struct rflags * flags = (struct rflags *)&(core->ctrl_regs.rflags);
104
105     hook = v3_get_io_hook(core->vm_info, io_qual.port);
106
107
108     PrintDebug("INS on port 0x%x\n", io_qual.port);
109
110     read_size = io_qual.access_size + 1;
111
112     if (io_qual.rep) {
113         struct vmx_exit_io_instr_info instr_info = *(struct vmx_exit_io_instr_info *)&(exit_info->instr_info);
114
115         if (instr_info.addr_size == 0) {
116             rep_num = core->vm_regs.rcx & 0xffff;
117         } else if(instr_info.addr_size == 1) {
118             rep_num = core->vm_regs.rcx & 0xffffffff;
119         } else if(instr_info.addr_size == 2) {
120             rep_num = core->vm_regs.rcx & 0xffffffffffffffffLL;
121         } else {
122             PrintDebug("Unknown INS address size!\n");
123             return -1;
124         }
125     }
126     
127     if (flags->df) {
128         rdi_change = -read_size;
129     } else {
130         rdi_change = read_size;
131     }
132
133     PrintDebug("INS size=%d for %ld steps\n", read_size, rep_num);
134
135
136
137     if (v3_gva_to_hva(core, guest_va, &host_addr) == -1) {
138         PrintError("Could not convert Guest VA to host VA\n");
139         return -1;
140     }
141
142     do {
143
144         if (hook == NULL) {
145             PrintDebug("INS operation on unhooked IO port 0x%x - returning zeros\n", io_qual.port);
146             
147             memset((char*)host_addr,0,read_size);
148
149         } else {
150             if (hook->read(core, io_qual.port, (char *)host_addr, read_size, hook->priv_data) != read_size) {
151                 PrintError("Read Failure for INS on port 0x%x\n", io_qual.port);
152                 return -1;
153             }
154         }
155         
156
157         host_addr += rdi_change;
158         core->vm_regs.rdi += rdi_change;
159
160         if (io_qual.rep) {
161             core->vm_regs.rcx--;
162         }
163         
164     } while (--rep_num > 0);
165
166
167     core->rip += exit_info->instr_len;
168
169     return 0;
170 }
171
172
173
174 int v3_handle_vmx_io_out(struct guest_info * core, struct vmx_exit_info * exit_info) {
175     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);
176     struct v3_io_hook * hook = NULL;
177     int write_size = 0;
178
179     hook =  v3_get_io_hook(core->vm_info, io_qual.port);
180
181
182     write_size = io_qual.access_size + 1;
183     
184     PrintDebug("OUT of %d bytes on port %d (0x%x)\n", write_size, io_qual.port, io_qual.port);
185
186     if (hook == NULL) {
187         PrintDebug("OUT operation on unhooked IO port 0x%x - ignored\n", io_qual.port);
188     } else {  
189         if (hook->write(core, io_qual.port, &(core->vm_regs.rax), write_size, hook->priv_data) != write_size) {
190             PrintError("Write failure for out on port %x\n",io_qual.port);
191             return -1;
192         }
193     }
194
195     core->rip += exit_info->instr_len;
196
197     return 0;
198 }
199
200
201
202 int v3_handle_vmx_io_outs(struct guest_info * core, struct vmx_exit_info * exit_info) {
203     struct vmx_exit_io_qual io_qual = *(struct vmx_exit_io_qual *)&(exit_info->exit_qual);
204     struct v3_io_hook * hook = NULL;
205     int write_size;
206     addr_t guest_va = exit_info->guest_linear_addr;
207     addr_t host_addr;
208     int rsi_change;
209     ulong_t rep_num = 1;
210     struct rflags * flags = (struct rflags *)&(core->ctrl_regs.rflags);
211
212     hook = v3_get_io_hook(core->vm_info, io_qual.port);
213
214     PrintDebug("OUTS on port 0x%x\n", io_qual.port);
215
216     write_size = io_qual.access_size + 1;
217
218     if (io_qual.rep) {
219         // Grab the address sized bits of rcx
220         struct vmx_exit_io_instr_info instr_info = *(struct vmx_exit_io_instr_info *)&(exit_info->instr_info);
221
222         if (instr_info.addr_size == 0) {
223             rep_num = core->vm_regs.rcx & 0xffff;
224         } else if(instr_info.addr_size == 1) {
225             rep_num = core->vm_regs.rcx & 0xffffffff;
226         } else if(instr_info.addr_size == 2) {
227             rep_num = core->vm_regs.rcx & 0xffffffffffffffffLL;
228         } else {
229             PrintDebug("Unknown INS address size!\n");
230             return -1;
231         }
232     }
233
234     if (flags->df) {
235         rsi_change = -write_size;
236     } else {
237         rsi_change = write_size;
238     }
239
240
241
242     PrintDebug("OUTS size=%d for %ld steps\n", write_size, rep_num);
243
244     if (v3_gva_to_hva(core, guest_va, &host_addr) == -1) {
245         PrintError("Could not convert guest VA to host VA\n");
246         return -1;
247     }
248
249     do {
250
251         if (hook == NULL) {
252             PrintDebug("OUTS operation on unhooked IO port 0x%x - ignored\n", io_qual.port);
253         } else {
254             if (hook->write(core, io_qual.port, (char *)host_addr, write_size, hook->priv_data) != write_size) {
255                 PrintError("Read failure for INS on port 0x%x\n", io_qual.port);
256                 return -1;
257             }
258         }
259         
260
261        host_addr += rsi_change;
262        core->vm_regs.rsi += rsi_change;
263
264        if (io_qual.rep) {
265            --core->vm_regs.rcx;
266        }
267
268     } while (--rep_num > 0);
269
270
271     core->rip += exit_info->instr_len;
272
273     return 0;
274 }
275