svn commit: r267447 - in stable/10: sys/amd64/include sys/amd64/vmm sys/amd64/vmm/intel sys/amd64/vmm/io usr.sbin/bhyve

John Baldwin jhb at FreeBSD.org
Fri Jun 13 19:10:42 UTC 2014


Author: jhb
Date: Fri Jun 13 19:10:40 2014
New Revision: 267447
URL: http://svnweb.freebsd.org/changeset/base/267447

Log:
  MFC 262139,262140,262236,262281,262532:
  Various x2APIC fixes and enhancements:
  - Use spinlocks for the vioapic.
  - Handle the SELF_IPI MSR.
  - Simplify the APIC mode switching between MMIO and x2APIC.  The guest is
    no longer allowed to switch modes at runtime.  Instead, the desired mode
    is set when the virtual machine is created.
  - Disallow MMIO access in x2APIC mode and MSR access in xAPIC mode.
  - Add support for x2APIC virtualization assist in Intel VT-x.

Modified:
  stable/10/sys/amd64/include/vmm.h
  stable/10/sys/amd64/vmm/intel/vmx.c
  stable/10/sys/amd64/vmm/io/vioapic.c
  stable/10/sys/amd64/vmm/io/vlapic.c
  stable/10/sys/amd64/vmm/io/vlapic.h
  stable/10/sys/amd64/vmm/io/vlapic_priv.h
  stable/10/sys/amd64/vmm/vmm.c
  stable/10/sys/amd64/vmm/vmm_lapic.c
  stable/10/sys/amd64/vmm/x86.c
  stable/10/usr.sbin/bhyve/bhyve.8
  stable/10/usr.sbin/bhyve/bhyverun.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/amd64/include/vmm.h
==============================================================================
--- stable/10/sys/amd64/include/vmm.h	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/sys/amd64/include/vmm.h	Fri Jun 13 19:10:40 2014	(r267447)
@@ -273,9 +273,8 @@ enum vm_cap_type {
 };
 
 enum x2apic_state {
-	X2APIC_ENABLED,
-	X2APIC_AVAILABLE,
 	X2APIC_DISABLED,
+	X2APIC_ENABLED,
 	X2APIC_STATE_LAST
 };
 

Modified: stable/10/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- stable/10/sys/amd64/vmm/intel/vmx.c	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/sys/amd64/vmm/intel/vmx.c	Fri Jun 13 19:10:40 2014	(r267447)
@@ -114,6 +114,9 @@ __FBSDID("$FreeBSD$");
 #define	guest_msr_rw(vmx, msr) \
 	msr_bitmap_change_access((vmx)->msr_bitmap, (msr), MSR_BITMAP_ACCESS_RW)
 
+#define	guest_msr_ro(vmx, msr) \
+    msr_bitmap_change_access((vmx)->msr_bitmap, (msr), MSR_BITMAP_ACCESS_READ)
+
 #define	HANDLED		1
 #define	UNHANDLED	0
 
@@ -302,6 +305,54 @@ exit_reason_to_str(int reason)
 }
 #endif	/* KTR */
 
+static int
+vmx_allow_x2apic_msrs(struct vmx *vmx)
+{
+	int i, error;
+
+	error = 0;
+
+	/*
+	 * Allow readonly access to the following x2APIC MSRs from the guest.
+	 */
+	error += guest_msr_ro(vmx, MSR_APIC_ID);
+	error += guest_msr_ro(vmx, MSR_APIC_VERSION);
+	error += guest_msr_ro(vmx, MSR_APIC_LDR);
+	error += guest_msr_ro(vmx, MSR_APIC_SVR);
+
+	for (i = 0; i < 8; i++)
+		error += guest_msr_ro(vmx, MSR_APIC_ISR0 + i);
+
+	for (i = 0; i < 8; i++)
+		error += guest_msr_ro(vmx, MSR_APIC_TMR0 + i);
+	
+	for (i = 0; i < 8; i++)
+		error += guest_msr_ro(vmx, MSR_APIC_IRR0 + i);
+
+	error += guest_msr_ro(vmx, MSR_APIC_ESR);
+	error += guest_msr_ro(vmx, MSR_APIC_LVT_TIMER);
+	error += guest_msr_ro(vmx, MSR_APIC_LVT_THERMAL);
+	error += guest_msr_ro(vmx, MSR_APIC_LVT_PCINT);
+	error += guest_msr_ro(vmx, MSR_APIC_LVT_LINT0);
+	error += guest_msr_ro(vmx, MSR_APIC_LVT_LINT1);
+	error += guest_msr_ro(vmx, MSR_APIC_LVT_ERROR);
+	error += guest_msr_ro(vmx, MSR_APIC_ICR_TIMER);
+	error += guest_msr_ro(vmx, MSR_APIC_DCR_TIMER);
+	error += guest_msr_ro(vmx, MSR_APIC_ICR);
+
+	/*
+	 * Allow TPR, EOI and SELF_IPI MSRs to be read and written by the guest.
+	 *
+	 * These registers get special treatment described in the section
+	 * "Virtualizing MSR-Based APIC Accesses".
+	 */
+	error += guest_msr_rw(vmx, MSR_APIC_TPR);
+	error += guest_msr_rw(vmx, MSR_APIC_EOI);
+	error += guest_msr_rw(vmx, MSR_APIC_SELF_IPI);
+
+	return (error);
+}
+
 u_long
 vmx_fix_cr0(u_long cr0)
 {
@@ -1499,17 +1550,53 @@ ept_emulation_fault(uint64_t ept_qual)
 	return (TRUE);
 }
 
+static __inline int
+apic_access_virtualization(struct vmx *vmx, int vcpuid)
+{
+	uint32_t proc_ctls2;
+
+	proc_ctls2 = vmx->cap[vcpuid].proc_ctls2;
+	return ((proc_ctls2 & PROCBASED2_VIRTUALIZE_APIC_ACCESSES) ? 1 : 0);
+}
+
+static __inline int
+x2apic_virtualization(struct vmx *vmx, int vcpuid)
+{
+	uint32_t proc_ctls2;
+
+	proc_ctls2 = vmx->cap[vcpuid].proc_ctls2;
+	return ((proc_ctls2 & PROCBASED2_VIRTUALIZE_X2APIC_MODE) ? 1 : 0);
+}
+
 static int
-vmx_handle_apic_write(struct vlapic *vlapic, uint64_t qual)
+vmx_handle_apic_write(struct vmx *vmx, int vcpuid, struct vlapic *vlapic,
+    uint64_t qual)
 {
 	int error, handled, offset;
+	uint32_t *apic_regs, vector;
 	bool retu;
 
-	if (!virtual_interrupt_delivery)
-		return (UNHANDLED);
-
 	handled = HANDLED;
 	offset = APIC_WRITE_OFFSET(qual);
+
+	if (!apic_access_virtualization(vmx, vcpuid)) {
+		/*
+		 * In general there should not be any APIC write VM-exits
+		 * unless APIC-access virtualization is enabled.
+		 *
+		 * However self-IPI virtualization can legitimately trigger
+		 * an APIC-write VM-exit so treat it specially.
+		 */
+		if (x2apic_virtualization(vmx, vcpuid) &&
+		    offset == APIC_OFFSET_SELF_IPI) {
+			apic_regs = (uint32_t *)(vlapic->apic_page);
+			vector = apic_regs[APIC_OFFSET_SELF_IPI / 4];
+			vlapic_self_ipi_handler(vlapic, vector);
+			return (HANDLED);
+		} else
+			return (UNHANDLED);
+	}
+
 	switch (offset) {
 	case APIC_OFFSET_ID:
 		vlapic_id_write_handler(vlapic);
@@ -1550,10 +1637,10 @@ vmx_handle_apic_write(struct vlapic *vla
 }
 
 static bool
-apic_access_fault(uint64_t gpa)
+apic_access_fault(struct vmx *vmx, int vcpuid, uint64_t gpa)
 {
 
-	if (virtual_interrupt_delivery &&
+	if (apic_access_virtualization(vmx, vcpuid) &&
 	    (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + PAGE_SIZE))
 		return (true);
 	else
@@ -1566,7 +1653,7 @@ vmx_handle_apic_access(struct vmx *vmx, 
 	uint64_t qual;
 	int access_type, offset, allowed;
 
-	if (!virtual_interrupt_delivery)
+	if (!apic_access_virtualization(vmx, vcpuid))
 		return (UNHANDLED);
 
 	qual = vmexit->u.vmx.exit_qualification;
@@ -1832,7 +1919,8 @@ vmx_exit_process(struct vmx *vmx, int vc
 		 * this must be an instruction that accesses MMIO space.
 		 */
 		gpa = vmcs_gpa();
-		if (vm_mem_allocated(vmx->vm, gpa) || apic_access_fault(gpa)) {
+		if (vm_mem_allocated(vmx->vm, gpa) ||
+		    apic_access_fault(vmx, vcpu, gpa)) {
 			vmexit->exitcode = VM_EXITCODE_PAGING;
 			vmexit->u.paging.gpa = gpa;
 			vmexit->u.paging.fault_type = ept_fault_type(qual);
@@ -1873,7 +1961,7 @@ vmx_exit_process(struct vmx *vmx, int vc
 		 */
 		vmexit->inst_length = 0;
 		vlapic = vm_lapic(vmx->vm, vcpu);
-		handled = vmx_handle_apic_write(vlapic, qual);
+		handled = vmx_handle_apic_write(vmx, vcpu, vlapic, qual);
 		break;
 	case EXIT_REASON_XSETBV:
 		handled = vmx_emulate_xsetbv(vmx, vcpu, vmexit);
@@ -2119,7 +2207,7 @@ vmx_vmcleanup(void *arg)
 	int i, error;
 	struct vmx *vmx = arg;
 
-	if (virtual_interrupt_delivery)
+	if (apic_access_virtualization(vmx, 0))
 		vm_unmap_mmio(vmx->vm, DEFAULT_APIC_BASE, PAGE_SIZE);
 
 	for (i = 0; i < VM_MAXCPU; i++)
@@ -2571,6 +2659,49 @@ vmx_set_tmr(struct vlapic *vlapic, int v
 }
 
 static void
+vmx_enable_x2apic_mode(struct vlapic *vlapic)
+{
+	struct vmx *vmx;
+	struct vmcs *vmcs;
+	uint32_t proc_ctls2;
+	int vcpuid, error;
+
+	vcpuid = vlapic->vcpuid;
+	vmx = ((struct vlapic_vtx *)vlapic)->vmx;
+	vmcs = &vmx->vmcs[vcpuid];
+
+	proc_ctls2 = vmx->cap[vcpuid].proc_ctls2;
+	KASSERT((proc_ctls2 & PROCBASED2_VIRTUALIZE_APIC_ACCESSES) != 0,
+	    ("%s: invalid proc_ctls2 %#x", __func__, proc_ctls2));
+
+	proc_ctls2 &= ~PROCBASED2_VIRTUALIZE_APIC_ACCESSES;
+	proc_ctls2 |= PROCBASED2_VIRTUALIZE_X2APIC_MODE;
+	vmx->cap[vcpuid].proc_ctls2 = proc_ctls2;
+
+	VMPTRLD(vmcs);
+	vmcs_write(VMCS_SEC_PROC_BASED_CTLS, proc_ctls2);
+	VMCLEAR(vmcs);
+
+	if (vlapic->vcpuid == 0) {
+		/*
+		 * The nested page table mappings are shared by all vcpus
+		 * so unmap the APIC access page just once.
+		 */
+		error = vm_unmap_mmio(vmx->vm, DEFAULT_APIC_BASE, PAGE_SIZE);
+		KASSERT(error == 0, ("%s: vm_unmap_mmio error %d",
+		    __func__, error));
+
+		/*
+		 * The MSR bitmap is shared by all vcpus so modify it only
+		 * once in the context of vcpu 0.
+		 */
+		error = vmx_allow_x2apic_msrs(vmx);
+		KASSERT(error == 0, ("%s: vmx_allow_x2apic_msrs error %d",
+		    __func__, error));
+	}
+}
+
+static void
 vmx_post_intr(struct vlapic *vlapic, int hostcpu)
 {
 
@@ -2675,6 +2806,7 @@ vmx_vlapic_init(void *arg, int vcpuid)
 		vlapic->ops.pending_intr = vmx_pending_intr;
 		vlapic->ops.intr_accepted = vmx_intr_accepted;
 		vlapic->ops.set_tmr = vmx_set_tmr;
+		vlapic->ops.enable_x2apic_mode = vmx_enable_x2apic_mode;
 	}
 
 	if (posted_interrupts)

Modified: stable/10/sys/amd64/vmm/io/vioapic.c
==============================================================================
--- stable/10/sys/amd64/vmm/io/vioapic.c	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/sys/amd64/vmm/io/vioapic.c	Fri Jun 13 19:10:40 2014	(r267447)
@@ -64,8 +64,8 @@ struct vioapic {
 	} rtbl[REDIR_ENTRIES];
 };
 
-#define	VIOAPIC_LOCK(vioapic)		mtx_lock(&((vioapic)->mtx))
-#define	VIOAPIC_UNLOCK(vioapic)		mtx_unlock(&((vioapic)->mtx))
+#define	VIOAPIC_LOCK(vioapic)		mtx_lock_spin(&((vioapic)->mtx))
+#define	VIOAPIC_UNLOCK(vioapic)		mtx_unlock_spin(&((vioapic)->mtx))
 #define	VIOAPIC_LOCKED(vioapic)		mtx_owned(&((vioapic)->mtx))
 
 static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic");
@@ -476,7 +476,7 @@ vioapic_init(struct vm *vm)
 	vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO);
 
 	vioapic->vm = vm;
-	mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_DEF);
+	mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_SPIN);
 
 	/* Initialize all redirection entries to mask all interrupts */
 	for (i = 0; i < REDIR_ENTRIES; i++)

Modified: stable/10/sys/amd64/vmm/io/vlapic.c
==============================================================================
--- stable/10/sys/amd64/vmm/io/vlapic.c	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/sys/amd64/vmm/io/vlapic.c	Fri Jun 13 19:10:40 2014	(r267447)
@@ -289,9 +289,11 @@ vlapic_set_intr_ready(struct vlapic *vla
 	 * the vlapic TMR registers.
 	 */
 	tmrptr = &lapic->tmr0;
-	KASSERT((tmrptr[idx] & mask) == (level ? mask : 0),
-	    ("vlapic TMR[%d] is 0x%08x but interrupt is %s-triggered",
-	    idx / 4, tmrptr[idx], level ? "level" : "edge"));
+	if ((tmrptr[idx] & mask) != (level ? mask : 0)) {
+		VLAPIC_CTR3(vlapic, "vlapic TMR[%d] is 0x%08x but "
+		    "interrupt is %s-triggered", idx / 4, tmrptr[idx],
+		    level ? "level" : "edge");
+	}
 
 	VLAPIC_CTR_IRR(vlapic, "vlapic_set_intr_ready");
 	return (1);
@@ -997,6 +999,20 @@ vlapic_icrlo_write_handler(struct vlapic
 	return (1);
 }
 
+void
+vlapic_self_ipi_handler(struct vlapic *vlapic, uint64_t val)
+{
+	int vec;
+
+	KASSERT(x2apic(vlapic), ("SELF_IPI does not exist in xAPIC mode"));
+
+	vec = val & 0xff;
+	lapic_intr_edge(vlapic->vm, vlapic->vcpuid, vec);
+	vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid, IPIS_SENT,
+	    vlapic->vcpuid, 1);
+	VLAPIC_CTR1(vlapic, "vlapic self-ipi %d", vec);
+}
+
 int
 vlapic_pending_intr(struct vlapic *vlapic, int *vecptr)
 {
@@ -1105,12 +1121,31 @@ vlapic_svr_write_handler(struct vlapic *
 }
 
 int
-vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data, bool *retu)
+vlapic_read(struct vlapic *vlapic, int mmio_access, uint64_t offset,
+    uint64_t *data, bool *retu)
 {
 	struct LAPIC	*lapic = vlapic->apic_page;
 	uint32_t	*reg;
 	int		 i;
 
+	/* Ignore MMIO accesses in x2APIC mode */
+	if (x2apic(vlapic) && mmio_access) {
+		VLAPIC_CTR1(vlapic, "MMIO read from offset %#lx in x2APIC mode",
+		    offset);
+		*data = 0;
+		goto done;
+	}
+
+	if (!x2apic(vlapic) && !mmio_access) {
+		/*
+		 * XXX Generate GP fault for MSR accesses in xAPIC mode
+		 */
+		VLAPIC_CTR1(vlapic, "x2APIC MSR read from offset %#lx in "
+		    "xAPIC mode", offset);
+		*data = 0;
+		goto done;
+	}
+
 	if (offset > sizeof(*lapic)) {
 		*data = 0;
 		goto done;
@@ -1190,6 +1225,12 @@ vlapic_read(struct vlapic *vlapic, uint6
 		case APIC_OFFSET_TIMER_DCR:
 			*data = lapic->dcr_timer;
 			break;
+		case APIC_OFFSET_SELF_IPI:
+			/*
+			 * XXX generate a GP fault if vlapic is in x2apic mode
+			 */
+			*data = 0;
+			break;
 		case APIC_OFFSET_RRR:
 		default:
 			*data = 0;
@@ -1201,7 +1242,8 @@ done:
 }
 
 int
-vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data, bool *retu)
+vlapic_write(struct vlapic *vlapic, int mmio_access, uint64_t offset,
+    uint64_t data, bool *retu)
 {
 	struct LAPIC	*lapic = vlapic->apic_page;
 	uint32_t	*regptr;
@@ -1210,10 +1252,26 @@ vlapic_write(struct vlapic *vlapic, uint
 	KASSERT((offset & 0xf) == 0 && offset < PAGE_SIZE,
 	    ("vlapic_write: invalid offset %#lx", offset));
 
-	VLAPIC_CTR2(vlapic, "vlapic write offset %#x, data %#lx", offset, data);
+	VLAPIC_CTR2(vlapic, "vlapic write offset %#lx, data %#lx",
+	    offset, data);
 
-	if (offset > sizeof(*lapic)) {
-		return 0;
+	if (offset > sizeof(*lapic))
+		return (0);
+
+	/* Ignore MMIO accesses in x2APIC mode */
+	if (x2apic(vlapic) && mmio_access) {
+		VLAPIC_CTR2(vlapic, "MMIO write of %#lx to offset %#lx "
+		    "in x2APIC mode", data, offset);
+		return (0);
+	}
+
+	/*
+	 * XXX Generate GP fault for MSR accesses in xAPIC mode
+	 */
+	if (!x2apic(vlapic) && !mmio_access) {
+		VLAPIC_CTR2(vlapic, "x2APIC MSR write of %#lx to offset %#lx "
+		    "in xAPIC mode", data, offset);
+		return (0);
 	}
 
 	retval = 0;
@@ -1270,6 +1328,12 @@ vlapic_write(struct vlapic *vlapic, uint
 		case APIC_OFFSET_ESR:
 			vlapic_esr_write_handler(vlapic);
 			break;
+
+		case APIC_OFFSET_SELF_IPI:
+			if (x2apic(vlapic))
+				vlapic_self_ipi_handler(vlapic, data);
+			break;
+
 		case APIC_OFFSET_VER:
 		case APIC_OFFSET_APR:
 		case APIC_OFFSET_PPR:
@@ -1354,50 +1418,52 @@ vlapic_get_apicbase(struct vlapic *vlapi
 	return (vlapic->msr_apicbase);
 }
 
-void
+int
 vlapic_set_apicbase(struct vlapic *vlapic, uint64_t new)
 {
-	struct LAPIC *lapic;
-	enum x2apic_state state;
-	uint64_t old;
-	int err;
-
-	err = vm_get_x2apic_state(vlapic->vm, vlapic->vcpuid, &state);
-	if (err)
-		panic("vlapic_set_apicbase: err %d fetching x2apic state", err);
 
-	if (state == X2APIC_DISABLED)
-		new &= ~APICBASE_X2APIC;
-
-	old = vlapic->msr_apicbase;
-	vlapic->msr_apicbase = new;
-
-	/*
-	 * If the vlapic is switching between xAPIC and x2APIC modes then
-	 * reset the mode-dependent registers.
-	 */
-	if ((old ^ new) & APICBASE_X2APIC) {
-		lapic = vlapic->apic_page;
-		lapic->id = vlapic_get_id(vlapic);
-		if (x2apic(vlapic)) {
-			lapic->ldr = x2apic_ldr(vlapic);
-			lapic->dfr = 0;
-		} else {
-			lapic->ldr = 0;
-			lapic->dfr = 0xffffffff;
-		}
+	if (vlapic->msr_apicbase != new) {
+		VLAPIC_CTR2(vlapic, "Changing APIC_BASE MSR from %#lx to %#lx "
+		    "not supported", vlapic->msr_apicbase, new);
+		return (-1);
 	}
+
+	return (0);
 }
 
 void
 vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state state)
 {
 	struct vlapic *vlapic;
+	struct LAPIC *lapic;
 
 	vlapic = vm_lapic(vm, vcpuid);
 
 	if (state == X2APIC_DISABLED)
 		vlapic->msr_apicbase &= ~APICBASE_X2APIC;
+	else
+		vlapic->msr_apicbase |= APICBASE_X2APIC;
+
+	/*
+	 * Reset the local APIC registers whose values are mode-dependent.
+	 *
+	 * XXX this works because the APIC mode can be changed only at vcpu
+	 * initialization time.
+	 */
+	lapic = vlapic->apic_page;
+	lapic->id = vlapic_get_id(vlapic);
+	if (x2apic(vlapic)) {
+		lapic->ldr = x2apic_ldr(vlapic);
+		lapic->dfr = 0;
+	} else {
+		lapic->ldr = 0;
+		lapic->dfr = 0xffffffff;
+	}
+
+	if (state == X2APIC_ENABLED) {
+		if (vlapic->ops.enable_x2apic_mode)
+			(*vlapic->ops.enable_x2apic_mode)(vlapic);
+	}
 }
 
 void

Modified: stable/10/sys/amd64/vmm/io/vlapic.h
==============================================================================
--- stable/10/sys/amd64/vmm/io/vlapic.h	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/sys/amd64/vmm/io/vlapic.h	Fri Jun 13 19:10:40 2014	(r267447)
@@ -32,10 +32,10 @@
 struct vm;
 enum x2apic_state;
 
-int vlapic_write(struct vlapic *vlapic, uint64_t offset, uint64_t data,
-    bool *retu);
-int vlapic_read(struct vlapic *vlapic, uint64_t offset, uint64_t *data,
-    bool *retu);
+int vlapic_write(struct vlapic *vlapic, int mmio_access, uint64_t offset,
+    uint64_t data, bool *retu);
+int vlapic_read(struct vlapic *vlapic, int mmio_access, uint64_t offset,
+    uint64_t *data, bool *retu);
 
 /*
  * Returns 0 if there is no eligible vector that can be delivered to the
@@ -74,7 +74,7 @@ void vlapic_fire_cmci(struct vlapic *vla
 int vlapic_trigger_lvt(struct vlapic *vlapic, int vector);
 
 uint64_t vlapic_get_apicbase(struct vlapic *vlapic);
-void vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val);
+int vlapic_set_apicbase(struct vlapic *vlapic, uint64_t val);
 void vlapic_set_x2apic_state(struct vm *vm, int vcpuid, enum x2apic_state s);
 bool vlapic_enabled(struct vlapic *vlapic);
 
@@ -102,4 +102,5 @@ int vlapic_icrlo_write_handler(struct vl
 void vlapic_icrtmr_write_handler(struct vlapic *vlapic);
 void vlapic_dcr_write_handler(struct vlapic *vlapic);
 void vlapic_lvt_write_handler(struct vlapic *vlapic, uint32_t offset);
+void vlapic_self_ipi_handler(struct vlapic *vlapic, uint64_t val);
 #endif	/* _VLAPIC_H_ */

Modified: stable/10/sys/amd64/vmm/io/vlapic_priv.h
==============================================================================
--- stable/10/sys/amd64/vmm/io/vlapic_priv.h	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/sys/amd64/vmm/io/vlapic_priv.h	Fri Jun 13 19:10:40 2014	(r267447)
@@ -81,6 +81,7 @@
 #define APIC_OFFSET_TIMER_ICR	0x380	/* Timer's Initial Count	*/
 #define APIC_OFFSET_TIMER_CCR	0x390	/* Timer's Current Count	*/
 #define APIC_OFFSET_TIMER_DCR	0x3E0	/* Timer's Divide Configuration	*/
+#define	APIC_OFFSET_SELF_IPI	0x3F0	/* Self IPI register */
 
 #define	VLAPIC_CTR0(vlapic, format)					\
 	VCPU_CTR0((vlapic)->vm, (vlapic)->vcpuid, format)
@@ -91,6 +92,9 @@
 #define	VLAPIC_CTR2(vlapic, format, p1, p2)				\
 	VCPU_CTR2((vlapic)->vm, (vlapic)->vcpuid, format, p1, p2)
 
+#define	VLAPIC_CTR3(vlapic, format, p1, p2, p3)				\
+	VCPU_CTR3((vlapic)->vm, (vlapic)->vcpuid, format, p1, p2, p3)
+
 #define	VLAPIC_CTR_IRR(vlapic, msg)					\
 do {									\
 	uint32_t *irrptr = &(vlapic)->apic_page->irr0;			\
@@ -140,6 +144,7 @@ struct vlapic_ops {
 	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);
+	void (*enable_x2apic_mode)(struct vlapic *vlapic);
 };
 
 struct vlapic {

Modified: stable/10/sys/amd64/vmm/vmm.c
==============================================================================
--- stable/10/sys/amd64/vmm/vmm.c	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/sys/amd64/vmm/vmm.c	Fri Jun 13 19:10:40 2014	(r267447)
@@ -206,7 +206,7 @@ vcpu_init(struct vm *vm, uint32_t vcpu_i
 	vcpu->hostcpu = NOCPU;
 	vcpu->vcpuid = vcpu_id;
 	vcpu->vlapic = VLAPIC_INIT(vm->cookie, vcpu_id);
-	vm_set_x2apic_state(vm, vcpu_id, X2APIC_ENABLED);
+	vm_set_x2apic_state(vm, vcpu_id, X2APIC_DISABLED);
 	vcpu->guest_xcr0 = XFEATURE_ENABLED_X87;
 	vcpu->guestfpu = fpu_save_area_alloc();
 	fpu_save_area_reset(vcpu->guestfpu);

Modified: stable/10/sys/amd64/vmm/vmm_lapic.c
==============================================================================
--- stable/10/sys/amd64/vmm/vmm_lapic.c	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/sys/amd64/vmm/vmm_lapic.c	Fri Jun 13 19:10:40 2014	(r267447)
@@ -172,7 +172,7 @@ lapic_rdmsr(struct vm *vm, int cpu, u_in
 		error = 0;
 	} else {
 		offset = x2apic_msr_to_regoff(msr);
-		error = vlapic_read(vlapic, offset, rval, retu);
+		error = vlapic_read(vlapic, 0, offset, rval, retu);
 	}
 
 	return (error);
@@ -188,11 +188,10 @@ lapic_wrmsr(struct vm *vm, int cpu, u_in
 	vlapic = vm_lapic(vm, cpu);
 
 	if (msr == MSR_APICBASE) {
-		vlapic_set_apicbase(vlapic, val);
-		error = 0;
+		error = vlapic_set_apicbase(vlapic, val);
 	} else {
 		offset = x2apic_msr_to_regoff(msr);
-		error = vlapic_write(vlapic, offset, val, retu);
+		error = vlapic_write(vlapic, 0, offset, val, retu);
 	}
 
 	return (error);
@@ -216,7 +215,7 @@ lapic_mmio_write(void *vm, int cpu, uint
 		return (EINVAL);
 
 	vlapic = vm_lapic(vm, cpu);
-	error = vlapic_write(vlapic, off, wval, arg);
+	error = vlapic_write(vlapic, 1, off, wval, arg);
 	return (error);
 }
 
@@ -238,6 +237,6 @@ lapic_mmio_read(void *vm, int cpu, uint6
 		return (EINVAL);
 
 	vlapic = vm_lapic(vm, cpu);
-	error = vlapic_read(vlapic, off, rval, arg);
+	error = vlapic_read(vlapic, 1, off, rval, arg);
 	return (error);
 }

Modified: stable/10/sys/amd64/vmm/x86.c
==============================================================================
--- stable/10/sys/amd64/vmm/x86.c	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/sys/amd64/vmm/x86.c	Fri Jun 13 19:10:40 2014	(r267447)
@@ -149,6 +149,8 @@ x86_emulate_cpuid(struct vm *vm, int vcp
 
 			if (x2apic_state != X2APIC_DISABLED)
 				regs[2] |= CPUID2_X2APIC;
+			else
+				regs[2] &= ~CPUID2_X2APIC;
 
 			/*
 			 * Only advertise CPUID2_XSAVE in the guest if

Modified: stable/10/usr.sbin/bhyve/bhyve.8
==============================================================================
--- stable/10/usr.sbin/bhyve/bhyve.8	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/usr.sbin/bhyve/bhyve.8	Fri Jun 13 19:10:40 2014	(r267447)
@@ -32,7 +32,7 @@
 .Nd "run a guest operating system inside a virtual machine"
 .Sh SYNOPSIS
 .Nm
-.Op Fl aehwAHPW
+.Op Fl aehwxAHPW
 .Op Fl c Ar numcpus
 .Op Fl g Ar gdbport
 .Op Fl p Ar pinnedcpu
@@ -58,7 +58,9 @@ exit is detected.
 .Sh OPTIONS
 .Bl -tag -width 10n
 .It Fl a
-Disallow use of the local APIC in X2APIC mode.
+The guest's local APIC is configured in xAPIC mode.
+The xAPIC mode is the default setting so this option is redundant. It will be
+deprecated in a future version.
 .It Fl A
 Generate ACPI tables.
 Required for
@@ -223,6 +225,8 @@ to exit when a guest issues an access to
 This is intended for debug purposes.
 .It Fl w
 Ignore accesses to unimplemented Model Specific Registers (MSRs). This is intended for debug purposes.
+.It Fl x
+The guest's local APIC is configured in x2APIC mode.
 .It Fl h
 Print help message and exit.
 .It Ar vmname

Modified: stable/10/usr.sbin/bhyve/bhyverun.c
==============================================================================
--- stable/10/usr.sbin/bhyve/bhyverun.c	Fri Jun 13 18:20:44 2014	(r267446)
+++ stable/10/usr.sbin/bhyve/bhyverun.c	Fri Jun 13 19:10:40 2014	(r267447)
@@ -84,8 +84,9 @@ char *vmname;
 int guest_ncpus;
 
 static int pincpu = -1;
-static int guest_vmexit_on_hlt, guest_vmexit_on_pause, disable_x2apic;
+static int guest_vmexit_on_hlt, guest_vmexit_on_pause;
 static int virtio_msix = 1;
+static int x2apic_mode = 0;	/* default is xAPIC */
 
 static int strictio;
 static int strictmsr = 1;
@@ -126,7 +127,7 @@ usage(int code)
         fprintf(stderr,
                 "Usage: %s [-aehwAHIPW] [-g <gdb port>] [-s <pci>]\n"
 		"       %*s [-c vcpus] [-p pincpu] [-m mem] [-l <lpc>] <vm>\n"
-		"       -a: local apic is in XAPIC mode (default is X2APIC)\n"
+		"       -a: local apic is in xAPIC mode (deprecated)\n"
 		"       -A: create an ACPI table\n"
 		"       -g: gdb port\n"
 		"       -c: # cpus (default 1)\n"
@@ -139,7 +140,8 @@ usage(int code)
 		"       -s: <slot,driver,configinfo> PCI slot config\n"
 		"       -l: LPC device configuration\n"
 		"       -m: memory size in MB\n"
-		"       -w: ignore unimplemented MSRs\n",
+		"       -w: ignore unimplemented MSRs\n"
+		"       -x: local apic is in x2APIC mode\n",
 		progname, (int)strlen(progname), "");
 
 	exit(code);
@@ -153,13 +155,6 @@ paddr_guest2host(struct vmctx *ctx, uint
 }
 
 int
-fbsdrun_disable_x2apic(void)
-{
-
-	return (disable_x2apic);
-}
-
-int
 fbsdrun_vmexit_on_pause(void)
 {
 
@@ -576,10 +571,10 @@ fbsdrun_set_capabilities(struct vmctx *c
 			handler[VM_EXITCODE_PAUSE] = vmexit_pause;
         }
 
-	if (fbsdrun_disable_x2apic())
-		err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED);
-	else
+	if (x2apic_mode)
 		err = vm_set_x2apic_state(ctx, cpu, X2APIC_ENABLED);
+	else
+		err = vm_set_x2apic_state(ctx, cpu, X2APIC_DISABLED);
 
 	if (err) {
 		fprintf(stderr, "Unable to set x2apic state (%d)\n", err);
@@ -604,10 +599,10 @@ main(int argc, char *argv[])
 	guest_ncpus = 1;
 	memsize = 256 * MB;
 
-	while ((c = getopt(argc, argv, "abehwAHIPWp:g:c:s:m:l:")) != -1) {
+	while ((c = getopt(argc, argv, "abehwxAHIPWp:g:c:s:m:l:")) != -1) {
 		switch (c) {
 		case 'a':
-			disable_x2apic = 1;
+			x2apic_mode = 0;
 			break;
 		case 'A':
 			acpi = 1;
@@ -664,6 +659,9 @@ main(int argc, char *argv[])
 		case 'W':
 			virtio_msix = 0;
 			break;
+		case 'x':
+			x2apic_mode = 1;
+			break;
 		case 'h':
 			usage(0);			
 		default:


More information about the svn-src-all mailing list