Deleted Added
full compact
vmx.c (276349) vmx.c (276403)
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 unchanged lines hidden (view full) ---

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 *
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 unchanged lines hidden (view full) ---

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: stable/10/sys/amd64/vmm/intel/vmx.c 276349 2014-12-28 21:27:13Z neel $
26 * $FreeBSD: stable/10/sys/amd64/vmm/intel/vmx.c 276403 2014-12-30 08:24:14Z neel $
27 */
28
29#include <sys/cdefs.h>
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/intel/vmx.c 276349 2014-12-28 21:27:13Z neel $");
30__FBSDID("$FreeBSD: stable/10/sys/amd64/vmm/intel/vmx.c 276403 2014-12-30 08:24:14Z neel $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/smp.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/pcpu.h>
38#include <sys/proc.h>

--- 239 unchanged lines hidden (view full) ---

278 case EXIT_REASON_MWAIT:
279 return "mwait";
280 case EXIT_REASON_MTF:
281 return "mtf";
282 case EXIT_REASON_MONITOR:
283 return "monitor";
284 case EXIT_REASON_PAUSE:
285 return "pause";
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/smp.h>
35#include <sys/kernel.h>
36#include <sys/malloc.h>
37#include <sys/pcpu.h>
38#include <sys/proc.h>

--- 239 unchanged lines hidden (view full) ---

278 case EXIT_REASON_MWAIT:
279 return "mwait";
280 case EXIT_REASON_MTF:
281 return "mtf";
282 case EXIT_REASON_MONITOR:
283 return "monitor";
284 case EXIT_REASON_PAUSE:
285 return "pause";
286 case EXIT_REASON_MCE:
287 return "mce";
286 case EXIT_REASON_MCE_DURING_ENTRY:
287 return "mce-during-entry";
288 case EXIT_REASON_TPR:
289 return "tpr";
290 case EXIT_REASON_APIC_ACCESS:
291 return "apic-access";
292 case EXIT_REASON_GDTR_IDTR:
293 return "gdtridtr";
294 case EXIT_REASON_LDTR_TR:
295 return "ldtrtr";

--- 520 unchanged lines hidden (view full) ---

816
817static void *
818vmx_vminit(struct vm *vm, pmap_t pmap)
819{
820 uint16_t vpid[VM_MAXCPU];
821 int i, error;
822 struct vmx *vmx;
823 struct vmcs *vmcs;
288 case EXIT_REASON_TPR:
289 return "tpr";
290 case EXIT_REASON_APIC_ACCESS:
291 return "apic-access";
292 case EXIT_REASON_GDTR_IDTR:
293 return "gdtridtr";
294 case EXIT_REASON_LDTR_TR:
295 return "ldtrtr";

--- 520 unchanged lines hidden (view full) ---

816
817static void *
818vmx_vminit(struct vm *vm, pmap_t pmap)
819{
820 uint16_t vpid[VM_MAXCPU];
821 int i, error;
822 struct vmx *vmx;
823 struct vmcs *vmcs;
824 uint32_t exc_bitmap;
824
825 vmx = malloc(sizeof(struct vmx), M_VMX, M_WAITOK | M_ZERO);
826 if ((uintptr_t)vmx & PAGE_MASK) {
827 panic("malloc of struct vmx not aligned on %d byte boundary",
828 PAGE_SIZE);
829 }
830 vmx->vm = vm;
831

--- 74 unchanged lines hidden (view full) ---

906 error += vmwrite(VMCS_EPTP, vmx->eptp);
907 error += vmwrite(VMCS_PIN_BASED_CTLS, pinbased_ctls);
908 error += vmwrite(VMCS_PRI_PROC_BASED_CTLS, procbased_ctls);
909 error += vmwrite(VMCS_SEC_PROC_BASED_CTLS, procbased_ctls2);
910 error += vmwrite(VMCS_EXIT_CTLS, exit_ctls);
911 error += vmwrite(VMCS_ENTRY_CTLS, entry_ctls);
912 error += vmwrite(VMCS_MSR_BITMAP, vtophys(vmx->msr_bitmap));
913 error += vmwrite(VMCS_VPID, vpid[i]);
825
826 vmx = malloc(sizeof(struct vmx), M_VMX, M_WAITOK | M_ZERO);
827 if ((uintptr_t)vmx & PAGE_MASK) {
828 panic("malloc of struct vmx not aligned on %d byte boundary",
829 PAGE_SIZE);
830 }
831 vmx->vm = vm;
832

--- 74 unchanged lines hidden (view full) ---

907 error += vmwrite(VMCS_EPTP, vmx->eptp);
908 error += vmwrite(VMCS_PIN_BASED_CTLS, pinbased_ctls);
909 error += vmwrite(VMCS_PRI_PROC_BASED_CTLS, procbased_ctls);
910 error += vmwrite(VMCS_SEC_PROC_BASED_CTLS, procbased_ctls2);
911 error += vmwrite(VMCS_EXIT_CTLS, exit_ctls);
912 error += vmwrite(VMCS_ENTRY_CTLS, entry_ctls);
913 error += vmwrite(VMCS_MSR_BITMAP, vtophys(vmx->msr_bitmap));
914 error += vmwrite(VMCS_VPID, vpid[i]);
915
916 /* exception bitmap */
917 if (vcpu_trace_exceptions(vm, i))
918 exc_bitmap = 0xffffffff;
919 else
920 exc_bitmap = 1 << IDT_MC;
921 error += vmwrite(VMCS_EXCEPTION_BITMAP, exc_bitmap);
922
914 if (virtual_interrupt_delivery) {
915 error += vmwrite(VMCS_APIC_ACCESS, APIC_ACCESS_ADDRESS);
916 error += vmwrite(VMCS_VIRTUAL_APIC,
917 vtophys(&vmx->apic_page[i]));
918 error += vmwrite(VMCS_EOI_EXIT0, 0);
919 error += vmwrite(VMCS_EOI_EXIT1, 0);
920 error += vmwrite(VMCS_EOI_EXIT2, 0);
921 error += vmwrite(VMCS_EOI_EXIT3, 0);

--- 819 unchanged lines hidden (view full) ---

1741 vis->seg_name = VM_REG_GUEST_ES;
1742 } else {
1743 s = (inst_info >> 15) & 0x7;
1744 vis->seg_name = vm_segment_name(s);
1745 }
1746
1747 error = vmx_getdesc(vmx, vcpuid, vis->seg_name, &vis->seg_desc);
1748 KASSERT(error == 0, ("%s: vmx_getdesc error %d", __func__, error));
923 if (virtual_interrupt_delivery) {
924 error += vmwrite(VMCS_APIC_ACCESS, APIC_ACCESS_ADDRESS);
925 error += vmwrite(VMCS_VIRTUAL_APIC,
926 vtophys(&vmx->apic_page[i]));
927 error += vmwrite(VMCS_EOI_EXIT0, 0);
928 error += vmwrite(VMCS_EOI_EXIT1, 0);
929 error += vmwrite(VMCS_EOI_EXIT2, 0);
930 error += vmwrite(VMCS_EOI_EXIT3, 0);

--- 819 unchanged lines hidden (view full) ---

1750 vis->seg_name = VM_REG_GUEST_ES;
1751 } else {
1752 s = (inst_info >> 15) & 0x7;
1753 vis->seg_name = vm_segment_name(s);
1754 }
1755
1756 error = vmx_getdesc(vmx, vcpuid, vis->seg_name, &vis->seg_desc);
1757 KASSERT(error == 0, ("%s: vmx_getdesc error %d", __func__, error));
1749
1750 /* XXX modify svm.c to update bit 16 of seg_desc.access (unusable) */
1751}
1752
1753static void
1754vmx_paging_info(struct vm_guest_paging *paging)
1755{
1756 paging->cr3 = vmcs_guest_cr3();
1757 paging->cpl = vmx_cpl();
1758 paging->cpu_mode = vmx_cpu_mode();

--- 17 unchanged lines hidden (view full) ---

1776 case CPU_MODE_COMPATIBILITY:
1777 csar = vmcs_read(VMCS_GUEST_CS_ACCESS_RIGHTS);
1778 vmexit->u.inst_emul.cs_d = SEG_DESC_DEF32(csar);
1779 break;
1780 default:
1781 vmexit->u.inst_emul.cs_d = 0;
1782 break;
1783 }
1758}
1759
1760static void
1761vmx_paging_info(struct vm_guest_paging *paging)
1762{
1763 paging->cr3 = vmcs_guest_cr3();
1764 paging->cpl = vmx_cpl();
1765 paging->cpu_mode = vmx_cpu_mode();

--- 17 unchanged lines hidden (view full) ---

1783 case CPU_MODE_COMPATIBILITY:
1784 csar = vmcs_read(VMCS_GUEST_CS_ACCESS_RIGHTS);
1785 vmexit->u.inst_emul.cs_d = SEG_DESC_DEF32(csar);
1786 break;
1787 default:
1788 vmexit->u.inst_emul.cs_d = 0;
1789 break;
1790 }
1791 vie_init(&vmexit->u.inst_emul.vie, NULL, 0);
1784}
1785
1786static int
1787ept_fault_type(uint64_t ept_qual)
1788{
1789 int fault_type;
1790
1791 if (ept_qual & EPT_VIOLATION_DATA_WRITE)

--- 260 unchanged lines hidden (view full) ---

2052static int
2053vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
2054{
2055 int error, handled, in;
2056 struct vmxctx *vmxctx;
2057 struct vlapic *vlapic;
2058 struct vm_inout_str *vis;
2059 struct vm_task_switch *ts;
1792}
1793
1794static int
1795ept_fault_type(uint64_t ept_qual)
1796{
1797 int fault_type;
1798
1799 if (ept_qual & EPT_VIOLATION_DATA_WRITE)

--- 260 unchanged lines hidden (view full) ---

2060static int
2061vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
2062{
2063 int error, handled, in;
2064 struct vmxctx *vmxctx;
2065 struct vlapic *vlapic;
2066 struct vm_inout_str *vis;
2067 struct vm_task_switch *ts;
2068 struct vm_exception vmexc;
2060 uint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, inst_info;
2069 uint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, inst_info;
2061 uint32_t intr_type, reason;
2070 uint32_t intr_type, intr_vec, reason;
2062 uint64_t exitintinfo, qual, gpa;
2063 bool retu;
2064
2065 CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_VIRTUAL_NMI) != 0);
2066 CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_NMI_EXITING) != 0);
2067
2068 handled = UNHANDLED;
2069 vmxctx = &vmx->ctx[vcpu];
2070
2071 qual = vmexit->u.vmx.exit_qualification;
2072 reason = vmexit->u.vmx.exit_reason;
2073 vmexit->exitcode = VM_EXITCODE_BOGUS;
2074
2075 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_COUNT, 1);
2076
2077 /*
2071 uint64_t exitintinfo, qual, gpa;
2072 bool retu;
2073
2074 CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_VIRTUAL_NMI) != 0);
2075 CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_NMI_EXITING) != 0);
2076
2077 handled = UNHANDLED;
2078 vmxctx = &vmx->ctx[vcpu];
2079
2080 qual = vmexit->u.vmx.exit_qualification;
2081 reason = vmexit->u.vmx.exit_reason;
2082 vmexit->exitcode = VM_EXITCODE_BOGUS;
2083
2084 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_COUNT, 1);
2085
2086 /*
2087 * VM-entry failures during or after loading guest state.
2088 *
2089 * These VM-exits are uncommon but must be handled specially
2090 * as most VM-exit fields are not populated as usual.
2091 */
2092 if (__predict_false(reason == EXIT_REASON_MCE_DURING_ENTRY)) {
2093 VCPU_CTR0(vmx->vm, vcpu, "Handling MCE during VM-entry");
2094 __asm __volatile("int $18");
2095 return (1);
2096 }
2097
2098 /*
2078 * VM exits that can be triggered during event delivery need to
2079 * be handled specially by re-injecting the event if the IDT
2080 * vectoring information field's valid bit is set.
2081 *
2082 * See "Information for VM Exits During Event Delivery" in Intel SDM
2083 * for details.
2084 */
2085 idtvec_info = vmcs_idt_vectoring_info();

--- 215 unchanged lines hidden (view full) ---

2301 handled = vmx_handle_cpuid(vmx->vm, vcpu, vmxctx);
2302 break;
2303 case EXIT_REASON_EXCEPTION:
2304 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_EXCEPTION, 1);
2305 intr_info = vmcs_read(VMCS_EXIT_INTR_INFO);
2306 KASSERT((intr_info & VMCS_INTR_VALID) != 0,
2307 ("VM exit interruption info invalid: %#x", intr_info));
2308
2099 * VM exits that can be triggered during event delivery need to
2100 * be handled specially by re-injecting the event if the IDT
2101 * vectoring information field's valid bit is set.
2102 *
2103 * See "Information for VM Exits During Event Delivery" in Intel SDM
2104 * for details.
2105 */
2106 idtvec_info = vmcs_idt_vectoring_info();

--- 215 unchanged lines hidden (view full) ---

2322 handled = vmx_handle_cpuid(vmx->vm, vcpu, vmxctx);
2323 break;
2324 case EXIT_REASON_EXCEPTION:
2325 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_EXCEPTION, 1);
2326 intr_info = vmcs_read(VMCS_EXIT_INTR_INFO);
2327 KASSERT((intr_info & VMCS_INTR_VALID) != 0,
2328 ("VM exit interruption info invalid: %#x", intr_info));
2329
2330 intr_vec = intr_info & 0xff;
2331 intr_type = intr_info & VMCS_INTR_T_MASK;
2332
2309 /*
2310 * If Virtual NMIs control is 1 and the VM-exit is due to a
2311 * fault encountered during the execution of IRET then we must
2312 * restore the state of "virtual-NMI blocking" before resuming
2313 * the guest.
2314 *
2315 * See "Resuming Guest Software after Handling an Exception".
2316 * See "Information for VM Exits Due to Vectored Events".
2317 */
2318 if ((idtvec_info & VMCS_IDT_VEC_VALID) == 0 &&
2333 /*
2334 * If Virtual NMIs control is 1 and the VM-exit is due to a
2335 * fault encountered during the execution of IRET then we must
2336 * restore the state of "virtual-NMI blocking" before resuming
2337 * the guest.
2338 *
2339 * See "Resuming Guest Software after Handling an Exception".
2340 * See "Information for VM Exits Due to Vectored Events".
2341 */
2342 if ((idtvec_info & VMCS_IDT_VEC_VALID) == 0 &&
2319 (intr_info & 0xff) != IDT_DF &&
2343 (intr_vec != IDT_DF) &&
2320 (intr_info & EXIT_QUAL_NMIUDTI) != 0)
2321 vmx_restore_nmi_blocking(vmx, vcpu);
2322
2323 /*
2324 * The NMI has already been handled in vmx_exit_handle_nmi().
2325 */
2344 (intr_info & EXIT_QUAL_NMIUDTI) != 0)
2345 vmx_restore_nmi_blocking(vmx, vcpu);
2346
2347 /*
2348 * The NMI has already been handled in vmx_exit_handle_nmi().
2349 */
2326 if ((intr_info & VMCS_INTR_T_MASK) == VMCS_INTR_T_NMI)
2350 if (intr_type == VMCS_INTR_T_NMI)
2327 return (1);
2351 return (1);
2328 break;
2352
2353 /*
2354 * Call the machine check handler by hand. Also don't reflect
2355 * the machine check back into the guest.
2356 */
2357 if (intr_vec == IDT_MC) {
2358 VCPU_CTR0(vmx->vm, vcpu, "Vectoring to MCE handler");
2359 __asm __volatile("int $18");
2360 return (1);
2361 }
2362
2363 if (intr_vec == IDT_PF) {
2364 error = vmxctx_setreg(vmxctx, VM_REG_GUEST_CR2, qual);
2365 KASSERT(error == 0, ("%s: vmxctx_setreg(cr2) error %d",
2366 __func__, error));
2367 }
2368
2369 /*
2370 * Software exceptions exhibit trap-like behavior. This in
2371 * turn requires populating the VM-entry instruction length
2372 * so that the %rip in the trap frame is past the INT3/INTO
2373 * instruction.
2374 */
2375 if (intr_type == VMCS_INTR_T_SWEXCEPTION)
2376 vmcs_write(VMCS_ENTRY_INST_LENGTH, vmexit->inst_length);
2377
2378 /* Reflect all other exceptions back into the guest */
2379 bzero(&vmexc, sizeof(struct vm_exception));
2380 vmexc.vector = intr_vec;
2381 if (intr_info & VMCS_INTR_DEL_ERRCODE) {
2382 vmexc.error_code_valid = 1;
2383 vmexc.error_code = vmcs_read(VMCS_EXIT_INTR_ERRCODE);
2384 }
2385 VCPU_CTR2(vmx->vm, vcpu, "Reflecting exception %d/%#x into "
2386 "the guest", vmexc.vector, vmexc.error_code);
2387 error = vm_inject_exception(vmx->vm, vcpu, &vmexc);
2388 KASSERT(error == 0, ("%s: vm_inject_exception error %d",
2389 __func__, error));
2390 return (1);
2391
2329 case EXIT_REASON_EPT_FAULT:
2330 /*
2331 * If 'gpa' lies within the address space allocated to
2332 * memory then this must be a nested page fault otherwise
2333 * this must be an instruction that accesses MMIO space.
2334 */
2335 gpa = vmcs_gpa();
2336 if (vm_mem_allocated(vmx->vm, gpa) ||

--- 1000 unchanged lines hidden ---
2392 case EXIT_REASON_EPT_FAULT:
2393 /*
2394 * If 'gpa' lies within the address space allocated to
2395 * memory then this must be a nested page fault otherwise
2396 * this must be an instruction that accesses MMIO space.
2397 */
2398 gpa = vmcs_gpa();
2399 if (vm_mem_allocated(vmx->vm, gpa) ||

--- 1000 unchanged lines hidden ---