svn commit: r260532 - head/sys/amd64/vmm/intel
Neel Natu
neel at FreeBSD.org
Sat Jan 11 04:22:02 UTC 2014
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
More information about the svn-src-all
mailing list