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_handler.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, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
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_handler.h>
21 #include <palacios/vmm_types.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vmcs.h>
24 #include <palacios/vmx_lowlevel.h>
25 #include <palacios/vmx_io.h>
26 #include <palacios/vmx.h>
27 #include <palacios/vmm_ctrl_regs.h>
28 #include <palacios/vmm_lowlevel.h>
29 #include <palacios/vmx_ctrl_regs.h>
30 #include <palacios/vmx_assist.h>
31
32
33 static int inline check_vmcs_write(vmcs_field_t field, addr_t val)
34 {
35     int ret = 0;
36     ret = vmcs_write(field, val);
37
38     if (ret != VMX_SUCCESS) {
39         PrintError("VMWRITE error on %s!: %d\n", v3_vmcs_field_to_str(field), ret);
40     }
41
42     return ret;
43 }
44
45 static int inline check_vmcs_read(vmcs_field_t field, void * val)
46 {
47     int ret = 0;
48     ret = vmcs_read(field, val);
49
50     if (ret != VMX_SUCCESS) {
51         PrintError("VMREAD error on %s!: %d\n", v3_vmcs_field_to_str(field), ret);
52     }
53
54     return ret;
55 }
56
57 static void inline translate_access_to_v3_seg(struct vmcs_segment_access * access, 
58                                               struct v3_segment * v3_seg) {
59     v3_seg->type = access->type;
60     v3_seg->system = access->desc_type;
61     v3_seg->dpl = access->dpl;
62     v3_seg->present = access->present;
63     v3_seg->avail = access->avail;
64     v3_seg->long_mode = access->long_mode;
65     v3_seg->db = access->db;
66     v3_seg->granularity = access->granularity;
67 }
68
69 static int load_vmcs_guest_state(struct guest_info * info)
70 {
71
72     struct vmcs_segment_access access;
73     int ret = 0;
74
75     // JRL: Add error checking
76
77     memset(&access, 0, sizeof(access));
78
79     /* CS Segment */
80     check_vmcs_read(VMCS_GUEST_CS_BASE, &(info->segments.cs.base));
81     check_vmcs_read(VMCS_GUEST_CS_SELECTOR, &(info->segments.cs.selector));
82     check_vmcs_read(VMCS_GUEST_CS_LIMIT, &(info->segments.cs.limit));
83     check_vmcs_read(VMCS_GUEST_CS_ACCESS, &(access.value));
84
85     translate_access_to_v3_seg(&access, &(info->segments.cs));
86
87     /* SS Segment */
88     check_vmcs_read(VMCS_GUEST_SS_BASE, &(info->segments.ss.base));
89     check_vmcs_read(VMCS_GUEST_SS_SELECTOR, &(info->segments.ss.selector));
90     check_vmcs_read(VMCS_GUEST_SS_LIMIT, &(info->segments.ss.limit));
91     check_vmcs_read(VMCS_GUEST_SS_ACCESS, &(access.value));
92
93     translate_access_to_v3_seg(&access, &(info->segments.ss));
94
95     /* DS Segment */
96     check_vmcs_read(VMCS_GUEST_DS_BASE, &(info->segments.ds.base));
97     check_vmcs_read(VMCS_GUEST_DS_SELECTOR, &(info->segments.ds.selector));
98     check_vmcs_read(VMCS_GUEST_DS_LIMIT, &(info->segments.ds.limit));
99     check_vmcs_read(VMCS_GUEST_DS_ACCESS, &(access.value));
100
101     translate_access_to_v3_seg(&access, &(info->segments.ds));
102
103     /* ES Segment */
104     check_vmcs_read(VMCS_GUEST_ES_BASE, &(info->segments.es.base));
105     check_vmcs_read(VMCS_GUEST_ES_SELECTOR, &(info->segments.es.selector));
106     check_vmcs_read(VMCS_GUEST_ES_LIMIT, &(info->segments.es.limit));
107     check_vmcs_read(VMCS_GUEST_ES_ACCESS, &(access.value));
108
109     translate_access_to_v3_seg(&access, &(info->segments.es));
110
111     /* FS Segment */
112     check_vmcs_read(VMCS_GUEST_FS_BASE, &(info->segments.fs.base));
113     check_vmcs_read(VMCS_GUEST_FS_SELECTOR, &(info->segments.fs.selector));
114     check_vmcs_read(VMCS_GUEST_FS_LIMIT, &(info->segments.fs.limit));
115     check_vmcs_read(VMCS_GUEST_FS_ACCESS, &(access.value));
116
117     translate_access_to_v3_seg(&access, &(info->segments.fs));
118
119
120     /* GS Segment */
121     check_vmcs_read(VMCS_GUEST_GS_BASE, &(info->segments.gs.base));
122     check_vmcs_read(VMCS_GUEST_GS_SELECTOR, &(info->segments.gs.selector));
123     check_vmcs_read(VMCS_GUEST_GS_LIMIT, &(info->segments.gs.limit));
124     check_vmcs_read(VMCS_GUEST_GS_ACCESS, &(access.value));
125
126     translate_access_to_v3_seg(&access, &(info->segments.gs));
127
128     /* LDTR Segment */
129     check_vmcs_read(VMCS_GUEST_LDTR_BASE, &(info->segments.ldtr.base));
130     check_vmcs_read(VMCS_GUEST_LDTR_SELECTOR, &(info->segments.ldtr.selector));
131     check_vmcs_read(VMCS_GUEST_LDTR_LIMIT, &(info->segments.ldtr.limit));
132     check_vmcs_read(VMCS_GUEST_LDTR_ACCESS, &(access.value));
133
134     translate_access_to_v3_seg(&access, &(info->segments.ldtr));
135
136     /* TR Segment */
137     check_vmcs_read(VMCS_GUEST_TR_BASE, &(info->segments.tr.base));
138     check_vmcs_read(VMCS_GUEST_TR_SELECTOR, &(info->segments.tr.selector));
139     check_vmcs_read(VMCS_GUEST_TR_LIMIT, &(info->segments.tr.limit));
140     check_vmcs_read(VMCS_GUEST_TR_ACCESS, &(access.value));
141
142     translate_access_to_v3_seg(&access, &(info->segments.tr));
143
144     /* GDTR Segment */
145     check_vmcs_read(VMCS_GUEST_GDTR_BASE, &(info->segments.gdtr.base));
146     check_vmcs_read(VMCS_GUEST_GDTR_LIMIT, &(info->segments.gdtr.limit));
147     
148     /* IDTR Segment */
149     check_vmcs_read(VMCS_GUEST_IDTR_BASE, &(info->segments.idtr.base));
150     check_vmcs_read(VMCS_GUEST_IDTR_LIMIT, &(info->segments.idtr.limit));
151
152
153     /* 
154      *  Read the control state
155      */
156     check_vmcs_read(VMCS_GUEST_RIP, &(info->rip));
157     check_vmcs_read(VMCS_GUEST_RSP, &(info->vm_regs.rsp));
158     check_vmcs_read(VMCS_GUEST_CR0, &(info->ctrl_regs.cr0));
159     check_vmcs_read(VMCS_CR0_READ_SHDW, &(info->shdw_pg_state.guest_cr0));
160     check_vmcs_read(VMCS_GUEST_CR3, &(info->ctrl_regs.cr3));
161     check_vmcs_read(VMCS_GUEST_CR4, &(info->ctrl_regs.cr4));
162
163     return ret;
164 }
165
166
167 #if 0
168 static void setup_v8086_mode_for_boot(struct guest_info * info)
169 {
170
171     ((struct vmx_data *)info->vmm_data)->state = VMXASSIST_V8086_BIOS;
172     struct rflags * flags = (struct rflags *)&(info->ctrl_regs.rflags);
173     flags->rsvd1 = 1;
174     flags->vm = 1;
175     flags->iopl = 3;
176
177     info->rip = 0xfff0;
178    
179     /* Zero the segment registers */
180     memset(&(info->segments), 0, sizeof(struct v3_segment)*6);
181
182
183     info->segments.cs.selector = 0xf000;
184     info->segments.cs.base = 0xf000 << 4;
185     info->segments.cs.limit = 0xffff;
186     info->segments.cs.type = 3;
187     info->segments.cs.system = 1;
188     info->segments.cs.dpl = 3;
189     info->segments.cs.present = 1;
190     info->segments.cs.granularity = 0;
191
192     int i;
193     
194     /* Set values for selectors ds through ss */
195     struct v3_segment * seg_ptr = (struct v3_segment *)&(info->segments);
196     for(i = 1; i < 6 ; i++) {
197         seg_ptr[i].selector = 0x0000;
198         seg_ptr[i].base = 0x00000;
199         seg_ptr[i].limit = 0xffff;
200         seg_ptr[i].type = 3;
201         seg_ptr[i].system = 1;
202         seg_ptr[i].dpl = 3;
203         seg_ptr[i].present = 1;
204         seg_ptr[i].granularity = 0;
205     }
206
207 }
208
209 #endif
210     
211 static int inline handle_cr_access(struct guest_info * info, ulong_t exit_qual) {
212     struct vmexit_cr_qual * cr_qual = (struct vmexit_cr_qual *)&exit_qual;
213
214     PrintDebug("Control register: %d\n", cr_qual->access_type);
215
216     if (cr_qual->access_type < 2) {
217         v3_reg_t reg = 0;
218        
219         switch(cr_qual->gpr) {
220             case 0:
221                 reg = info->vm_regs.rax;
222                 break;
223             case 1:
224                 reg = info->vm_regs.rcx;
225                 break;
226             case 2:
227                 reg = info->vm_regs.rdx;
228                 break;
229             case 3:
230                 reg = info->vm_regs.rbx;
231                 break;
232             case 4:
233                 reg = info->vm_regs.rsp;
234                 break;
235             case 5:
236                 reg = info->vm_regs.rbp;
237                 break;
238             case 6:
239                 reg = info->vm_regs.rsi;
240                 break;
241             case 7:
242                 reg = info->vm_regs.rdi;
243                 break;
244             case 8:
245                 reg = info->vm_regs.r8;
246                 break;
247             case 9:
248                 reg = info->vm_regs.r9;
249                 break;
250             case 10:
251                 reg = info->vm_regs.r10;
252                 break;
253             case 11:
254                 reg = info->vm_regs.r11;
255                 break;
256             case 12:
257                 reg = info->vm_regs.r11;
258                 break;
259             case 13:
260                 reg = info->vm_regs.r13;
261                 break;
262             case 14:
263                 reg = info->vm_regs.r14;
264                 break;
265             case 15:
266                 reg = info->vm_regs.r15;
267                 break;
268         }
269
270         if (cr_qual->cr_id == 0) {
271             uint32_t instr_len;
272
273             vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
274
275             if ( ~reg & CR0_PE ) {
276
277                 if (v3_vmxassist_ctx_switch(info) != 0) {
278                     PrintError("Unable to execute VMXASSIST context switch!\n");
279                     return -1;
280                 }
281
282                 load_vmcs_guest_state(info);
283
284                 ((struct vmx_data *)info->vmm_data)->state = VMXASSIST_ENABLED;
285
286                 PrintDebug("Loading vmxassist at RIP: 0x%p\n", (void *)info->rip);
287                 return 0;
288             } else if (v3_vmx_handle_cr0_write(info, reg) != 0) {
289                 PrintError("Could not handle CR0 Write\n");
290                 return -1;
291             }
292
293             load_vmcs_guest_state(info);
294
295             PrintDebug("Leaving VMXASSIST and entering protected mode at RIP: 0x%p\n", (void *)info->rip);
296
297             return 0;
298         }
299     }
300
301     PrintError("Unhandled CR access\n");
302     return -1;
303 }
304
305
306 /* At this point the GPRs are already copied into the guest_info state */
307 int v3_handle_vmx_exit(struct v3_gprs * gprs, struct guest_info * info) {
308     uint32_t exit_reason;
309     ulong_t exit_qual;
310
311     check_vmcs_read(VMCS_EXIT_REASON, &exit_reason);
312     check_vmcs_read(VMCS_EXIT_QUAL, &exit_qual);
313
314     // PrintDebug("VMX Exit taken, id-qual: %u-%lu\n", exit_reason, exit_qual);
315
316     /* Update guest state */
317     load_vmcs_guest_state(info);
318   
319     switch (exit_reason) {
320         case VMEXIT_INFO_EXCEPTION_OR_NMI: {
321             uint32_t int_info;
322             pf_error_t error_code;
323
324             check_vmcs_read(VMCS_EXIT_INT_INFO, &int_info);
325             check_vmcs_read(VMCS_EXIT_INT_ERR, &error_code);
326             
327             // JRL: Change "0x0e" to a macro value
328             if ((uint8_t)int_info == 0x0e) {
329                 PrintDebug("Page Fault at %p\n", (void *)exit_qual);
330                 
331                 if (info->shdw_pg_mode == SHADOW_PAGING) {
332                     if (v3_handle_shadow_pagefault(info, (addr_t)exit_qual, error_code) == -1) {
333                         PrintError("Error handling shadow page fault\n");
334                         return -1;
335                     }
336                 } else {
337                     PrintError("Page fault in unimplemented paging mode\n");
338                     return -1;
339                 }
340             } else {
341                 PrintDebug("Unknown exception: 0x%x\n", (uint8_t)int_info);
342                 v3_print_GPRs(info);
343                 return -1;
344             }
345             break;
346         }
347             
348         case VMEXIT_CPUID: {
349             int instr_len;
350
351             v3_cpuid(info->vm_regs.rax, (addr_t *)&(info->vm_regs.rax), (addr_t *)&(info->vm_regs.rbx), 
352                      (addr_t *)&(info->vm_regs.rcx), (addr_t *)&(info->vm_regs.rdx));
353
354             check_vmcs_read(VMCS_EXIT_INSTR_LEN, &instr_len);
355
356             info->rip += instr_len;
357             break;
358         }
359             
360         case VMEXIT_IO_INSTR: {
361             struct vmexit_io_qual * io_qual = (struct vmexit_io_qual *)&exit_qual;
362             
363             if (io_qual->dir == 0) {
364                 if (io_qual->string) {
365                     if (v3_handle_vmx_io_outs(info) == -1) {
366                         PrintError("Error in outs IO handler\n");
367                         return -1;
368                     }
369                 } else {
370                     if (v3_handle_vmx_io_out(info) == -1) {
371                         PrintError("Error in out IO handler\n");
372                         return -1;
373                     }
374                 }
375             } else {
376                 if (io_qual->string) {
377                     if(v3_handle_vmx_io_ins(info) == -1) {
378                         PrintError("Error in ins IO handler\n");
379                         return -1;
380                     }
381                 } else {
382                     if (v3_handle_vmx_io_in(info) == -1) {
383                         PrintError("Error in in IO handler\n");
384                         return -1;
385                     }
386                 }
387             }
388             break;
389         }
390             
391         case VMEXIT_CR_REG_ACCESSES:
392             if (handle_cr_access(info,exit_qual) != 0) {
393                 PrintError("Error handling CR access\n");
394                 return -1;
395             }
396
397             break;
398
399         default:
400             PrintError("Unhandled VMEXIT: %u (0x%x), %lu (0x%lx)\n", exit_reason, exit_reason, exit_qual, exit_qual);
401             return -1;
402     }
403
404     check_vmcs_write(VMCS_GUEST_CR0, info->ctrl_regs.cr0);
405     check_vmcs_write(VMCS_GUEST_CR3, info->ctrl_regs.cr3);
406     check_vmcs_write(VMCS_GUEST_CR4, info->ctrl_regs.cr4);
407     check_vmcs_write(VMCS_GUEST_RIP, info->rip);
408     check_vmcs_write(VMCS_GUEST_RSP, info->vm_regs.rsp);
409
410     check_vmcs_write(VMCS_CR0_READ_SHDW, info->shdw_pg_state.guest_cr0);
411
412     return 0;
413 }