svn commit: r261170 - in head/sys/amd64: include vmm vmm/intel vmm/io

Neel Natu neel at FreeBSD.org
Sat Jan 25 20:58:07 UTC 2014


Author: neel
Date: Sat Jan 25 20:58:05 2014
New Revision: 261170
URL: http://svnweb.freebsd.org/changeset/base/261170

Log:
  Support level triggered interrupts with VT-x virtual interrupt delivery.
  
  The VMCS field EOI_bitmap[] is an array of 256 bits - one for each vector.
  If a bit is set to '1' in the EOI_bitmap[] then the processor will trigger
  an EOI-induced VM-exit when it is doing EOI virtualization.
  
  The EOI-induced VM-exit results in the EOI being forwarded to the vioapic
  so that level triggered interrupts can be properly handled.
  
  Tested by:	Anish Gupta (akgupt3 at gmail.com)

Modified:
  head/sys/amd64/include/vmm.h
  head/sys/amd64/vmm/intel/vmcs.h
  head/sys/amd64/vmm/intel/vmx.c
  head/sys/amd64/vmm/io/vlapic.c
  head/sys/amd64/vmm/io/vlapic_priv.h
  head/sys/amd64/vmm/vmm.c

Modified: head/sys/amd64/include/vmm.h
==============================================================================
--- head/sys/amd64/include/vmm.h	Sat Jan 25 20:39:23 2014	(r261169)
+++ head/sys/amd64/include/vmm.h	Sat Jan 25 20:58:05 2014	(r261170)
@@ -298,6 +298,7 @@ enum vm_exitcode {
 	VM_EXITCODE_SPINUP_AP,
 	VM_EXITCODE_SPINDOWN_CPU,
 	VM_EXITCODE_RENDEZVOUS,
+	VM_EXITCODE_IOAPIC_EOI,
 	VM_EXITCODE_MAX
 };
 
@@ -354,6 +355,9 @@ struct vm_exit {
 		struct {
 			uint64_t	rflags;
 		} hlt;
+		struct {
+			int		vector;
+		} ioapic_eoi;
 	} u;
 };
 

Modified: head/sys/amd64/vmm/intel/vmcs.h
==============================================================================
--- head/sys/amd64/vmm/intel/vmcs.h	Sat Jan 25 20:39:23 2014	(r261169)
+++ head/sys/amd64/vmm/intel/vmcs.h	Sat Jan 25 20:58:05 2014	(r261170)
@@ -136,6 +136,7 @@ vmcs_write(uint32_t encoding, uint64_t v
 #define	VMCS_EOI_EXIT1			0x0000201E
 #define	VMCS_EOI_EXIT2			0x00002020
 #define	VMCS_EOI_EXIT3			0x00002022
+#define	VMCS_EOI_EXIT(vector)		(VMCS_EOI_EXIT0 + ((vector) / 64) * 2)
 
 /* 64-bit read-only fields */
 #define	VMCS_GUEST_PHYSICAL_ADDRESS	0x00002400
@@ -318,6 +319,7 @@ vmcs_write(uint32_t encoding, uint64_t v
 #define EXIT_REASON_MCE			41
 #define EXIT_REASON_TPR			43
 #define EXIT_REASON_APIC_ACCESS		44
+#define	EXIT_REASON_VIRTUALIZED_EOI	45
 #define EXIT_REASON_GDTR_IDTR		46
 #define EXIT_REASON_LDTR_TR		47
 #define EXIT_REASON_EPT_FAULT		48

Modified: head/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- head/sys/amd64/vmm/intel/vmx.c	Sat Jan 25 20:39:23 2014	(r261169)
+++ head/sys/amd64/vmm/intel/vmx.c	Sat Jan 25 20:58:05 2014	(r261170)
@@ -1726,6 +1726,11 @@ vmx_exit_process(struct vmx *vmx, int vc
 		    (qual & EXIT_QUAL_NMIUDTI) != 0)
 			vmx_restore_nmi_blocking(vmx, vcpu);
 		break;
+	case EXIT_REASON_VIRTUALIZED_EOI:
+		vmexit->exitcode = VM_EXITCODE_IOAPIC_EOI;
+		vmexit->u.ioapic_eoi.vector = qual & 0xFF;
+		vmexit->inst_length = 0;	/* trap-like */
+		break;
 	case EXIT_REASON_APIC_ACCESS:
 		handled = vmx_handle_apic_access(vmx, vcpu, vmexit);
 		break;
@@ -2320,6 +2325,7 @@ vmx_setcap(void *arg, int vcpu, int type
 struct vlapic_vtx {
 	struct vlapic	vlapic;
 	struct pir_desc	*pir_desc;
+	struct vmx	*vmx;
 };
 
 #define	VMX_CTR_PIR(vm, vcpuid, pir_desc, notify, vector, level, msg)	\
@@ -2345,9 +2351,6 @@ vmx_set_intr_ready(struct vlapic *vlapic
 	uint64_t mask;
 	int idx, notify;
 
-	/*
-	 * XXX need to deal with level triggered interrupts
-	 */
 	vlapic_vtx = (struct vlapic_vtx *)vlapic;
 	pir_desc = vlapic_vtx->pir_desc;
 
@@ -2422,6 +2425,33 @@ vmx_intr_accepted(struct vlapic *vlapic,
 }
 
 static void
+vmx_set_tmr(struct vlapic *vlapic, int vector, bool level)
+{
+	struct vlapic_vtx *vlapic_vtx;
+	struct vmx *vmx;
+	struct vmcs *vmcs;
+	uint64_t mask, val;
+
+	KASSERT(vector >= 0 && vector <= 255, ("invalid vector %d", vector));
+	KASSERT(!vcpu_is_running(vlapic->vm, vlapic->vcpuid, NULL),
+	    ("vmx_set_tmr: vcpu cannot be running"));
+
+	vlapic_vtx = (struct vlapic_vtx *)vlapic;
+	vmx = vlapic_vtx->vmx;
+	vmcs = &vmx->vmcs[vlapic->vcpuid];
+	mask = 1UL << (vector % 64);
+
+	VMPTRLD(vmcs);
+	val = vmcs_read(VMCS_EOI_EXIT(vector));
+	if (level)
+		val |= mask;
+	else
+		val &= ~mask;
+	vmcs_write(VMCS_EOI_EXIT(vector), val);
+	VMCLEAR(vmcs);
+}
+
+static void
 vmx_post_intr(struct vlapic *vlapic, int hostcpu)
 {
 
@@ -2519,11 +2549,13 @@ vmx_vlapic_init(void *arg, int vcpuid)
 
 	vlapic_vtx = (struct vlapic_vtx *)vlapic;
 	vlapic_vtx->pir_desc = &vmx->pir_desc[vcpuid];
+	vlapic_vtx->vmx = vmx;
 
 	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;
+		vlapic->ops.set_tmr = vmx_set_tmr;
 	}
 
 	if (posted_interrupts)

Modified: head/sys/amd64/vmm/io/vlapic.c
==============================================================================
--- head/sys/amd64/vmm/io/vlapic.c	Sat Jan 25 20:39:23 2014	(r261169)
+++ head/sys/amd64/vmm/io/vlapic.c	Sat Jan 25 20:58:05 2014	(r261170)
@@ -1300,6 +1300,7 @@ vlapic_reset(struct vlapic *vlapic)
 	lapic->dfr = 0xffffffff;
 	lapic->svr = APIC_SVR_VECTOR;
 	vlapic_mask_lvts(vlapic);
+	vlapic_reset_tmr(vlapic);
 
 	lapic->dcr_timer = 0;
 	vlapic_dcr_write_handler(vlapic);
@@ -1457,32 +1458,42 @@ vlapic_enabled(struct vlapic *vlapic)
 		return (false);
 }
 
+static void
+vlapic_set_tmr(struct vlapic *vlapic, int vector, bool level)
+{
+	struct LAPIC *lapic;
+	uint32_t *tmrptr, mask;
+	int idx;
+
+	lapic = vlapic->apic_page;
+	tmrptr = &lapic->tmr0;
+	idx = (vector / 32) * 4;
+	mask = 1 << (vector % 32);
+	if (level)
+		tmrptr[idx] |= mask;
+	else
+		tmrptr[idx] &= ~mask;
+
+	if (vlapic->ops.set_tmr != NULL)
+		(*vlapic->ops.set_tmr)(vlapic, vector, level);
+}
+
 void
 vlapic_reset_tmr(struct vlapic *vlapic)
 {
-	struct LAPIC *lapic;
+	int vector;
 
 	VLAPIC_CTR0(vlapic, "vlapic resetting all vectors to edge-triggered");
 
-	lapic = vlapic->apic_page;
-	lapic->tmr0 = 0;
-	lapic->tmr1 = 0;
-	lapic->tmr2 = 0;
-	lapic->tmr3 = 0;
-	lapic->tmr4 = 0;
-	lapic->tmr5 = 0;
-	lapic->tmr6 = 0;
-	lapic->tmr7 = 0;
+	for (vector = 0; vector <= 255; vector++)
+		vlapic_set_tmr(vlapic, vector, false);
 }
 
 void
 vlapic_set_tmr_level(struct vlapic *vlapic, uint32_t dest, bool phys,
     int delmode, int vector)
 {
-	struct LAPIC *lapic;
-	uint32_t *tmrptr, mask;
 	cpuset_t dmask;
-	int idx;
 	bool lowprio;
 
 	KASSERT(vector >= 0 && vector <= 255, ("invalid vector %d", vector));
@@ -1502,11 +1513,6 @@ vlapic_set_tmr_level(struct vlapic *vlap
 	if (!CPU_ISSET(vlapic->vcpuid, &dmask))
 		return;
 
-	lapic = vlapic->apic_page;
-	tmrptr = &lapic->tmr0;
-	idx = (vector / 32) * 4;
-	mask = 1 << (vector % 32);
-	tmrptr[idx] |= mask;
-
 	VLAPIC_CTR1(vlapic, "vector %d set to level-triggered", vector);
+	vlapic_set_tmr(vlapic, vector, true);
 }

Modified: head/sys/amd64/vmm/io/vlapic_priv.h
==============================================================================
--- head/sys/amd64/vmm/io/vlapic_priv.h	Sat Jan 25 20:39:23 2014	(r261169)
+++ head/sys/amd64/vmm/io/vlapic_priv.h	Sat Jan 25 20:58:05 2014	(r261170)
@@ -139,6 +139,7 @@ struct vlapic_ops {
 	int (*pending_intr)(struct vlapic *vlapic, int *vecptr);
 	void (*intr_accepted)(struct vlapic *vlapic, int vector);
 	void (*post_intr)(struct vlapic *vlapic, int hostcpu);
+	void (*set_tmr)(struct vlapic *vlapic, int vector, bool level);
 };
 
 struct vlapic {

Modified: head/sys/amd64/vmm/vmm.c
==============================================================================
--- head/sys/amd64/vmm/vmm.c	Sat Jan 25 20:39:23 2014	(r261169)
+++ head/sys/amd64/vmm/vmm.c	Sat Jan 25 20:58:05 2014	(r261170)
@@ -1150,6 +1150,10 @@ restart:
 	if (error == 0) {
 		retu = false;
 		switch (vme->exitcode) {
+		case VM_EXITCODE_IOAPIC_EOI:
+			vioapic_process_eoi(vm, vcpuid,
+			    vme->u.ioapic_eoi.vector);
+			break;
 		case VM_EXITCODE_RENDEZVOUS:
 			vm_handle_rendezvous(vm, vcpuid);
 			error = 0;


More information about the svn-src-all mailing list