]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/amd64/vmm/intel/vmcs.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / amd64 / vmm / intel / vmcs.c
1 /*-
2  * Copyright (c) 2011 NetApp, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include "opt_ddb.h"
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/pcpu.h>
37
38 #include <vm/vm.h>
39 #include <vm/pmap.h>
40
41 #include <machine/segments.h>
42 #include <machine/pmap.h>
43
44 #include <machine/vmm.h>
45 #include "vmm_host.h"
46 #include "vmcs.h"
47 #include "vmx_cpufunc.h"
48 #include "ept.h"
49 #include "vmx.h"
50
51 #ifdef DDB
52 #include <ddb/ddb.h>
53 #endif
54
55 static uint64_t
56 vmcs_fix_regval(uint32_t encoding, uint64_t val)
57 {
58
59         switch (encoding) {
60         case VMCS_GUEST_CR0:
61                 val = vmx_fix_cr0(val);
62                 break;
63         case VMCS_GUEST_CR4:
64                 val = vmx_fix_cr4(val);
65                 break;
66         default:
67                 break;
68         }
69         return (val);
70 }
71
72 static uint32_t
73 vmcs_field_encoding(int ident)
74 {
75         switch (ident) {
76         case VM_REG_GUEST_CR0:
77                 return (VMCS_GUEST_CR0);
78         case VM_REG_GUEST_CR3:
79                 return (VMCS_GUEST_CR3);
80         case VM_REG_GUEST_CR4:
81                 return (VMCS_GUEST_CR4);
82         case VM_REG_GUEST_DR7:
83                 return (VMCS_GUEST_DR7);
84         case VM_REG_GUEST_RSP:
85                 return (VMCS_GUEST_RSP);
86         case VM_REG_GUEST_RIP:
87                 return (VMCS_GUEST_RIP);
88         case VM_REG_GUEST_RFLAGS:
89                 return (VMCS_GUEST_RFLAGS);
90         case VM_REG_GUEST_ES:
91                 return (VMCS_GUEST_ES_SELECTOR);
92         case VM_REG_GUEST_CS:
93                 return (VMCS_GUEST_CS_SELECTOR);
94         case VM_REG_GUEST_SS:
95                 return (VMCS_GUEST_SS_SELECTOR);
96         case VM_REG_GUEST_DS:
97                 return (VMCS_GUEST_DS_SELECTOR);
98         case VM_REG_GUEST_FS:
99                 return (VMCS_GUEST_FS_SELECTOR);
100         case VM_REG_GUEST_GS:
101                 return (VMCS_GUEST_GS_SELECTOR);
102         case VM_REG_GUEST_TR:
103                 return (VMCS_GUEST_TR_SELECTOR);
104         case VM_REG_GUEST_LDTR:
105                 return (VMCS_GUEST_LDTR_SELECTOR);
106         case VM_REG_GUEST_EFER:
107                 return (VMCS_GUEST_IA32_EFER);
108         default:
109                 return (-1);
110         }
111
112 }
113
114 static int
115 vmcs_seg_desc_encoding(int seg, uint32_t *base, uint32_t *lim, uint32_t *acc)
116 {
117
118         switch (seg) {
119         case VM_REG_GUEST_ES:
120                 *base = VMCS_GUEST_ES_BASE;
121                 *lim = VMCS_GUEST_ES_LIMIT;
122                 *acc = VMCS_GUEST_ES_ACCESS_RIGHTS;
123                 break;
124         case VM_REG_GUEST_CS:
125                 *base = VMCS_GUEST_CS_BASE;
126                 *lim = VMCS_GUEST_CS_LIMIT;
127                 *acc = VMCS_GUEST_CS_ACCESS_RIGHTS;
128                 break;
129         case VM_REG_GUEST_SS:
130                 *base = VMCS_GUEST_SS_BASE;
131                 *lim = VMCS_GUEST_SS_LIMIT;
132                 *acc = VMCS_GUEST_SS_ACCESS_RIGHTS;
133                 break;
134         case VM_REG_GUEST_DS:
135                 *base = VMCS_GUEST_DS_BASE;
136                 *lim = VMCS_GUEST_DS_LIMIT;
137                 *acc = VMCS_GUEST_DS_ACCESS_RIGHTS;
138                 break;
139         case VM_REG_GUEST_FS:
140                 *base = VMCS_GUEST_FS_BASE;
141                 *lim = VMCS_GUEST_FS_LIMIT;
142                 *acc = VMCS_GUEST_FS_ACCESS_RIGHTS;
143                 break;
144         case VM_REG_GUEST_GS:
145                 *base = VMCS_GUEST_GS_BASE;
146                 *lim = VMCS_GUEST_GS_LIMIT;
147                 *acc = VMCS_GUEST_GS_ACCESS_RIGHTS;
148                 break;
149         case VM_REG_GUEST_TR:
150                 *base = VMCS_GUEST_TR_BASE;
151                 *lim = VMCS_GUEST_TR_LIMIT;
152                 *acc = VMCS_GUEST_TR_ACCESS_RIGHTS;
153                 break;
154         case VM_REG_GUEST_LDTR:
155                 *base = VMCS_GUEST_LDTR_BASE;
156                 *lim = VMCS_GUEST_LDTR_LIMIT;
157                 *acc = VMCS_GUEST_LDTR_ACCESS_RIGHTS;
158                 break;
159         case VM_REG_GUEST_IDTR:
160                 *base = VMCS_GUEST_IDTR_BASE;
161                 *lim = VMCS_GUEST_IDTR_LIMIT;
162                 *acc = VMCS_INVALID_ENCODING;
163                 break;
164         case VM_REG_GUEST_GDTR:
165                 *base = VMCS_GUEST_GDTR_BASE;
166                 *lim = VMCS_GUEST_GDTR_LIMIT;
167                 *acc = VMCS_INVALID_ENCODING;
168                 break;
169         default:
170                 return (EINVAL);
171         }
172
173         return (0);
174 }
175
176 int
177 vmcs_getreg(struct vmcs *vmcs, int running, int ident, uint64_t *retval)
178 {
179         int error;
180         uint32_t encoding;
181
182         /*
183          * If we need to get at vmx-specific state in the VMCS we can bypass
184          * the translation of 'ident' to 'encoding' by simply setting the
185          * sign bit. As it so happens the upper 16 bits are reserved (i.e
186          * set to 0) in the encodings for the VMCS so we are free to use the
187          * sign bit.
188          */
189         if (ident < 0)
190                 encoding = ident & 0x7fffffff;
191         else
192                 encoding = vmcs_field_encoding(ident);
193
194         if (encoding == (uint32_t)-1)
195                 return (EINVAL);
196
197         if (!running)
198                 VMPTRLD(vmcs);
199
200         error = vmread(encoding, retval);
201
202         if (!running)
203                 VMCLEAR(vmcs);
204
205         return (error);
206 }
207
208 int
209 vmcs_setreg(struct vmcs *vmcs, int running, int ident, uint64_t val)
210 {
211         int error;
212         uint32_t encoding;
213
214         if (ident < 0)
215                 encoding = ident & 0x7fffffff;
216         else
217                 encoding = vmcs_field_encoding(ident);
218
219         if (encoding == (uint32_t)-1)
220                 return (EINVAL);
221
222         val = vmcs_fix_regval(encoding, val);
223
224         if (!running)
225                 VMPTRLD(vmcs);
226
227         error = vmwrite(encoding, val);
228
229         if (!running)
230                 VMCLEAR(vmcs);
231
232         return (error);
233 }
234
235 int
236 vmcs_setdesc(struct vmcs *vmcs, int seg, struct seg_desc *desc)
237 {
238         int error;
239         uint32_t base, limit, access;
240
241         error = vmcs_seg_desc_encoding(seg, &base, &limit, &access);
242         if (error != 0)
243                 panic("vmcs_setdesc: invalid segment register %d", seg);
244
245         VMPTRLD(vmcs);
246         if ((error = vmwrite(base, desc->base)) != 0)
247                 goto done;
248
249         if ((error = vmwrite(limit, desc->limit)) != 0)
250                 goto done;
251
252         if (access != VMCS_INVALID_ENCODING) {
253                 if ((error = vmwrite(access, desc->access)) != 0)
254                         goto done;
255         }
256 done:
257         VMCLEAR(vmcs);
258         return (error);
259 }
260
261 int
262 vmcs_getdesc(struct vmcs *vmcs, int seg, struct seg_desc *desc)
263 {
264         int error;
265         uint32_t base, limit, access;
266         uint64_t u64;
267
268         error = vmcs_seg_desc_encoding(seg, &base, &limit, &access);
269         if (error != 0)
270                 panic("vmcs_getdesc: invalid segment register %d", seg);
271
272         VMPTRLD(vmcs);
273         if ((error = vmread(base, &u64)) != 0)
274                 goto done;
275         desc->base = u64;
276
277         if ((error = vmread(limit, &u64)) != 0)
278                 goto done;
279         desc->limit = u64;
280
281         if (access != VMCS_INVALID_ENCODING) {
282                 if ((error = vmread(access, &u64)) != 0)
283                         goto done;
284                 desc->access = u64;
285         }
286 done:
287         VMCLEAR(vmcs);
288         return (error);
289 }
290
291 int
292 vmcs_set_msr_save(struct vmcs *vmcs, u_long g_area, u_int g_count)
293 {
294         int error;
295
296         VMPTRLD(vmcs);
297
298         /*
299          * Guest MSRs are saved in the VM-exit MSR-store area.
300          * Guest MSRs are loaded from the VM-entry MSR-load area.
301          * Both areas point to the same location in memory.
302          */
303         if ((error = vmwrite(VMCS_EXIT_MSR_STORE, g_area)) != 0)
304                 goto done;
305         if ((error = vmwrite(VMCS_EXIT_MSR_STORE_COUNT, g_count)) != 0)
306                 goto done;
307
308         if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD, g_area)) != 0)
309                 goto done;
310         if ((error = vmwrite(VMCS_ENTRY_MSR_LOAD_COUNT, g_count)) != 0)
311                 goto done;
312
313         error = 0;
314 done:
315         VMCLEAR(vmcs);
316         return (error);
317 }
318
319 int
320 vmcs_set_defaults(struct vmcs *vmcs,
321                   u_long host_rip, u_long host_rsp, uint64_t eptp,
322                   uint32_t pinbased_ctls, uint32_t procbased_ctls,
323                   uint32_t procbased_ctls2, uint32_t exit_ctls,
324                   uint32_t entry_ctls, u_long msr_bitmap, uint16_t vpid)
325 {
326         int error, codesel, datasel, tsssel;
327         u_long cr0, cr4, efer;
328         uint64_t pat, fsbase, idtrbase;
329         uint32_t exc_bitmap;
330
331         codesel = vmm_get_host_codesel();
332         datasel = vmm_get_host_datasel();
333         tsssel = vmm_get_host_tsssel();
334
335         /*
336          * Make sure we have a "current" VMCS to work with.
337          */
338         VMPTRLD(vmcs);
339
340         /*
341          * Load the VMX controls
342          */
343         if ((error = vmwrite(VMCS_PIN_BASED_CTLS, pinbased_ctls)) != 0)
344                 goto done;
345         if ((error = vmwrite(VMCS_PRI_PROC_BASED_CTLS, procbased_ctls)) != 0)
346                 goto done;
347         if ((error = vmwrite(VMCS_SEC_PROC_BASED_CTLS, procbased_ctls2)) != 0)
348                 goto done;
349         if ((error = vmwrite(VMCS_EXIT_CTLS, exit_ctls)) != 0)
350                 goto done;
351         if ((error = vmwrite(VMCS_ENTRY_CTLS, entry_ctls)) != 0)
352                 goto done;
353
354         /* Guest state */
355
356         /* Initialize guest IA32_PAT MSR with the default value */
357         pat = PAT_VALUE(0, PAT_WRITE_BACK)      |
358               PAT_VALUE(1, PAT_WRITE_THROUGH)   |
359               PAT_VALUE(2, PAT_UNCACHED)        |
360               PAT_VALUE(3, PAT_UNCACHEABLE)     |
361               PAT_VALUE(4, PAT_WRITE_BACK)      |
362               PAT_VALUE(5, PAT_WRITE_THROUGH)   |
363               PAT_VALUE(6, PAT_UNCACHED)        |
364               PAT_VALUE(7, PAT_UNCACHEABLE);
365         if ((error = vmwrite(VMCS_GUEST_IA32_PAT, pat)) != 0)
366                 goto done;
367
368         /* Host state */
369
370         /* Initialize host IA32_PAT MSR */
371         pat = vmm_get_host_pat();
372         if ((error = vmwrite(VMCS_HOST_IA32_PAT, pat)) != 0)
373                 goto done;
374
375         /* Load the IA32_EFER MSR */
376         efer = vmm_get_host_efer();
377         if ((error = vmwrite(VMCS_HOST_IA32_EFER, efer)) != 0)
378                 goto done;
379
380         /* Load the control registers */
381
382         cr0 = vmm_get_host_cr0();
383         if ((error = vmwrite(VMCS_HOST_CR0, cr0)) != 0)
384                 goto done;
385         
386         cr4 = vmm_get_host_cr4() | CR4_VMXE;
387         if ((error = vmwrite(VMCS_HOST_CR4, cr4)) != 0)
388                 goto done;
389
390         /* Load the segment selectors */
391         if ((error = vmwrite(VMCS_HOST_ES_SELECTOR, datasel)) != 0)
392                 goto done;
393
394         if ((error = vmwrite(VMCS_HOST_CS_SELECTOR, codesel)) != 0)
395                 goto done;
396
397         if ((error = vmwrite(VMCS_HOST_SS_SELECTOR, datasel)) != 0)
398                 goto done;
399
400         if ((error = vmwrite(VMCS_HOST_DS_SELECTOR, datasel)) != 0)
401                 goto done;
402
403         if ((error = vmwrite(VMCS_HOST_FS_SELECTOR, datasel)) != 0)
404                 goto done;
405
406         if ((error = vmwrite(VMCS_HOST_GS_SELECTOR, datasel)) != 0)
407                 goto done;
408
409         if ((error = vmwrite(VMCS_HOST_TR_SELECTOR, tsssel)) != 0)
410                 goto done;
411
412         /*
413          * Load the Base-Address for %fs and idtr.
414          *
415          * Note that we exclude %gs, tss and gdtr here because their base
416          * address is pcpu specific.
417          */
418         fsbase = vmm_get_host_fsbase();
419         if ((error = vmwrite(VMCS_HOST_FS_BASE, fsbase)) != 0)
420                 goto done;
421
422         idtrbase = vmm_get_host_idtrbase();
423         if ((error = vmwrite(VMCS_HOST_IDTR_BASE, idtrbase)) != 0)
424                 goto done;
425
426         /* instruction pointer */
427         if ((error = vmwrite(VMCS_HOST_RIP, host_rip)) != 0)
428                 goto done;
429
430         /* stack pointer */
431         if ((error = vmwrite(VMCS_HOST_RSP, host_rsp)) != 0)
432                 goto done;
433
434         /* eptp */
435         if ((error = vmwrite(VMCS_EPTP, eptp)) != 0)
436                 goto done;
437
438         /* vpid */
439         if ((error = vmwrite(VMCS_VPID, vpid)) != 0)
440                 goto done;
441
442         /* msr bitmap */
443         if ((error = vmwrite(VMCS_MSR_BITMAP, msr_bitmap)) != 0)
444                 goto done;
445
446         /* exception bitmap */
447         exc_bitmap = 1 << IDT_MC;
448         if ((error = vmwrite(VMCS_EXCEPTION_BITMAP, exc_bitmap)) != 0)
449                 goto done;
450
451         /* link pointer */
452         if ((error = vmwrite(VMCS_LINK_POINTER, ~0)) != 0)
453                 goto done;
454 done:
455         VMCLEAR(vmcs);
456         return (error);
457 }
458
459 uint64_t
460 vmcs_read(uint32_t encoding)
461 {
462         int error;
463         uint64_t val;
464
465         error = vmread(encoding, &val);
466         if (error != 0)
467                 panic("vmcs_read(%u) error %d", encoding, error);
468
469         return (val);
470 }
471
472 #ifdef DDB
473 extern int vmxon_enabled[];
474
475 DB_SHOW_COMMAND(vmcs, db_show_vmcs)
476 {
477         uint64_t cur_vmcs, val;
478         uint32_t exit;
479
480         if (!vmxon_enabled[curcpu]) {
481                 db_printf("VMX not enabled\n");
482                 return;
483         }
484
485         if (have_addr) {
486                 db_printf("Only current VMCS supported\n");
487                 return;
488         }
489
490         vmptrst(&cur_vmcs);
491         if (cur_vmcs == VMCS_INITIAL) {
492                 db_printf("No current VM context\n");
493                 return;
494         }
495         db_printf("VMCS: %jx\n", cur_vmcs);
496         db_printf("VPID: %lu\n", vmcs_read(VMCS_VPID));
497         db_printf("Activity: ");
498         val = vmcs_read(VMCS_GUEST_ACTIVITY);
499         switch (val) {
500         case 0:
501                 db_printf("Active");
502                 break;
503         case 1:
504                 db_printf("HLT");
505                 break;
506         case 2:
507                 db_printf("Shutdown");
508                 break;
509         case 3:
510                 db_printf("Wait for SIPI");
511                 break;
512         default:
513                 db_printf("Unknown: %#lx", val);
514         }
515         db_printf("\n");
516         exit = vmcs_read(VMCS_EXIT_REASON);
517         if (exit & 0x80000000)
518                 db_printf("Entry Failure Reason: %u\n", exit & 0xffff);
519         else
520                 db_printf("Exit Reason: %u\n", exit & 0xffff);
521         db_printf("Qualification: %#lx\n", vmcs_exit_qualification());
522         db_printf("Guest Linear Address: %#lx\n",
523             vmcs_read(VMCS_GUEST_LINEAR_ADDRESS));
524         switch (exit & 0x8000ffff) {
525         case EXIT_REASON_EXCEPTION:
526         case EXIT_REASON_EXT_INTR:
527                 val = vmcs_read(VMCS_EXIT_INTERRUPTION_INFO);
528                 db_printf("Interrupt Type: ");
529                 switch (val >> 8 & 0x7) {
530                 case 0:
531                         db_printf("external");
532                         break;
533                 case 2:
534                         db_printf("NMI");
535                         break;
536                 case 3:
537                         db_printf("HW exception");
538                         break;
539                 case 4:
540                         db_printf("SW exception");
541                         break;
542                 default:
543                         db_printf("?? %lu", val >> 8 & 0x7);
544                         break;
545                 }
546                 db_printf("  Vector: %lu", val & 0xff);
547                 if (val & 0x800)
548                         db_printf("  Error Code: %lx",
549                             vmcs_read(VMCS_EXIT_INTERRUPTION_ERROR));
550                 db_printf("\n");
551                 break;
552         case EXIT_REASON_EPT_FAULT:
553         case EXIT_REASON_EPT_MISCONFIG:
554                 db_printf("Guest Physical Address: %#lx\n",
555                     vmcs_read(VMCS_GUEST_PHYSICAL_ADDRESS));
556                 break;
557         }
558         db_printf("VM-instruction error: %#lx\n", vmcs_instruction_error());
559 }
560 #endif