summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortychon <tychon@FreeBSD.org>2014-04-14 19:00:20 +0000
committertychon <tychon@FreeBSD.org>2014-04-14 19:00:20 +0000
commit5906c6773b959dc0603b2a0ecf5744a8c6dcf3d5 (patch)
treeabc3965993a67d6437ea7cf084d499b75060e460
parent78e547c5404320fbd04ad333c9f9691a30b0e86e (diff)
downloadFreeBSD-src-5906c6773b959dc0603b2a0ecf5744a8c6dcf3d5.zip
FreeBSD-src-5906c6773b959dc0603b2a0ecf5744a8c6dcf3d5.tar.gz
Add support for emulating the slave PIC.
Reviewed by: grehan, jhb Approved by: grehan (co-mentor)
-rw-r--r--lib/libvmmapi/vmmapi.h2
-rw-r--r--sys/amd64/vmm/io/vatpic.c197
-rw-r--r--usr.sbin/bhyve/pm.c4
3 files changed, 135 insertions, 68 deletions
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
index ce150d8..ed63fb2 100644
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -72,9 +72,9 @@ int vm_ioapic_assert_irq(struct vmctx *ctx, int irq);
int vm_ioapic_deassert_irq(struct vmctx *ctx, int irq);
int vm_ioapic_pulse_irq(struct vmctx *ctx, int irq);
int vm_ioapic_pincount(struct vmctx *ctx, int *pincount);
+int vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
int vm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
int vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
-int vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq);
int vm_inject_nmi(struct vmctx *ctx, int vcpu);
int vm_capability_name2type(const char *capname);
const char *vm_capability_type2name(int type);
diff --git a/sys/amd64/vmm/io/vatpic.c b/sys/amd64/vmm/io/vatpic.c
index bc05722..8e582fa 100644
--- a/sys/amd64/vmm/io/vatpic.c
+++ b/sys/amd64/vmm/io/vatpic.c
@@ -67,6 +67,7 @@ struct atpic {
bool aeoi;
bool poll;
bool rotate;
+ bool sfn; /* special fully-nested mode */
int irq_base;
uint8_t request; /* Interrupt Request Register (IIR) */
@@ -75,6 +76,8 @@ struct atpic {
int acnt[8]; /* sum of pin asserts and deasserts */
int priority; /* current pin priority */
+
+ bool intr_raised;
};
struct vatpic {
@@ -82,8 +85,6 @@ struct vatpic {
struct mtx mtx;
struct atpic atpic[2];
uint8_t elc[2];
-
- bool intr_raised;
};
#define VATPIC_CTR0(vatpic, fmt) \
@@ -101,6 +102,7 @@ struct vatpic {
#define VATPIC_CTR4(vatpic, fmt, a1, a2, a3, a4) \
VM_CTR4((vatpic)->vm, fmt, a1, a2, a3, a4)
+static void vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate);
static __inline int
vatpic_get_highest_isrpin(struct atpic *atpic)
@@ -122,13 +124,23 @@ vatpic_get_highest_isrpin(struct atpic *atpic)
static __inline int
vatpic_get_highest_irrpin(struct atpic *atpic)
{
+ int serviced;
int bit, pin;
int i, j;
+ /*
+ * In 'Special Fully-Nested Mode' when an interrupt request from
+ * a slave is in service, the slave is not locked out from the
+ * master's priority logic.
+ */
+ serviced = atpic->service;
+ if (atpic->sfn)
+ serviced &= ~(1 << 2);
+
for (i = 0; i <= 7; i++) {
pin = ((i + 7 - atpic->priority) & 0x7);
bit = (1 << pin);
- if (atpic->service & bit)
+ if (serviced & bit)
break;
}
@@ -150,14 +162,35 @@ vatpic_notify_intr(struct vatpic *vatpic)
KASSERT(VATPIC_LOCKED(vatpic), ("vatpic_notify_intr not locked"));
- if (vatpic->intr_raised == true)
- return;
+ /*
+ * First check the slave.
+ */
+ atpic = &vatpic->atpic[1];
+ if (!atpic->intr_raised &&
+ (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
+ VATPIC_CTR4(vatpic, "atpic slave notify pin = %d "
+ "(imr 0x%x irr 0x%x isr 0x%x)", pin,
+ atpic->mask, atpic->request, atpic->service);
- /* XXX master only */
- atpic = &vatpic->atpic[0];
+ /*
+ * Cascade the request from the slave to the master.
+ */
+ atpic->intr_raised = true;
+ vatpic_set_pinstate(vatpic, 2, true);
+ vatpic_set_pinstate(vatpic, 2, false);
+ } else {
+ VATPIC_CTR3(vatpic, "atpic slave no eligible interrupts "
+ "(imr 0x%x irr 0x%x isr 0x%x)",
+ atpic->mask, atpic->request, atpic->service);
+ }
- if ((pin = vatpic_get_highest_irrpin(atpic)) != -1) {
- VATPIC_CTR4(vatpic, "atpic notify pin = %d "
+ /*
+ * Then check the master.
+ */
+ atpic = &vatpic->atpic[0];
+ if (!atpic->intr_raised &&
+ (pin = vatpic_get_highest_irrpin(atpic)) != -1) {
+ VATPIC_CTR4(vatpic, "atpic master notify pin = %d "
"(imr 0x%x irr 0x%x isr 0x%x)", pin,
atpic->mask, atpic->request, atpic->service);
@@ -183,11 +216,11 @@ vatpic_notify_intr(struct vatpic *vatpic)
* programmed as ExtINT to indicate that the PIC is
* the source of the interrupt.
*/
+ atpic->intr_raised = true;
lapic_set_local_intr(vatpic->vm, -1, APIC_LVT_LINT0);
vioapic_pulse_irq(vatpic->vm, 0);
- vatpic->intr_raised = true;
} else {
- VATPIC_CTR3(vatpic, "atpic no eligible interrupts "
+ VATPIC_CTR3(vatpic, "atpic master no eligible interrupts "
"(imr 0x%x irr 0x%x isr 0x%x)",
atpic->mask, atpic->request, atpic->service);
}
@@ -422,7 +455,6 @@ vatpic_pending_intr(struct vm *vm, int *vecptr)
vatpic = vm_atpic(vm);
- /* XXX master only */
atpic = &vatpic->atpic[0];
VATPIC_LOCK(vatpic);
@@ -430,37 +462,53 @@ vatpic_pending_intr(struct vm *vm, int *vecptr)
pin = vatpic_get_highest_irrpin(atpic);
if (pin == -1)
pin = 7;
+ if (pin == 2) {
+ atpic = &vatpic->atpic[1];
+ pin = vatpic_get_highest_irrpin(atpic);
+ }
*vecptr = atpic->irq_base + pin;
VATPIC_UNLOCK(vatpic);
}
+static void
+vatpic_pin_accepted(struct atpic *atpic, int pin)
+{
+ atpic->intr_raised = false;
+
+ if (atpic->acnt[pin] == 0)
+ atpic->request &= ~(1 << pin);
+
+ if (atpic->aeoi == true) {
+ if (atpic->rotate == true)
+ atpic->priority = pin;
+ } else {
+ atpic->service |= (1 << pin);
+ }
+}
+
void
vatpic_intr_accepted(struct vm *vm, int vector)
{
struct vatpic *vatpic;
- struct atpic *atpic;
int pin;
vatpic = vm_atpic(vm);
- /* XXX master only */
- atpic = &vatpic->atpic[0];
-
VATPIC_LOCK(vatpic);
- vatpic->intr_raised = false;
pin = vector & 0x7;
- if (atpic->acnt[pin] == 0)
- atpic->request &= ~(1 << pin);
-
- if (atpic->aeoi == true) {
- if (atpic->rotate == true)
- atpic->priority = pin;
+ if ((vector & ~0x7) == vatpic->atpic[1].irq_base) {
+ vatpic_pin_accepted(&vatpic->atpic[1], pin);
+ /*
+ * If this vector originated from the slave,
+ * accept the cascaded interrupt too.
+ */
+ vatpic_pin_accepted(&vatpic->atpic[0], 2);
} else {
- atpic->service |= (1 << pin);
+ vatpic_pin_accepted(&vatpic->atpic[0], pin);
}
vatpic_notify_intr(vatpic);
@@ -468,47 +516,43 @@ vatpic_intr_accepted(struct vm *vm, int vector)
VATPIC_UNLOCK(vatpic);
}
-int
-vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
+static int
+vatpic_read(struct vatpic *vatpic, struct atpic *atpic, struct vm_exit *vmexit)
{
- struct vatpic *vatpic;
- struct atpic *atpic;
- int error;
- uint8_t val;
-
- error = 0;
- vatpic = vm_atpic(vm);
- atpic = &vatpic->atpic[0];
+ VATPIC_LOCK(vatpic);
- if (vmexit->u.inout.bytes != 1)
+ if (atpic->poll) {
+ VATPIC_CTR0(vatpic, "vatpic polled mode not supported");
+ VATPIC_UNLOCK(vatpic);
return (-1);
-
- if (vmexit->u.inout.in) {
- VATPIC_LOCK(vatpic);
- if (atpic->poll) {
- VATPIC_CTR0(vatpic, "vatpic polled mode not "
- "supported");
- VATPIC_UNLOCK(vatpic);
- return (-1);
+ } else {
+ if (vmexit->u.inout.port & ICU_IMR_OFFSET) {
+ /* read interrrupt mask register */
+ vmexit->u.inout.eax = atpic->mask;
} else {
- if (vmexit->u.inout.port & ICU_IMR_OFFSET) {
- /* read interrrupt mask register */
- vmexit->u.inout.eax = atpic->mask;
+ if (atpic->rd_cmd_reg == OCW3_RIS) {
+ /* read interrupt service register */
+ vmexit->u.inout.eax = atpic->service;
} else {
- if (atpic->rd_cmd_reg == OCW3_RIS) {
- /* read interrupt service register */
- vmexit->u.inout.eax = atpic->service;
- } else {
- /* read interrupt request register */
- vmexit->u.inout.eax = atpic->request;
- }
+ /* read interrupt request register */
+ vmexit->u.inout.eax = atpic->request;
}
}
- VATPIC_UNLOCK(vatpic);
-
- return (0);
}
+ VATPIC_UNLOCK(vatpic);
+
+ return (0);
+
+}
+
+static int
+vatpic_write(struct vatpic *vatpic, struct atpic *atpic,
+ struct vm_exit *vmexit)
+{
+ int error;
+ uint8_t val;
+
val = vmexit->u.inout.eax;
VATPIC_LOCK(vatpic);
@@ -550,22 +594,41 @@ vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
}
int
-vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
+vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
{
+ struct vatpic *vatpic;
+ struct atpic *atpic;
+
+ vatpic = vm_atpic(vm);
+ atpic = &vatpic->atpic[0];
+
if (vmexit->u.inout.bytes != 1)
return (-1);
if (vmexit->u.inout.in) {
- if (vmexit->u.inout.port & ICU_IMR_OFFSET) {
- /* all interrupts masked */
- vmexit->u.inout.eax = 0xff;
- } else {
- vmexit->u.inout.eax = 0x00;
- }
+ return (vatpic_read(vatpic, atpic, vmexit));
}
- /* Pretend all accesses to the slave 8259 are alright */
- return (0);
+ return (vatpic_write(vatpic, atpic, vmexit));
+}
+
+int
+vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
+{
+ struct vatpic *vatpic;
+ struct atpic *atpic;
+
+ vatpic = vm_atpic(vm);
+ atpic = &vatpic->atpic[1];
+
+ if (vmexit->u.inout.bytes != 1)
+ return (-1);
+
+ if (vmexit->u.inout.in) {
+ return (vatpic_read(vatpic, atpic, vmexit));
+ }
+
+ return (vatpic_write(vatpic, atpic, vmexit));
}
int
@@ -580,6 +643,8 @@ vatpic_elc_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
if (vmexit->u.inout.bytes != 1)
return (-1);
+ VATPIC_LOCK(vatpic);
+
if (vmexit->u.inout.in) {
if (is_master)
vmexit->u.inout.eax = vatpic->elc[0];
@@ -602,6 +667,8 @@ vatpic_elc_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
vatpic->elc[1] = (vmexit->u.inout.eax & 0xde);
}
+ VATPIC_UNLOCK(vatpic);
+
return (0);
}
diff --git a/usr.sbin/bhyve/pm.c b/usr.sbin/bhyve/pm.c
index 627f527..99087e4 100644
--- a/usr.sbin/bhyve/pm.c
+++ b/usr.sbin/bhyve/pm.c
@@ -83,7 +83,7 @@ sci_assert(struct vmctx *ctx)
if (sci_active)
return;
- vm_ioapic_assert_irq(ctx, SCI_INT);
+ vm_isa_assert_irq(ctx, SCI_INT, SCI_INT);
sci_active = 1;
}
@@ -93,7 +93,7 @@ sci_deassert(struct vmctx *ctx)
if (!sci_active)
return;
- vm_ioapic_deassert_irq(ctx, SCI_INT);
+ vm_isa_deassert_irq(ctx, SCI_INT, SCI_INT);
sci_active = 0;
}
OpenPOWER on IntegriCloud