aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libvmmapi/vmmapi.c12
-rw-r--r--lib/libvmmapi/vmmapi.h1
-rw-r--r--sys/amd64/include/vmm_dev.h3
-rw-r--r--sys/amd64/vmm/io/vlapic.c166
-rw-r--r--sys/amd64/vmm/io/vlapic.h4
-rw-r--r--sys/amd64/vmm/vmm_dev.c5
-rw-r--r--sys/amd64/vmm/vmm_lapic.c27
-rw-r--r--sys/amd64/vmm/vmm_lapic.h7
-rw-r--r--usr.sbin/bhyve/acpi.c10
-rw-r--r--usr.sbin/bhyve/mptbl.c32
-rw-r--r--usr.sbin/bhyvectl/bhyvectl.c13
11 files changed, 264 insertions, 16 deletions
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
index 463ae7e5ec38..6fec469ac92f 100644
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -397,6 +397,18 @@ vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector)
}
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;
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
index 52e7e92bebbd..69762c7cf995 100644
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -67,6 +67,7 @@ int vm_inject_event(struct vmctx *ctx, int vcpu, enum vm_event_type type,
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);
diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h
index b71b745795e9..454c411e5fae 100644
--- a/sys/amd64/include/vmm_dev.h
+++ b/sys/amd64/include/vmm_dev.h
@@ -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 \
diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c
index 39db9c9f1b65..695040dc2118 100644
--- a/sys/amd64/vmm/io/vlapic.c
+++ b/sys/amd64/vmm/io/vlapic.c
@@ -91,7 +91,7 @@ static MALLOC_DEFINE(M_VLAPIC, "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 *vlapic, int vector, bool level)
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, uint32_t offset)
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, uint32_t offset)
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, uint32_t offset, uint32_t val)
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 *vlapic)
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, uint64_t icrval, bool *retu)
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, uint64_t offset, uint64_t *data, bool *retu)
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, uint64_t offset, uint64_t data, bool *retu)
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;
diff --git a/sys/amd64/vmm/io/vlapic.h b/sys/amd64/vmm/io/vlapic.h
index f66994074c35..98f377eeec05 100644
--- a/sys/amd64/vmm/io/vlapic.h
+++ b/sys/amd64/vmm/io/vlapic.h
@@ -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, uint64_t offset, uint64_t *data,
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);
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
index 829d8d5c18c3..4b5f691021f5 100644
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -297,6 +297,11 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
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);
diff --git a/sys/amd64/vmm/vmm_lapic.c b/sys/amd64/vmm/vmm_lapic.c
index 96234a186ed1..8d915cd156d4 100644
--- a/sys/amd64/vmm/vmm_lapic.c
+++ b/sys/amd64/vmm/vmm_lapic.c
@@ -90,6 +90,33 @@ lapic_set_intr(struct vm *vm, int cpu, int vector, bool level)
}
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;
diff --git a/sys/amd64/vmm/vmm_lapic.h b/sys/amd64/vmm/vmm_lapic.h
index d7e75a960c03..c5c95aa69ff0 100644
--- a/sys/amd64/vmm/vmm_lapic.h
+++ b/sys/amd64/vmm/vmm_lapic.h
@@ -84,5 +84,12 @@ lapic_intr_edge(struct vm *vm, int cpu, int vector)
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
diff --git a/usr.sbin/bhyve/acpi.c b/usr.sbin/bhyve/acpi.c
index 32dd84243035..71c7bbdf0191 100644
--- a/usr.sbin/bhyve/acpi.c
+++ b/usr.sbin/bhyve/acpi.c
@@ -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);
diff --git a/usr.sbin/bhyve/mptbl.c b/usr.sbin/bhyve/mptbl.c
index 3d45cc6cd77b..50e4e203807b 100644
--- a/usr.sbin/bhyve/mptbl.c
+++ b/usr.sbin/bhyve/mptbl.c
@@ -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 mpep, int ncpu)
}
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 ncpu)
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;
diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c
index 1b68776dca2e..c697492230de 100644
--- a/usr.sbin/bhyvectl/bhyvectl.c
+++ b/usr.sbin/bhyvectl/bhyvectl.c
@@ -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);