svn commit: r259779 - in head: lib/libvmmapi sys/amd64/include sys/amd64/vmm sys/amd64/vmm/io usr.sbin/bhyve usr.sbin/bhyvectl

John Baldwin jhb at FreeBSD.org
Mon Dec 23 19:29:10 UTC 2013


Author: jhb
Date: Mon Dec 23 19:29:07 2013
New Revision: 259779
URL: http://svnweb.freebsd.org/changeset/base/259779

Log:
  Extend the support for local interrupts on the local APIC:
  - Add a generic routine to trigger an LVT interrupt that supports both
    fixed and NMI delivery modes.
  - Add an ioctl and bhyvectl command to trigger local interrupts inside a
    guest.  In particular, a global NMI similar to that raised by SERR# or
    PERR# can be simulated by asserting LINT1 on all vCPUs.
  - Extend the LVT table in the vCPU local APIC to support CMCI.
  - Flesh out the local APIC error reporting a bit to cache errors and
    report them via ESR when ESR is written to.  Add support for asserting
    the error LVT when an error occurs.  Raise illegal vector errors when
    attempting to signal an invalid vector for an interrupt or when sending
    an IPI.
  - Ignore writes to reserved bits in LVT entries.
  - Export table entries the MADT and MP Table advertising the stock x86
    config of LINT0 set to ExtInt and LINT1 wired to NMI.
  
  Reviewed by:	neel (earlier version)

Modified:
  head/lib/libvmmapi/vmmapi.c
  head/lib/libvmmapi/vmmapi.h
  head/sys/amd64/include/vmm_dev.h
  head/sys/amd64/vmm/io/vlapic.c
  head/sys/amd64/vmm/io/vlapic.h
  head/sys/amd64/vmm/vmm_dev.c
  head/sys/amd64/vmm/vmm_lapic.c
  head/sys/amd64/vmm/vmm_lapic.h
  head/usr.sbin/bhyve/acpi.c
  head/usr.sbin/bhyve/mptbl.c
  head/usr.sbin/bhyvectl/bhyvectl.c

Modified: head/lib/libvmmapi/vmmapi.c
==============================================================================
--- head/lib/libvmmapi/vmmapi.c	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/lib/libvmmapi/vmmapi.c	Mon Dec 23 19:29:07 2013	(r259779)
@@ -397,6 +397,18 @@ vm_lapic_irq(struct vmctx *ctx, int vcpu
 }
 
 int
+vm_lapic_local_irq(struct vmctx *ctx, int vcpu, int vector)
+{
+	struct vm_lapic_irq vmirq;
+
+	bzero(&vmirq, sizeof(vmirq));
+	vmirq.cpuid = vcpu;
+	vmirq.vector = vector;
+
+	return (ioctl(ctx->fd, VM_LAPIC_LOCAL_IRQ, &vmirq));
+}
+
+int
 vm_lapic_msi(struct vmctx *ctx, uint64_t addr, uint64_t msg)
 {
 	struct vm_lapic_msi vmmsi;

Modified: head/lib/libvmmapi/vmmapi.h
==============================================================================
--- head/lib/libvmmapi/vmmapi.h	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/lib/libvmmapi/vmmapi.h	Mon Dec 23 19:29:07 2013	(r259779)
@@ -67,6 +67,7 @@ int	vm_inject_event(struct vmctx *ctx, i
 int	vm_inject_event2(struct vmctx *ctx, int vcpu, enum vm_event_type type,
 			 int vector, int error_code);
 int	vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector);
+int	vm_lapic_local_irq(struct vmctx *ctx, int vcpu, int vector);
 int	vm_lapic_msi(struct vmctx *ctx, uint64_t addr, uint64_t msg);
 int	vm_ioapic_assert_irq(struct vmctx *ctx, int irq);
 int	vm_ioapic_deassert_irq(struct vmctx *ctx, int irq);

Modified: head/sys/amd64/include/vmm_dev.h
==============================================================================
--- head/sys/amd64/include/vmm_dev.h	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/sys/amd64/include/vmm_dev.h	Mon Dec 23 19:29:07 2013	(r259779)
@@ -181,6 +181,7 @@ enum {
 	IOCNUM_IOAPIC_DEASSERT_IRQ = 34,
 	IOCNUM_IOAPIC_PULSE_IRQ = 35,
 	IOCNUM_LAPIC_MSI = 36,
+	IOCNUM_LAPIC_LOCAL_IRQ = 37, 
 
 	/* PCI pass-thru */
 	IOCNUM_BIND_PPTDEV = 40,
@@ -217,6 +218,8 @@ enum {
 	_IOW('v', IOCNUM_INJECT_EVENT, struct vm_event)
 #define	VM_LAPIC_IRQ 		\
 	_IOW('v', IOCNUM_LAPIC_IRQ, struct vm_lapic_irq)
+#define	VM_LAPIC_LOCAL_IRQ 	\
+	_IOW('v', IOCNUM_LAPIC_LOCAL_IRQ, struct vm_lapic_irq)
 #define	VM_LAPIC_MSI		\
 	_IOW('v', IOCNUM_LAPIC_MSI, struct vm_lapic_msi)
 #define	VM_IOAPIC_ASSERT_IRQ	\

Modified: head/sys/amd64/vmm/io/vlapic.c
==============================================================================
--- head/sys/amd64/vmm/io/vlapic.c	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/sys/amd64/vmm/io/vlapic.c	Mon Dec 23 19:29:07 2013	(r259779)
@@ -91,7 +91,7 @@ static MALLOC_DEFINE(M_VLAPIC, "vlapic",
 #define	PRIO(x)			((x) >> 4)
 
 #define VLAPIC_VERSION		(16)
-#define VLAPIC_MAXLVT_ENTRIES	(5)
+#define VLAPIC_MAXLVT_ENTRIES	(APIC_LVT_CMCI)
 
 #define	x2apic(vlapic)	(((vlapic)->msr_apicbase & APICBASE_X2APIC) ? 1 : 0)
 
@@ -107,7 +107,8 @@ struct vlapic {
 
 	struct LAPIC		apic;
 
-	int			 esr_update;
+	uint32_t		esr_pending;
+	int			esr_firing;
 
 	struct callout	callout;	/* vlapic timer */
 	struct bintime	timer_fire_bt;	/* callout expiry time */
@@ -330,7 +331,8 @@ static void
 vlapic_update_errors(struct vlapic *vlapic)
 {
 	struct LAPIC    *lapic = &vlapic->apic;
-	lapic->esr = 0; // XXX 
+	lapic->esr = vlapic->esr_pending;
+	vlapic->esr_pending = 0;
 }
 
 static void
@@ -345,7 +347,8 @@ vlapic_reset(struct vlapic *vlapic)
 	lapic->version |= (VLAPIC_MAXLVT_ENTRIES << MAXLVTSHIFT);
 	lapic->dfr = 0xffffffff;
 	lapic->svr = APIC_SVR_VECTOR;
-	vlapic_mask_lvts(&lapic->lvt_timer, VLAPIC_MAXLVT_ENTRIES+1);
+	vlapic_mask_lvts(&lapic->lvt_timer, 6);
+	vlapic_mask_lvts(&lapic->lvt_cmci, 1);
 	vlapic_set_dcr(vlapic, 0);
 
 	if (vlapic->vcpuid == 0)
@@ -370,6 +373,11 @@ vlapic_set_intr_ready(struct vlapic *vla
 		return;
 	}
 
+	if (vector < 16) {
+		vlapic_set_error(vlapic, APIC_ESR_RECEIVE_ILLEGAL_VECTOR);
+		return;
+	}
+		
 	idx = (vector / 32) * 4;
 	mask = 1 << (vector % 32);
 
@@ -396,11 +404,15 @@ vlapic_get_lvtptr(struct vlapic *vlapic,
 	struct LAPIC	*lapic = &vlapic->apic;
 	int 		 i;
 
-	if (offset < APIC_OFFSET_TIMER_LVT || offset > APIC_OFFSET_ERROR_LVT) {
+	switch (offset) {
+	case APIC_OFFSET_CMCI_LVT:
+		return (&lapic->lvt_cmci);
+	case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT:
+		i = (offset - APIC_OFFSET_TIMER_LVT) >> 2;
+		return ((&lapic->lvt_timer) + i);;
+	default:
 		panic("vlapic_get_lvt: invalid LVT\n");
 	}
-	i = (offset - APIC_OFFSET_TIMER_LVT) >> 2;
-	return ((&lapic->lvt_timer) + i);;
 }
 
 static __inline uint32_t
@@ -413,7 +425,7 @@ vlapic_get_lvt(struct vlapic *vlapic, ui
 static void
 vlapic_set_lvt(struct vlapic *vlapic, uint32_t offset, uint32_t val)
 {
-	uint32_t *lvtptr;
+	uint32_t *lvtptr, mask;
 	struct LAPIC *lapic;
 	
 	lapic = &vlapic->apic;
@@ -424,12 +436,57 @@ vlapic_set_lvt(struct vlapic *vlapic, ui
 
 	if (!(lapic->svr & APIC_SVR_ENABLE))
 		val |= APIC_LVT_M;
-	*lvtptr = val;
+	mask = APIC_LVT_M | APIC_LVT_DS | APIC_LVT_VECTOR;
+	switch (offset) {
+	case APIC_OFFSET_TIMER_LVT:
+		mask |= APIC_LVTT_TM;
+		break;
+	case APIC_OFFSET_ERROR_LVT:
+		break;
+	case APIC_OFFSET_LINT0_LVT:
+	case APIC_OFFSET_LINT1_LVT:
+		mask |= APIC_LVT_TM | APIC_LVT_RIRR | APIC_LVT_IIPP;
+		/* FALLTHROUGH */
+	default:
+		mask |= APIC_LVT_DM;
+		break;
+	}
+	*lvtptr = val & mask;
 
 	if (offset == APIC_OFFSET_TIMER_LVT)
 		VLAPIC_TIMER_UNLOCK(vlapic);
 }
 
+static int
+vlapic_fire_lvt(struct vlapic *vlapic, uint32_t lvt)
+{
+	uint32_t vec, mode;
+
+	if (lvt & APIC_LVT_M)
+		return (0);
+
+	vec = lvt & APIC_LVT_VECTOR;
+	mode = lvt & APIC_LVT_DM;
+
+	switch (mode) {
+	case APIC_LVT_DM_FIXED:
+		if (vec < 16) {
+			vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);
+			return (0);
+		}
+		vlapic_set_intr_ready(vlapic, vec, false);
+		vcpu_notify_event(vlapic->vm, vlapic->vcpuid);
+		break;
+	case APIC_LVT_DM_NMI:
+		vm_inject_nmi(vlapic->vm, vlapic->vcpuid);
+		break;
+	default:
+		// Other modes ignored
+		return (0);
+	}
+	return (1);
+}
+
 #if 1
 static void
 dump_isrvec_stk(struct vlapic *vlapic)
@@ -568,26 +625,98 @@ vlapic_periodic_timer(struct vlapic *vla
 	return (vlapic_get_lvt_field(lvt, APIC_LVTT_TM_PERIODIC));
 }
 
+static VMM_STAT(VLAPIC_INTR_ERROR, "error interrupts generated by vlapic");
+
+void
+vlapic_set_error(struct vlapic *vlapic, uint32_t mask)
+{
+	uint32_t lvt;
+
+	vlapic->esr_pending |= mask;
+	if (vlapic->esr_firing)
+		return;
+	vlapic->esr_firing = 1;
+
+	// The error LVT always uses the fixed delivery mode.
+	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_ERROR_LVT);
+	if (vlapic_fire_lvt(vlapic, lvt | APIC_LVT_DM_FIXED)) {
+		vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_ERROR, 1);
+	}
+	vlapic->esr_firing = 0;
+}
+
 static VMM_STAT(VLAPIC_INTR_TIMER, "timer interrupts generated by vlapic");
 
 static void
 vlapic_fire_timer(struct vlapic *vlapic)
 {
-	int vector;
 	uint32_t lvt;
 
 	KASSERT(VLAPIC_TIMER_LOCKED(vlapic), ("vlapic_fire_timer not locked"));
 	
+	// The timer LVT always uses the fixed delivery mode.
 	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);
-
-	if (!vlapic_get_lvt_field(lvt, APIC_LVTT_M)) {
+	if (vlapic_fire_lvt(vlapic, lvt | APIC_LVT_DM_FIXED)) {
 		vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_TIMER, 1);
-		vector = vlapic_get_lvt_field(lvt, APIC_LVTT_VECTOR);
-		vlapic_set_intr_ready(vlapic, vector, false);
-		vcpu_notify_event(vlapic->vm, vlapic->vcpuid);
 	}
 }
 
+static VMM_STAT(VLAPIC_INTR_CMC,
+    "corrected machine check interrupts generated by vlapic");
+
+void
+vlapic_fire_cmci(struct vlapic *vlapic)
+{
+	uint32_t lvt;
+
+	lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_CMCI_LVT);
+	if (vlapic_fire_lvt(vlapic, lvt)) {
+		vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_INTR_CMC, 1);
+	}
+}
+
+static VMM_STAT_ARRAY(LVTS_TRIGGERRED, VLAPIC_MAXLVT_ENTRIES,
+    "lvts triggered");
+
+int
+vlapic_trigger_lvt(struct vlapic *vlapic, int vector)
+{
+	uint32_t lvt;
+
+	switch (vector) {
+	case APIC_LVT_LINT0:
+		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_LINT0_LVT);
+		break;
+	case APIC_LVT_LINT1:
+		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_LINT1_LVT);
+		break;
+	case APIC_LVT_TIMER:
+		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_TIMER_LVT);
+		lvt |= APIC_LVT_DM_FIXED;
+		break;
+	case APIC_LVT_ERROR:
+		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_ERROR_LVT);
+		lvt |= APIC_LVT_DM_FIXED;
+		break;
+	case APIC_LVT_PMC:
+		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_PERF_LVT);
+		break;
+	case APIC_LVT_THERMAL:
+		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_THERM_LVT);
+		break;
+	case APIC_LVT_CMCI:
+		lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_CMCI_LVT);
+		break;
+	default:
+		return (EINVAL);
+	}
+	if (vlapic_fire_lvt(vlapic, lvt)) {
+		vmm_stat_array_incr(vlapic->vm, vlapic->vcpuid,
+		    LVTS_TRIGGERRED, vector, 1);
+	}
+	return (0);
+}
+
 static void
 vlapic_callout_handler(void *arg)
 {
@@ -800,6 +929,11 @@ lapic_process_icr(struct vlapic *vlapic,
 	vec = icrval & APIC_VECTOR_MASK;
 	mode = icrval & APIC_DELMODE_MASK;
 
+	if (mode == APIC_DELMODE_FIXED && vec < 16) {
+		vlapic_set_error(vlapic, APIC_ESR_SEND_ILLEGAL_VECTOR);
+		return (0);
+	}
+	
 	if (mode == APIC_DELMODE_FIXED || mode == APIC_DELMODE_NMI) {
 		switch (icrval & APIC_DEST_MASK) {
 		case APIC_DEST_DESTFLD:
@@ -1044,6 +1178,7 @@ vlapic_read(struct vlapic *vlapic, uint6
 		case APIC_OFFSET_ICR_HI: 
 			*data = lapic->icr_hi;
 			break;
+		case APIC_OFFSET_CMCI_LVT:
 		case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT:
 			*data = vlapic_get_lvt(vlapic, offset);	
 			break;
@@ -1113,6 +1248,7 @@ vlapic_write(struct vlapic *vlapic, uint
 				lapic->icr_hi = data;
 			}
 			break;
+		case APIC_OFFSET_CMCI_LVT:
 		case APIC_OFFSET_TIMER_LVT ... APIC_OFFSET_ERROR_LVT:
 			vlapic_set_lvt(vlapic, offset, data);
 			break;

Modified: head/sys/amd64/vmm/io/vlapic.h
==============================================================================
--- head/sys/amd64/vmm/io/vlapic.h	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/sys/amd64/vmm/io/vlapic.h	Mon Dec 23 19:29:07 2013	(r259779)
@@ -69,6 +69,7 @@ struct vm;
 #define APIC_OFFSET_IRR6 	0x260   // IRR  192-223                    	R
 #define APIC_OFFSET_IRR7 	0x270   // IRR  224-255                    	R
 #define APIC_OFFSET_ESR		0x280   // Error Status Register           	R
+#define APIC_OFFSET_CMCI_LVT 	0x2F0   // Local Vector Table (CMCI)      	R/W
 #define APIC_OFFSET_ICR_LOW 	0x300   // Interrupt Command Reg. (0-31)   	R/W
 #define APIC_OFFSET_ICR_HI 	0x310   // Interrupt Command Reg. (32-63)  	R/W
 #define APIC_OFFSET_TIMER_LVT 	0x320   // Local Vector Table (Timer)      	R/W
@@ -97,6 +98,9 @@ int vlapic_read(struct vlapic *vlapic, u
 int vlapic_pending_intr(struct vlapic *vlapic);
 void vlapic_intr_accepted(struct vlapic *vlapic, int vector);
 void vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level);
+void vlapic_set_error(struct vlapic *vlapic, uint32_t mask);
+void vlapic_fire_cmci(struct vlapic *vlapic);
+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);

Modified: head/sys/amd64/vmm/vmm_dev.c
==============================================================================
--- head/sys/amd64/vmm/vmm_dev.c	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/sys/amd64/vmm/vmm_dev.c	Mon Dec 23 19:29:07 2013	(r259779)
@@ -297,6 +297,11 @@ vmmdev_ioctl(struct cdev *cdev, u_long c
 		vmirq = (struct vm_lapic_irq *)data;
 		error = lapic_intr_edge(sc->vm, vmirq->cpuid, vmirq->vector);
 		break;
+	case VM_LAPIC_LOCAL_IRQ:
+		vmirq = (struct vm_lapic_irq *)data;
+		error = lapic_set_local_intr(sc->vm, vmirq->cpuid,
+		    vmirq->vector);
+		break;
 	case VM_LAPIC_MSI:
 		vmmsi = (struct vm_lapic_msi *)data;
 		error = lapic_intr_msi(sc->vm, vmmsi->addr, vmmsi->msg);

Modified: head/sys/amd64/vmm/vmm_lapic.c
==============================================================================
--- head/sys/amd64/vmm/vmm_lapic.c	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/sys/amd64/vmm/vmm_lapic.c	Mon Dec 23 19:29:07 2013	(r259779)
@@ -90,6 +90,33 @@ lapic_set_intr(struct vm *vm, int cpu, i
 }
 
 int
+lapic_set_local_intr(struct vm *vm, int cpu, int vector)
+{
+	struct vlapic *vlapic;
+	cpuset_t dmask;
+	int error;
+
+	if (cpu < -1 || cpu >= VM_MAXCPU)
+		return (EINVAL);
+
+	if (cpu == -1)
+		dmask = vm_active_cpus(vm);
+	else
+		CPU_SETOF(cpu, &dmask);
+	error = 0;
+	while ((cpu = CPU_FFS(&dmask)) != 0) {
+		cpu--;
+		CPU_CLR(cpu, &dmask);
+		vlapic = vm_lapic(vm, cpu);
+		error = vlapic_trigger_lvt(vlapic, vector);
+		if (error)
+			break;
+	}
+
+	return (error);
+}
+
+int
 lapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg)
 {
 	int delmode, vec;

Modified: head/sys/amd64/vmm/vmm_lapic.h
==============================================================================
--- head/sys/amd64/vmm/vmm_lapic.h	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/sys/amd64/vmm/vmm_lapic.h	Mon Dec 23 19:29:07 2013	(r259779)
@@ -84,5 +84,12 @@ lapic_intr_edge(struct vm *vm, int cpu, 
 	return (lapic_set_intr(vm, cpu, vector, LAPIC_TRIG_EDGE));
 }
 
+/*
+ * Triggers the LAPIC local interrupt (LVT) 'vector' on 'cpu'.  'cpu' can
+ * be set to -1 to trigger the interrupt on all CPUs.
+ */
+int	lapic_set_local_intr(struct vm *vm, int cpu, int vector);
+
 int	lapic_intr_msi(struct vm *vm, uint64_t addr, uint64_t msg);
+
 #endif

Modified: head/usr.sbin/bhyve/acpi.c
==============================================================================
--- head/usr.sbin/bhyve/acpi.c	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/usr.sbin/bhyve/acpi.c	Mon Dec 23 19:29:07 2013	(r259779)
@@ -290,6 +290,16 @@ basl_fwrite_madt(FILE *fp)
 	EFPRINTF(fp, "\t\t\tTrigger Mode : 0\n");
 	EFPRINTF(fp, "\n");
 
+	/* Local APIC NMI is connected to LINT 1 on all CPUs */
+	EFPRINTF(fp, "[0001]\t\tSubtable Type : 04\n");
+	EFPRINTF(fp, "[0001]\t\tLength : 06\n");
+	EFPRINTF(fp, "[0001]\t\tProcessorId : FF\n");
+	EFPRINTF(fp, "[0002]\t\tFlags (decoded below) : 0005\n");
+	EFPRINTF(fp, "\t\t\tPolarity : 1\n");
+	EFPRINTF(fp, "\t\t\tTrigger Mode : 1\n");
+	EFPRINTF(fp, "[0001]\t\tInterrupt : 01\n");
+	EFPRINTF(fp, "\n");
+
 	EFFLUSH(fp);
 
 	return (0);

Modified: head/usr.sbin/bhyve/mptbl.c
==============================================================================
--- head/usr.sbin/bhyve/mptbl.c	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/usr.sbin/bhyve/mptbl.c	Mon Dec 23 19:29:07 2013	(r259779)
@@ -71,6 +71,9 @@ __FBSDID("$FreeBSD$");
 
 #define MPEP_FEATURES           (0xBFEBFBFF) /* XXX Intel i7 */
 
+/* Number of local intr entries */
+#define	MPEII_NUM_LOCAL_IRQ	2
+
 /* Number of i/o intr entries */
 #define	MPEII_MAX_IRQ		24
 
@@ -140,6 +143,30 @@ mpt_build_proc_entries(proc_entry_ptr mp
 }
 
 static void
+mpt_build_localint_entries(int_entry_ptr mpie)
+{
+
+	/* Hardcode LINT0 as ExtINT on all CPUs. */
+	memset(mpie, 0, sizeof(*mpie));
+	mpie->type = MPCT_ENTRY_LOCAL_INT;
+	mpie->int_type = INTENTRY_TYPE_EXTINT;
+	mpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |
+	    INTENTRY_FLAGS_TRIGGER_CONFORM;
+	mpie->dst_apic_id = 0xff;
+	mpie->dst_apic_int = 0;
+	mpie++;
+
+	/* Hardcode LINT1 as NMI on all CPUs. */
+	memset(mpie, 0, sizeof(*mpie));
+	mpie->type = MPCT_ENTRY_LOCAL_INT;
+	mpie->int_type = INTENTRY_TYPE_NMI;
+	mpie->int_flags = INTENTRY_FLAGS_POLARITY_CONFORM |
+	    INTENTRY_FLAGS_TRIGGER_CONFORM;
+	mpie->dst_apic_id = 0xff;
+	mpie->dst_apic_int = 1;
+}
+
+static void
 mpt_build_bus_entries(bus_entry_ptr mpeb)
 {
 
@@ -275,6 +302,11 @@ mptable_build(struct vmctx *ctx, int ncp
 	curraddr += sizeof(*mpie) * MPEII_MAX_IRQ;
 	mpch->entry_count += MPEII_MAX_IRQ;
 
+	mpie = (int_entry_ptr)curraddr;
+	mpt_build_localint_entries(mpie);
+	curraddr += sizeof(*mpie) * MPEII_NUM_LOCAL_IRQ;
+	mpch->entry_count += MPEII_NUM_LOCAL_IRQ;
+
 	if (oem_tbl_start) {
 		mpch->oem_table_pointer = curraddr - startaddr + MPTABLE_BASE;
 		mpch->oem_table_size = oem_tbl_size;

Modified: head/usr.sbin/bhyvectl/bhyvectl.c
==============================================================================
--- head/usr.sbin/bhyvectl/bhyvectl.c	Mon Dec 23 19:04:14 2013	(r259778)
+++ head/usr.sbin/bhyvectl/bhyvectl.c	Mon Dec 23 19:29:07 2013	(r259779)
@@ -190,13 +190,14 @@ usage(void)
 	"       [--get-lowmem]\n"
 	"       [--get-highmem]\n"
 	"       [--get-gpa-pmap]\n"
+	"       [--assert-lapic-lvt=<pin>]\n"
 	"       [--inject-nmi]\n",
 	progname);
 	exit(1);
 }
 
 static int get_stats, getcap, setcap, capval, get_gpa_pmap;
-static int inject_nmi;
+static int inject_nmi, assert_lapic_lvt;
 static const char *capname;
 static int create, destroy, get_lowmem, get_highmem;
 static uint64_t memsize;
@@ -381,6 +382,7 @@ enum {
 	CAPNAME,
 	UNASSIGN_PPTDEV,
 	GET_GPA_PMAP,
+	ASSERT_LAPIC_LVT,
 };
 
 int
@@ -433,6 +435,7 @@ main(int argc, char *argv[])
 		{ "unassign-pptdev", REQ_ARG,	0,	UNASSIGN_PPTDEV },
 		{ "setcap",	REQ_ARG,	0,	SET_CAP },
 		{ "get-gpa-pmap", REQ_ARG,	0,	GET_GPA_PMAP },
+		{ "assert-lapic-lvt", REQ_ARG,	0,	ASSERT_LAPIC_LVT },
 		{ "getcap",	NO_ARG,		&getcap,	1 },
 		{ "get-stats",	NO_ARG,		&get_stats,	1 },
 		{ "get-desc-ds",NO_ARG,		&get_desc_ds,	1 },
@@ -564,6 +567,7 @@ main(int argc, char *argv[])
 	};
 
 	vcpu = 0;
+	assert_lapic_lvt = -1;
 	progname = basename(argv[0]);
 
 	while ((ch = getopt_long(argc, argv, "", opts, NULL)) != -1) {
@@ -685,6 +689,9 @@ main(int argc, char *argv[])
 			if (sscanf(optarg, "%d/%d/%d", &bus, &slot, &func) != 3)
 				usage();
 			break;
+		case ASSERT_LAPIC_LVT:
+			assert_lapic_lvt = atoi(optarg);
+			break;
 		default:
 			usage();
 		}
@@ -832,6 +839,10 @@ main(int argc, char *argv[])
 		error = vm_inject_nmi(ctx, vcpu);
 	}
 
+	if (!error && assert_lapic_lvt != -1) {
+		error = vm_lapic_local_irq(ctx, vcpu, assert_lapic_lvt);
+	}
+
 	if (!error && (get_lowmem || get_all)) {
 		gpa = 0;
 		error = vm_get_memory_seg(ctx, gpa, &len, &wired);


More information about the svn-src-all mailing list