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.


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