Date: Sat, 11 Jan 2014 04:22:01 +0000 (UTC) From: Neel Natu <neel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r260532 - head/sys/amd64/vmm/intel Message-ID: <201401110422.s0B4M1Dc060182@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: neel Date: Sat Jan 11 04:22:00 2014 New Revision: 260532 URL: http://svnweb.freebsd.org/changeset/base/260532 Log: Enable "Posted Interrupt Processing" if supported by the CPU. This lets us inject interrupts into the guest without causing a VM-exit. This feature can be disabled by setting the tunable "hw.vmm.vmx.use_apic_pir" to "0". The following sysctls provide information about this feature: - hw.vmm.vmx.posted_interrupts (0 if disabled, 1 if enabled) - hw.vmm.vmx.posted_interrupt_vector (vector number used for vcpu notification) Tested on a Intel Xeon E5-2620v2 courtesy of Allan Jude at ScaleEngine. Modified: head/sys/amd64/vmm/intel/vmcs.h head/sys/amd64/vmm/intel/vmx.c head/sys/amd64/vmm/intel/vmx.h Modified: head/sys/amd64/vmm/intel/vmcs.h ============================================================================== --- head/sys/amd64/vmm/intel/vmcs.h Sat Jan 11 03:14:05 2014 (r260531) +++ head/sys/amd64/vmm/intel/vmcs.h Sat Jan 11 04:22:00 2014 (r260532) @@ -97,6 +97,7 @@ vmcs_write(uint32_t encoding, uint64_t v /* 16-bit control fields */ #define VMCS_VPID 0x00000000 +#define VMCS_PIR_VECTOR 0x00000002 /* 16-bit guest-state fields */ #define VMCS_GUEST_ES_SELECTOR 0x00000800 @@ -129,6 +130,7 @@ vmcs_write(uint32_t encoding, uint64_t v #define VMCS_TSC_OFFSET 0x00002010 #define VMCS_VIRTUAL_APIC 0x00002012 #define VMCS_APIC_ACCESS 0x00002014 +#define VMCS_PIR_DESC 0x00002016 #define VMCS_EPTP 0x0000201A #define VMCS_EOI_EXIT0 0x0000201C #define VMCS_EOI_EXIT1 0x0000201E Modified: head/sys/amd64/vmm/intel/vmx.c ============================================================================== --- head/sys/amd64/vmm/intel/vmx.c Sat Jan 11 03:14:05 2014 (r260531) +++ head/sys/amd64/vmm/intel/vmx.c Sat Jan 11 04:22:00 2014 (r260532) @@ -45,11 +45,13 @@ __FBSDID("$FreeBSD$"); #include <machine/cpufunc.h> #include <machine/md_var.h> #include <machine/segments.h> +#include <machine/smp.h> #include <machine/specialreg.h> #include <machine/vmparam.h> #include <machine/vmm.h> #include "vmm_host.h" +#include "vmm_ipi.h" #include "vmm_msr.h" #include "vmm_ktr.h" #include "vmm_stat.h" @@ -172,6 +174,14 @@ static int virtual_interrupt_delivery; SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, virtual_interrupt_delivery, CTLFLAG_RD, &virtual_interrupt_delivery, 0, "APICv virtual interrupt delivery support"); +static int posted_interrupts; +SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, posted_interrupts, CTLFLAG_RD, + &posted_interrupts, 0, "APICv posted interrupt support"); + +static int pirvec; +SYSCTL_INT(_hw_vmm_vmx, OID_AUTO, posted_interrupt_vector, CTLFLAG_RD, + &pirvec, 0, "APICv posted interrupt vector"); + static struct unrhdr *vpid_unr; static u_int vpid_alloc_failed; SYSCTL_UINT(_hw_vmm_vmx, OID_AUTO, vpid_alloc_failed, CTLFLAG_RD, @@ -442,6 +452,9 @@ vmx_disable(void *arg __unused) static int vmx_cleanup(void) { + + if (pirvec != 0) + vmm_ipi_free(pirvec); if (vpid_unr != NULL) { delete_unrhdr(vpid_unr); @@ -637,8 +650,32 @@ vmx_init(int ipinum) procbased_ctls |= PROCBASED_USE_TPR_SHADOW; procbased_ctls2 |= procbased2_vid_bits; procbased_ctls2 &= ~PROCBASED2_VIRTUALIZE_X2APIC_MODE; + + /* + * Check for Posted Interrupts only if Virtual Interrupt + * Delivery is enabled. + */ + error = vmx_set_ctlreg(MSR_VMX_PINBASED_CTLS, + MSR_VMX_TRUE_PINBASED_CTLS, PINBASED_POSTED_INTERRUPT, 0, + &tmp); + if (error == 0) { + pirvec = vmm_ipi_alloc(); + if (pirvec == 0) { + if (bootverbose) { + printf("vmx_init: unable to allocate " + "posted interrupt vector\n"); + } + } else { + posted_interrupts = 1; + TUNABLE_INT_FETCH("hw.vmm.vmx.use_apic_pir", + &posted_interrupts); + } + } } + if (posted_interrupts) + pinbased_ctls |= PINBASED_POSTED_INTERRUPT; + /* Initialize EPT */ error = ept_init(ipinum); if (error) { @@ -848,6 +885,11 @@ vmx_vminit(struct vm *vm, pmap_t pmap) error += vmwrite(VMCS_EOI_EXIT2, 0); error += vmwrite(VMCS_EOI_EXIT3, 0); } + if (posted_interrupts) { + error += vmwrite(VMCS_PIR_VECTOR, pirvec); + error += vmwrite(VMCS_PIR_DESC, + vtophys(&vmx->pir_desc[i])); + } VMCLEAR(vmcs); KASSERT(error == 0, ("vmx_vminit: error customizing the vmcs")); @@ -2132,19 +2174,9 @@ vmx_setcap(void *arg, int vcpu, int type return (retval); } -/* - * Posted Interrupt Descriptor (described in section 29.6 of the Intel SDM). - */ -struct pir_desc { - uint64_t pir[4]; - uint64_t pending; - uint64_t unused[3]; -} __aligned(64); -CTASSERT(sizeof(struct pir_desc) == 64); - struct vlapic_vtx { struct vlapic vlapic; - struct pir_desc pir_desc; + struct pir_desc *pir_desc; }; #define VMX_CTR_PIR(vm, vcpuid, pir_desc, notify, vector, level, msg) \ @@ -2174,7 +2206,7 @@ vmx_set_intr_ready(struct vlapic *vlapic * XXX need to deal with level triggered interrupts */ vlapic_vtx = (struct vlapic_vtx *)vlapic; - pir_desc = &vlapic_vtx->pir_desc; + pir_desc = vlapic_vtx->pir_desc; /* * Keep track of interrupt requests in the PIR descriptor. This is @@ -2208,7 +2240,7 @@ vmx_pending_intr(struct vlapic *vlapic, KASSERT(vecptr == NULL, ("vmx_pending_intr: vecptr must be NULL")); vlapic_vtx = (struct vlapic_vtx *)vlapic; - pir_desc = &vlapic_vtx->pir_desc; + pir_desc = vlapic_vtx->pir_desc; pending = atomic_load_acq_long(&pir_desc->pending); if (!pending) @@ -2246,6 +2278,13 @@ vmx_intr_accepted(struct vlapic *vlapic, panic("vmx_intr_accepted: not expected to be called"); } +static void +vmx_post_intr(struct vlapic *vlapic, int hostcpu) +{ + + ipi_cpu(hostcpu, pirvec); +} + /* * Transfer the pending interrupts in the PIR descriptor to the IRR * in the virtual APIC page. @@ -2261,7 +2300,7 @@ vmx_inject_pir(struct vlapic *vlapic) uint16_t intr_status_old, intr_status_new; vlapic_vtx = (struct vlapic_vtx *)vlapic; - pir_desc = &vlapic_vtx->pir_desc; + pir_desc = vlapic_vtx->pir_desc; if (atomic_cmpset_long(&pir_desc->pending, 1, 0) == 0) { VCPU_CTR0(vlapic->vm, vlapic->vcpuid, "vmx_inject_pir: " "no posted interrupt pending"); @@ -2326,6 +2365,7 @@ vmx_vlapic_init(void *arg, int vcpuid) { struct vmx *vmx; struct vlapic *vlapic; + struct vlapic_vtx *vlapic_vtx; vmx = arg; @@ -2334,12 +2374,18 @@ vmx_vlapic_init(void *arg, int vcpuid) vlapic->vcpuid = vcpuid; vlapic->apic_page = (struct LAPIC *)&vmx->apic_page[vcpuid]; + vlapic_vtx = (struct vlapic_vtx *)vlapic; + vlapic_vtx->pir_desc = &vmx->pir_desc[vcpuid]; + if (virtual_interrupt_delivery) { vlapic->ops.set_intr_ready = vmx_set_intr_ready; vlapic->ops.pending_intr = vmx_pending_intr; vlapic->ops.intr_accepted = vmx_intr_accepted; } + if (posted_interrupts) + vlapic->ops.post_intr = vmx_post_intr; + vlapic_init(vlapic); return (vlapic); Modified: head/sys/amd64/vmm/intel/vmx.h ============================================================================== --- head/sys/amd64/vmm/intel/vmx.h Sat Jan 11 03:14:05 2014 (r260531) +++ head/sys/amd64/vmm/intel/vmx.h Sat Jan 11 04:22:00 2014 (r260532) @@ -93,11 +93,20 @@ struct apic_page { }; CTASSERT(sizeof(struct apic_page) == PAGE_SIZE); +/* Posted Interrupt Descriptor (described in section 29.6 of the Intel SDM) */ +struct pir_desc { + uint64_t pir[4]; + uint64_t pending; + uint64_t unused[3]; +} __aligned(64); +CTASSERT(sizeof(struct pir_desc) == 64); + /* virtual machine softc */ struct vmx { struct vmcs vmcs[VM_MAXCPU]; /* one vmcs per virtual cpu */ struct apic_page apic_page[VM_MAXCPU]; /* one apic page per vcpu */ char msr_bitmap[PAGE_SIZE]; + struct pir_desc pir_desc[VM_MAXCPU]; struct msr_entry guest_msrs[VM_MAXCPU][GUEST_MSR_MAX_ENTRIES]; struct vmxctx ctx[VM_MAXCPU]; struct vmxcap cap[VM_MAXCPU]; @@ -108,6 +117,7 @@ struct vmx { CTASSERT((offsetof(struct vmx, vmcs) & PAGE_MASK) == 0); CTASSERT((offsetof(struct vmx, msr_bitmap) & PAGE_MASK) == 0); CTASSERT((offsetof(struct vmx, guest_msrs) & 15) == 0); +CTASSERT((offsetof(struct vmx, pir_desc[0]) & 63) == 0); #define VMX_GUEST_VMEXIT 0 #define VMX_VMRESUME_ERROR 1
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201401110422.s0B4M1Dc060182>