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.


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