vmx.c (266550) | vmx.c (266573) |
---|---|
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: head/sys/amd64/vmm/intel/vmx.c 266550 2014-05-22 17:22:37Z neel $ | 26 * $FreeBSD: head/sys/amd64/vmm/intel/vmx.c 266573 2014-05-23 05:15:17Z neel $ |
27 */ 28 29#include <sys/cdefs.h> | 27 */ 28 29#include <sys/cdefs.h> |
30__FBSDID("$FreeBSD: head/sys/amd64/vmm/intel/vmx.c 266550 2014-05-22 17:22:37Z neel $"); | 30__FBSDID("$FreeBSD: head/sys/amd64/vmm/intel/vmx.c 266573 2014-05-23 05:15:17Z 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> --- 141 unchanged lines hidden (view full) --- 180 181/* 182 * Use the last page below 4GB as the APIC access address. This address is 183 * occupied by the boot firmware so it is guaranteed that it will not conflict 184 * with a page in system memory. 185 */ 186#define APIC_ACCESS_ADDRESS 0xFFFFF000 187 | 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> --- 141 unchanged lines hidden (view full) --- 180 181/* 182 * Use the last page below 4GB as the APIC access address. This address is 183 * occupied by the boot firmware so it is guaranteed that it will not conflict 184 * with a page in system memory. 185 */ 186#define APIC_ACCESS_ADDRESS 0xFFFFF000 187 |
188static int vmx_getdesc(void *arg, int vcpu, int reg, struct seg_desc *desc); 189static int vmx_getreg(void *arg, int vcpu, int reg, uint64_t *retval); |
|
188static void vmx_inject_pir(struct vlapic *vlapic); 189 190#ifdef KTR 191static const char * 192exit_reason_to_str(int reason) 193{ 194 static char reasonbuf[32]; 195 --- 329 unchanged lines hidden (view full) --- 525 if (vmxon_enabled[curcpu]) 526 vmxon(vmxon_region[curcpu]); 527} 528 529static int 530vmx_init(int ipinum) 531{ 532 int error, use_tpr_shadow; | 190static void vmx_inject_pir(struct vlapic *vlapic); 191 192#ifdef KTR 193static const char * 194exit_reason_to_str(int reason) 195{ 196 static char reasonbuf[32]; 197 --- 329 unchanged lines hidden (view full) --- 527 if (vmxon_enabled[curcpu]) 528 vmxon(vmxon_region[curcpu]); 529} 530 531static int 532vmx_init(int ipinum) 533{ 534 int error, use_tpr_shadow; |
533 uint64_t fixed0, fixed1, feature_control; | 535 uint64_t basic, fixed0, fixed1, feature_control; |
534 uint32_t tmp, procbased2_vid_bits; 535 536 /* CPUID.1:ECX[bit 5] must be 1 for processor to support VMX */ 537 if (!(cpu_feature2 & CPUID2_VMX)) { 538 printf("vmx_init: processor does not support VMX operation\n"); 539 return (ENXIO); 540 } 541 542 /* 543 * Verify that MSR_IA32_FEATURE_CONTROL lock and VMXON enable bits 544 * are set (bits 0 and 2 respectively). 545 */ 546 feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL); 547 if ((feature_control & IA32_FEATURE_CONTROL_LOCK) == 0 || 548 (feature_control & IA32_FEATURE_CONTROL_VMX_EN) == 0) { 549 printf("vmx_init: VMX operation disabled by BIOS\n"); 550 return (ENXIO); 551 } 552 | 536 uint32_t tmp, procbased2_vid_bits; 537 538 /* CPUID.1:ECX[bit 5] must be 1 for processor to support VMX */ 539 if (!(cpu_feature2 & CPUID2_VMX)) { 540 printf("vmx_init: processor does not support VMX operation\n"); 541 return (ENXIO); 542 } 543 544 /* 545 * Verify that MSR_IA32_FEATURE_CONTROL lock and VMXON enable bits 546 * are set (bits 0 and 2 respectively). 547 */ 548 feature_control = rdmsr(MSR_IA32_FEATURE_CONTROL); 549 if ((feature_control & IA32_FEATURE_CONTROL_LOCK) == 0 || 550 (feature_control & IA32_FEATURE_CONTROL_VMX_EN) == 0) { 551 printf("vmx_init: VMX operation disabled by BIOS\n"); 552 return (ENXIO); 553 } 554 |
555 /* 556 * Verify capabilities MSR_VMX_BASIC: 557 * - bit 54 indicates support for INS/OUTS decoding 558 */ 559 basic = rdmsr(MSR_VMX_BASIC); 560 if ((basic & (1UL << 54)) == 0) { 561 printf("vmx_init: processor does not support desired basic " 562 "capabilities\n"); 563 return (EINVAL); 564 } 565 |
|
553 /* Check support for primary processor-based VM-execution controls */ 554 error = vmx_set_ctlreg(MSR_VMX_PROCBASED_CTLS, 555 MSR_VMX_TRUE_PROCBASED_CTLS, 556 PROCBASED_CTLS_ONE_SETTING, 557 PROCBASED_CTLS_ZERO_SETTING, &procbased_ctls); 558 if (error) { 559 printf("vmx_init: processor does not support desired primary " 560 "processor-based controls\n"); --- 962 unchanged lines hidden (view full) --- 1523 if (!(vmcs_read(VMCS_GUEST_CR4) & CR4_PAE)) 1524 return (PAGING_MODE_32); 1525 if (vmcs_read(VMCS_GUEST_IA32_EFER) & EFER_LME) 1526 return (PAGING_MODE_64); 1527 else 1528 return (PAGING_MODE_PAE); 1529} 1530 | 566 /* Check support for primary processor-based VM-execution controls */ 567 error = vmx_set_ctlreg(MSR_VMX_PROCBASED_CTLS, 568 MSR_VMX_TRUE_PROCBASED_CTLS, 569 PROCBASED_CTLS_ONE_SETTING, 570 PROCBASED_CTLS_ZERO_SETTING, &procbased_ctls); 571 if (error) { 572 printf("vmx_init: processor does not support desired primary " 573 "processor-based controls\n"); --- 962 unchanged lines hidden (view full) --- 1536 if (!(vmcs_read(VMCS_GUEST_CR4) & CR4_PAE)) 1537 return (PAGING_MODE_32); 1538 if (vmcs_read(VMCS_GUEST_IA32_EFER) & EFER_LME) 1539 return (PAGING_MODE_64); 1540 else 1541 return (PAGING_MODE_PAE); 1542} 1543 |
1544static uint64_t 1545inout_str_index(struct vmx *vmx, int vcpuid, int in) 1546{ 1547 uint64_t val; 1548 int error; 1549 enum vm_reg_name reg; 1550 1551 reg = in ? VM_REG_GUEST_RDI : VM_REG_GUEST_RSI; 1552 error = vmx_getreg(vmx, vcpuid, reg, &val); 1553 KASSERT(error == 0, ("%s: vmx_getreg error %d", __func__, error)); 1554 return (val); 1555} 1556 1557static uint64_t 1558inout_str_count(struct vmx *vmx, int vcpuid, int rep) 1559{ 1560 uint64_t val; 1561 int error; 1562 1563 if (rep) { 1564 error = vmx_getreg(vmx, vcpuid, VM_REG_GUEST_RCX, &val); 1565 KASSERT(!error, ("%s: vmx_getreg error %d", __func__, error)); 1566 } else { 1567 val = 1; 1568 } 1569 return (val); 1570} 1571 1572static int 1573inout_str_addrsize(uint32_t inst_info) 1574{ 1575 uint32_t size; 1576 1577 size = (inst_info >> 7) & 0x7; 1578 switch (size) { 1579 case 0: 1580 return (2); /* 16 bit */ 1581 case 1: 1582 return (4); /* 32 bit */ 1583 case 2: 1584 return (8); /* 64 bit */ 1585 default: 1586 panic("%s: invalid size encoding %d", __func__, size); 1587 } 1588} 1589 |
|
1531static void | 1590static void |
1591inout_str_seginfo(struct vmx *vmx, int vcpuid, uint32_t inst_info, int in, 1592 struct vm_inout_str *vis) 1593{ 1594 int error, s; 1595 1596 if (in) { 1597 vis->seg_name = VM_REG_GUEST_ES; 1598 } else { 1599 s = (inst_info >> 15) & 0x7; 1600 vis->seg_name = vm_segment_name(s); 1601 } 1602 1603 error = vmx_getdesc(vmx, vcpuid, vis->seg_name, &vis->seg_desc); 1604 KASSERT(error == 0, ("%s: vmx_getdesc error %d", __func__, error)); 1605 1606 /* XXX modify svm.c to update bit 16 of seg_desc.access (unusable) */ 1607} 1608 1609static void |
|
1532vmexit_inst_emul(struct vm_exit *vmexit, uint64_t gpa, uint64_t gla) 1533{ 1534 vmexit->exitcode = VM_EXITCODE_INST_EMUL; 1535 vmexit->u.inst_emul.gpa = gpa; 1536 vmexit->u.inst_emul.gla = gla; 1537 vmexit->u.inst_emul.cr3 = vmcs_guest_cr3(); 1538 vmexit->u.inst_emul.cpu_mode = vmx_cpu_mode(); 1539 vmexit->u.inst_emul.paging_mode = vmx_paging_mode(); --- 204 unchanged lines hidden (view full) --- 1744 * exitcode of VM_EXITCODE_VMX and will be dealt with in userland. 1745 */ 1746 return (UNHANDLED); 1747} 1748 1749static int 1750vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) 1751{ | 1610vmexit_inst_emul(struct vm_exit *vmexit, uint64_t gpa, uint64_t gla) 1611{ 1612 vmexit->exitcode = VM_EXITCODE_INST_EMUL; 1613 vmexit->u.inst_emul.gpa = gpa; 1614 vmexit->u.inst_emul.gla = gla; 1615 vmexit->u.inst_emul.cr3 = vmcs_guest_cr3(); 1616 vmexit->u.inst_emul.cpu_mode = vmx_cpu_mode(); 1617 vmexit->u.inst_emul.paging_mode = vmx_paging_mode(); --- 204 unchanged lines hidden (view full) --- 1822 * exitcode of VM_EXITCODE_VMX and will be dealt with in userland. 1823 */ 1824 return (UNHANDLED); 1825} 1826 1827static int 1828vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit) 1829{ |
1752 int error, handled; | 1830 int error, handled, in; |
1753 struct vmxctx *vmxctx; 1754 struct vlapic *vlapic; | 1831 struct vmxctx *vmxctx; 1832 struct vlapic *vlapic; |
1755 uint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, reason; | 1833 struct vm_inout_str *vis; 1834 uint32_t eax, ecx, edx, idtvec_info, idtvec_err, intr_info, inst_info; 1835 uint32_t reason; |
1756 uint64_t qual, gpa; 1757 bool retu; 1758 1759 CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_VIRTUAL_NMI) != 0); 1760 CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_NMI_EXITING) != 0); 1761 1762 handled = UNHANDLED; 1763 vmxctx = &vmx->ctx[vcpu]; --- 140 unchanged lines hidden (view full) --- 1904 vmx_inject_nmi(vmx, vcpu); 1905 vmx_clear_nmi_window_exiting(vmx, vcpu); 1906 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_NMI_WINDOW, 1); 1907 return (1); 1908 case EXIT_REASON_INOUT: 1909 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INOUT, 1); 1910 vmexit->exitcode = VM_EXITCODE_INOUT; 1911 vmexit->u.inout.bytes = (qual & 0x7) + 1; | 1836 uint64_t qual, gpa; 1837 bool retu; 1838 1839 CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_VIRTUAL_NMI) != 0); 1840 CTASSERT((PINBASED_CTLS_ONE_SETTING & PINBASED_NMI_EXITING) != 0); 1841 1842 handled = UNHANDLED; 1843 vmxctx = &vmx->ctx[vcpu]; --- 140 unchanged lines hidden (view full) --- 1984 vmx_inject_nmi(vmx, vcpu); 1985 vmx_clear_nmi_window_exiting(vmx, vcpu); 1986 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_NMI_WINDOW, 1); 1987 return (1); 1988 case EXIT_REASON_INOUT: 1989 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_INOUT, 1); 1990 vmexit->exitcode = VM_EXITCODE_INOUT; 1991 vmexit->u.inout.bytes = (qual & 0x7) + 1; |
1912 vmexit->u.inout.in = (qual & 0x8) ? 1 : 0; | 1992 vmexit->u.inout.in = in = (qual & 0x8) ? 1 : 0; |
1913 vmexit->u.inout.string = (qual & 0x10) ? 1 : 0; 1914 vmexit->u.inout.rep = (qual & 0x20) ? 1 : 0; 1915 vmexit->u.inout.port = (uint16_t)(qual >> 16); 1916 vmexit->u.inout.eax = (uint32_t)(vmxctx->guest_rax); | 1993 vmexit->u.inout.string = (qual & 0x10) ? 1 : 0; 1994 vmexit->u.inout.rep = (qual & 0x20) ? 1 : 0; 1995 vmexit->u.inout.port = (uint16_t)(qual >> 16); 1996 vmexit->u.inout.eax = (uint32_t)(vmxctx->guest_rax); |
1917 error = emulate_ioport(vmx->vm, vcpu, vmexit); 1918 if (error == 0) { 1919 handled = 1; 1920 vmxctx->guest_rax = vmexit->u.inout.eax; | 1997 if (vmexit->u.inout.string) { 1998 inst_info = vmcs_read(VMCS_EXIT_INSTRUCTION_INFO); 1999 vmexit->exitcode = VM_EXITCODE_INOUT_STR; 2000 vis = &vmexit->u.inout_str; 2001 vis->cpu_mode = vmx_cpu_mode(); 2002 vis->paging_mode = vmx_paging_mode(); 2003 vis->rflags = vmcs_read(VMCS_GUEST_RFLAGS); 2004 vis->cr0 = vmcs_read(VMCS_GUEST_CR0); 2005 vis->cr3 = vmcs_read(VMCS_GUEST_CR3); 2006 vis->cpl = vmx_cpl(); 2007 vis->index = inout_str_index(vmx, vcpu, in); 2008 vis->count = inout_str_count(vmx, vcpu, vis->inout.rep); 2009 vis->addrsize = inout_str_addrsize(inst_info); 2010 inout_str_seginfo(vmx, vcpu, inst_info, in, vis); 2011 vis->gla = vmcs_gla(); |
1921 } 1922 break; 1923 case EXIT_REASON_CPUID: 1924 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_CPUID, 1); 1925 handled = vmx_handle_cpuid(vmx->vm, vcpu, vmxctx); 1926 break; 1927 case EXIT_REASON_EXCEPTION: 1928 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_EXCEPTION, 1); --- 978 unchanged lines hidden --- | 2012 } 2013 break; 2014 case EXIT_REASON_CPUID: 2015 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_CPUID, 1); 2016 handled = vmx_handle_cpuid(vmx->vm, vcpu, vmxctx); 2017 break; 2018 case EXIT_REASON_EXCEPTION: 2019 vmm_stat_incr(vmx->vm, vcpu, VMEXIT_EXCEPTION, 1); --- 978 unchanged lines hidden --- |