Deleted Added
sdiff udiff text old ( 271912 ) new ( 271939 )
full compact
1/*-
2 * Copyright (c) 2013, Anish Gupta (akgupt3@gmail.com)
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

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

20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: projects/bhyve_svm/sys/amd64/vmm/amd/svm.c 271939 2014-09-21 23:42:54Z neel $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/smp.h>
33#include <sys/kernel.h>
34#include <sys/malloc.h>
35#include <sys/pcpu.h>
36#include <sys/proc.h>

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

84#define AMD_CPUID_SVM_DECODE_ASSIST BIT(7) /* Decode assist */
85#define AMD_CPUID_SVM_PAUSE_INC BIT(10) /* Pause intercept filter. */
86#define AMD_CPUID_SVM_PAUSE_FTH BIT(12) /* Pause filter threshold */
87
88#define VMCB_CACHE_DEFAULT (VMCB_CACHE_ASID | \
89 VMCB_CACHE_IOPM | \
90 VMCB_CACHE_I | \
91 VMCB_CACHE_TPR | \
92 VMCB_CACHE_CR2 | \
93 VMCB_CACHE_CR | \
94 VMCB_CACHE_DT | \
95 VMCB_CACHE_SEG | \
96 VMCB_CACHE_NP)
97
98static uint32_t vmcb_clean = VMCB_CACHE_DEFAULT;
99SYSCTL_INT(_hw_vmm_svm, OID_AUTO, vmcb_clean, CTLFLAG_RDTUN, &vmcb_clean,
100 0, NULL);
101
102MALLOC_DEFINE(M_SVM, "svm", "svm");
103MALLOC_DEFINE(M_SVM_VLAPIC, "svm-vlapic", "svm-vlapic");
104
105/* Per-CPU context area. */
106extern struct pcpu __pcpu[];
107
108static uint32_t svm_feature; /* AMD SVM features. */
109SYSCTL_UINT(_hw_vmm_svm, OID_AUTO, features, CTLFLAG_RD, &svm_feature, 0,
110 "SVM features advertised by CPUID.8000000AH:EDX");
111
112static int disable_npf_assist;
113SYSCTL_INT(_hw_vmm_svm, OID_AUTO, disable_npf_assist, CTLFLAG_RWTUN,
114 &disable_npf_assist, 0, NULL);
115

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

130 * S/w saved host context.
131 */
132static struct svm_regctx host_ctx[MAXCPU];
133
134static VMM_STAT_AMD(VCPU_EXITINTINFO, "VM exits during event delivery");
135static VMM_STAT_AMD(VCPU_INTINFO_INJECTED, "Events pending at VM entry");
136static VMM_STAT_AMD(VMEXIT_VINTR, "VM exits due to interrupt window");
137
138static int svm_setreg(void *arg, int vcpu, int ident, uint64_t val);
139
140/*
141 * Common function to enable or disabled SVM for a CPU.
142 */
143static int
144cpu_svm_enable_disable(boolean_t enable)
145{
146 uint64_t efer_msr;
147

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

295svm_init(int ipinum)
296{
297 int err, cpu;
298
299 err = is_svm_enabled();
300 if (err)
301 return (err);
302
303 vmcb_clean &= VMCB_CACHE_DEFAULT;
304
305 for (cpu = 0; cpu < MAXCPU; cpu++) {
306 /*
307 * Initialize the host ASIDs to their "highest" valid values.
308 *
309 * The next ASID allocation will rollover both 'gen' and 'num'
310 * and start off the sequence at {1,1}.
311 */
312 asid[cpu].gen = ~0UL;

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

415}
416
417static int
418svm_msr_rd_ok(uint8_t *perm_bitmap, uint64_t msr)
419{
420 return svm_msr_perm(perm_bitmap, msr, true, false);
421}
422
423static __inline int
424svm_get_intercept(struct svm_softc *sc, int vcpu, int idx, uint32_t bitmask)
425{
426 struct vmcb_ctrl *ctrl;
427
428 KASSERT(idx >=0 && idx < 5, ("invalid intercept index %d", idx));
429
430 ctrl = svm_get_vmcb_ctrl(sc, vcpu);

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

444 oldval = ctrl->intercept[idx];
445
446 if (enabled)
447 ctrl->intercept[idx] |= bitmask;
448 else
449 ctrl->intercept[idx] &= ~bitmask;
450
451 if (ctrl->intercept[idx] != oldval) {
452 svm_set_dirty(sc, vcpu, VMCB_CACHE_I);
453 VCPU_CTR3(sc->vm, vcpu, "intercept[%d] modified "
454 "from %#x to %#x", idx, oldval, ctrl->intercept[idx]);
455 }
456}
457
458static __inline void
459svm_disable_intercept(struct svm_softc *sc, int vcpu, int off, uint32_t bitmask)
460{

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

587 svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_SYSENTER_CS_MSR);
588 svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_SYSENTER_ESP_MSR);
589 svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_SYSENTER_EIP_MSR);
590
591 /* For Nested Paging/RVI only. */
592 svm_msr_rw_ok(svm_sc->msr_bitmap, MSR_PAT);
593
594 svm_msr_rd_ok(svm_sc->msr_bitmap, MSR_TSC);
595
596 /*
597 * Intercept writes to make sure that the EFER_SVM bit is not cleared.
598 */
599 svm_msr_rd_ok(svm_sc->msr_bitmap, MSR_EFER);
600
601 /* Intercept access to all I/O ports. */
602 memset(svm_sc->iopm_bitmap, 0xFF, sizeof(svm_sc->iopm_bitmap));
603
604 /* Cache physical address for multiple vcpus. */
605 iopm_pa = vtophys(svm_sc->iopm_bitmap);
606 msrpm_pa = vtophys(svm_sc->msr_bitmap);

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

626 * from any segment DPL"
627 */
628 return (state->cpl);
629}
630
631static enum vm_cpu_mode
632svm_vcpu_mode(struct vmcb *vmcb)
633{
634 struct vmcb_segment seg;
635 struct vmcb_state *state;
636 int error;
637
638 state = &vmcb->state;
639
640 if (state->efer & EFER_LMA) {
641 error = vmcb_seg(vmcb, VM_REG_GUEST_CS, &seg);
642 KASSERT(error == 0, ("%s: vmcb_seg(cs) error %d", __func__,
643 error));
644
645 /*
646 * Section 4.8.1 for APM2, check if Code Segment has
647 * Long attribute set in descriptor.
648 */
649 if (seg.attrib & VMCB_CS_ATTRIB_L)
650 return (CPU_MODE_64BIT);
651 else
652 return (CPU_MODE_COMPATIBILITY);
653 } else if (state->cr0 & CR0_PE) {
654 return (CPU_MODE_PROTECTED);
655 } else {
656 return (CPU_MODE_REAL);
657 }

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

703 if (in) {
704 vis->seg_name = VM_REG_GUEST_ES;
705 } else {
706 /* The segment field has standard encoding */
707 s = (info1 >> 10) & 0x7;
708 vis->seg_name = vm_segment_name(s);
709 }
710
711 error = vmcb_getdesc(svm_sc, vcpu, vis->seg_name, &vis->seg_desc);
712 KASSERT(error == 0, ("%s: svm_getdesc error %d", __func__, error));
713}
714
715static int
716svm_inout_str_addrsize(uint64_t info1)
717{
718 uint32_t size;
719

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

827
828 return (true);
829}
830
831static void
832svm_handle_inst_emul(struct vmcb *vmcb, uint64_t gpa, struct vm_exit *vmexit)
833{
834 struct vm_guest_paging *paging;
835 struct vmcb_segment seg;
836 struct vmcb_ctrl *ctrl;
837 char *inst_bytes;
838 int error, inst_len;
839
840 ctrl = &vmcb->ctrl;
841 paging = &vmexit->u.inst_emul.paging;
842
843 vmexit->exitcode = VM_EXITCODE_INST_EMUL;
844 vmexit->u.inst_emul.gpa = gpa;
845 vmexit->u.inst_emul.gla = VIE_INVALID_GLA;
846 svm_paging_info(vmcb, paging);
847
848 error = vmcb_seg(vmcb, VM_REG_GUEST_CS, &seg);
849 KASSERT(error == 0, ("%s: vmcb_seg(CS) error %d", __func__, error));
850
851 switch(paging->cpu_mode) {
852 case CPU_MODE_PROTECTED:
853 case CPU_MODE_COMPATIBILITY:
854 /*
855 * Section 4.8.1 of APM2, Default Operand Size or D bit.
856 */
857 vmexit->u.inst_emul.cs_d = (seg.attrib & VMCB_CS_ATTRIB_D) ?
858 1 : 0;
859 break;
860 default:
861 vmexit->u.inst_emul.cs_d = 0;
862 break;
863 }
864
865 /*

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

870 inst_bytes = ctrl->inst_bytes;
871 } else {
872 inst_len = 0;
873 inst_bytes = NULL;
874 }
875 vie_init(&vmexit->u.inst_emul.vie, inst_bytes, inst_len);
876}
877
878#ifdef KTR
879static const char *
880intrtype_to_str(int intr_type)
881{
882 switch (intr_type) {
883 case VMCB_EVENTINJ_TYPE_INTR:
884 return ("hwintr");
885 case VMCB_EVENTINJ_TYPE_NMI:

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

1011 ("%s: vintr intercept should be enabled", __func__));
1012 return;
1013 }
1014
1015 VCPU_CTR0(sc->vm, vcpu, "Enable intr window exiting");
1016 ctrl->v_irq = 1;
1017 ctrl->v_ign_tpr = 1;
1018 ctrl->v_intr_vector = 0;
1019 svm_set_dirty(sc, vcpu, VMCB_CACHE_TPR);
1020 svm_enable_intercept(sc, vcpu, VMCB_CTRL1_INTCPT, VMCB_INTCPT_VINTR);
1021}
1022
1023static __inline void
1024disable_intr_window_exiting(struct svm_softc *sc, int vcpu)
1025{
1026 struct vmcb_ctrl *ctrl;
1027

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

1036#ifdef KTR
1037 if (ctrl->v_intr_vector == 0)
1038 VCPU_CTR0(sc->vm, vcpu, "Disable intr window exiting");
1039 else
1040 VCPU_CTR0(sc->vm, vcpu, "Clearing V_IRQ interrupt injection");
1041#endif
1042 ctrl->v_irq = 0;
1043 ctrl->v_intr_vector = 0;
1044 svm_set_dirty(sc, vcpu, VMCB_CACHE_TPR);
1045 svm_disable_intercept(sc, vcpu, VMCB_CTRL1_INTCPT, VMCB_INTCPT_VINTR);
1046}
1047
1048static int
1049svm_modify_intr_shadow(struct svm_softc *sc, int vcpu, uint64_t val)
1050{
1051 struct vmcb_ctrl *ctrl;
1052 int oldval, newval;

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

1127emulate_wrmsr(struct svm_softc *sc, int vcpu, u_int num, uint64_t val,
1128 bool *retu)
1129{
1130 int error;
1131
1132 if (lapic_msr(num))
1133 error = lapic_wrmsr(sc->vm, vcpu, num, val, retu);
1134 else if (num == MSR_EFER)
1135 error = svm_setreg(sc, vcpu, VM_REG_GUEST_EFER, val);
1136 else
1137 error = svm_wrmsr(sc, vcpu, num, val, retu);
1138
1139 return (error);
1140}
1141
1142static int
1143emulate_rdmsr(struct svm_softc *sc, int vcpu, u_int num, bool *retu)

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

1605 * VMRUN.
1606 */
1607 v_tpr = vlapic_get_cr8(vlapic);
1608 KASSERT(v_tpr >= 0 && v_tpr <= 15, ("invalid v_tpr %#x", v_tpr));
1609 if (ctrl->v_tpr != v_tpr) {
1610 VCPU_CTR2(sc->vm, vcpu, "VMCB V_TPR changed from %#x to %#x",
1611 ctrl->v_tpr, v_tpr);
1612 ctrl->v_tpr = v_tpr;
1613 svm_set_dirty(sc, vcpu, VMCB_CACHE_TPR);
1614 }
1615
1616 if (pending_apic_vector) {
1617 /*
1618 * If an APIC vector is being injected then interrupt window
1619 * exiting is not possible on this VMRUN.
1620 */
1621 KASSERT(!need_intr_window, ("intr_window exiting impossible"));
1622 VCPU_CTR1(sc->vm, vcpu, "Injecting vector %d using V_IRQ",
1623 pending_apic_vector);
1624
1625 ctrl->v_irq = 1;
1626 ctrl->v_ign_tpr = 0;
1627 ctrl->v_intr_vector = pending_apic_vector;
1628 ctrl->v_intr_prio = pending_apic_vector >> 4;
1629 svm_set_dirty(sc, vcpu, VMCB_CACHE_TPR);
1630 } else if (need_intr_window) {
1631 /*
1632 * We use V_IRQ in conjunction with the VINTR intercept to
1633 * trap into the hypervisor as soon as a virtual interrupt
1634 * can be delivered.
1635 *
1636 * Since injected events are not subject to intercept checks
1637 * we need to ensure that the V_IRQ is not actually going to

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

1747 */
1748 if (!flush_by_asid())
1749 ctrl->tlb_ctrl = VMCB_TLB_FLUSH_ALL;
1750 }
1751 vcpustate->asid.gen = asid[thiscpu].gen;
1752 vcpustate->asid.num = asid[thiscpu].num;
1753
1754 ctrl->asid = vcpustate->asid.num;
1755 svm_set_dirty(sc, vcpuid, VMCB_CACHE_ASID);
1756 /*
1757 * If this cpu supports "flush-by-asid" then the TLB
1758 * was not flushed after the generation bump. The TLB
1759 * is flushed selectively after every new ASID allocation.
1760 */
1761 if (flush_by_asid())
1762 ctrl->tlb_ctrl = VMCB_TLB_FLUSH_GUEST;
1763 }

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

1813 /*
1814 * Force new ASID allocation by invalidating the generation.
1815 */
1816 vcpustate->asid.gen = 0;
1817
1818 /*
1819 * Invalidate the VMCB state cache by marking all fields dirty.
1820 */
1821 svm_set_dirty(svm_sc, vcpu, 0xffffffff);
1822
1823 /*
1824 * XXX
1825 * Setting 'vcpustate->lastcpu' here is bit premature because
1826 * we may return from this function without actually executing
1827 * the VMRUN instruction. This could happen if a rendezvous
1828 * or an AST is pending on the first time through the loop.
1829 *

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

1874 CPU_SET_ATOMIC_ACQ(thiscpu, &pmap->pm_active);
1875
1876 /*
1877 * Check the pmap generation and the ASID generation to
1878 * ensure that the vcpu does not use stale TLB mappings.
1879 */
1880 check_asid(svm_sc, vcpu, pmap, thiscpu);
1881
1882 ctrl->vmcb_clean = vmcb_clean & ~vcpustate->dirty;
1883 vcpustate->dirty = 0;
1884 VCPU_CTR1(vm, vcpu, "vmcb clean %#x", ctrl->vmcb_clean);
1885
1886 /* Launch Virtual Machine. */
1887 VCPU_CTR1(vm, vcpu, "Resume execution at %#lx", state->rip);
1888 svm_launch(vmcb_pa, gctx, hctx);
1889
1890 CPU_CLR_ATOMIC(thiscpu, &pmap->pm_active);

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

1984/*
1985 * Interface to read guest registers.
1986 * This can be SVM h/w saved or hypervisor saved register.
1987 */
1988static int
1989svm_getreg(void *arg, int vcpu, int ident, uint64_t *val)
1990{
1991 struct svm_softc *svm_sc;
1992 register_t *reg;
1993
1994 svm_sc = arg;
1995
1996 if (ident == VM_REG_GUEST_INTR_SHADOW) {
1997 return (svm_get_intr_shadow(svm_sc, vcpu, val));
1998 }
1999
2000 if (vmcb_read(svm_sc, vcpu, ident, val) == 0) {
2001 return (0);
2002 }
2003
2004 reg = swctx_regptr(svm_get_guest_regctx(svm_sc, vcpu), ident);
2005
2006 if (reg != NULL) {
2007 *val = *reg;
2008 return (0);

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

2015/*
2016 * Interface to write to guest registers.
2017 * This can be SVM h/w saved or hypervisor saved register.
2018 */
2019static int
2020svm_setreg(void *arg, int vcpu, int ident, uint64_t val)
2021{
2022 struct svm_softc *svm_sc;
2023 register_t *reg;
2024
2025 svm_sc = arg;
2026
2027 if (ident == VM_REG_GUEST_INTR_SHADOW) {
2028 return (svm_modify_intr_shadow(svm_sc, vcpu, val));
2029 }
2030
2031 if (vmcb_write(svm_sc, vcpu, ident, val) == 0) {
2032 return (0);
2033 }
2034
2035 reg = swctx_regptr(svm_get_guest_regctx(svm_sc, vcpu), ident);
2036
2037 if (reg != NULL) {
2038 *reg = val;
2039 return (0);

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

2044 * vcpu's ASID. This needs to be treated differently depending on
2045 * whether 'running' is true/false.
2046 */
2047
2048 ERR("SVM_ERR:reg type %x is not saved in VMCB.\n", ident);
2049 return (EINVAL);
2050}
2051
2052static int
2053svm_setcap(void *arg, int vcpu, int type, int val)
2054{
2055 struct svm_softc *sc;
2056 int error;
2057
2058 sc = arg;
2059 error = 0;
2060 switch (type) {

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

2135 svm_init,
2136 svm_cleanup,
2137 svm_restore,
2138 svm_vminit,
2139 svm_vmrun,
2140 svm_vmcleanup,
2141 svm_getreg,
2142 svm_setreg,
2143 vmcb_getdesc,
2144 vmcb_setdesc,
2145 svm_getcap,
2146 svm_setcap,
2147 svm_npt_alloc,
2148 svm_npt_free,
2149 svm_vlapic_init,
2150 svm_vlapic_cleanup
2151};