summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libvmmapi/vmmapi.c35
-rw-r--r--lib/libvmmapi/vmmapi.h3
-rw-r--r--sys/amd64/include/vmm.h1
-rw-r--r--sys/amd64/include/vmm_dev.h16
-rw-r--r--sys/amd64/vmm/intel/vmx.c6
-rw-r--r--sys/amd64/vmm/io/vatpic.c595
-rw-r--r--sys/amd64/vmm/io/vatpic.h53
-rw-r--r--sys/amd64/vmm/io/vhpet.c35
-rw-r--r--sys/amd64/vmm/io/vlapic.c54
-rw-r--r--sys/amd64/vmm/io/vlapic_priv.h2
-rw-r--r--sys/amd64/vmm/vmm.c10
-rw-r--r--sys/amd64/vmm/vmm_dev.c22
-rw-r--r--sys/amd64/vmm/vmm_ioport.c (renamed from usr.sbin/bhyve/elcr.c)58
-rw-r--r--sys/amd64/vmm/vmm_ioport.h37
-rw-r--r--sys/modules/vmm/Makefile2
-rw-r--r--usr.sbin/bhyve/Makefile2
-rw-r--r--usr.sbin/bhyve/atpic.c89
-rw-r--r--usr.sbin/bhyve/pci_lpc.c22
-rw-r--r--usr.sbin/bhyve/pit_8254.c2
19 files changed, 916 insertions, 128 deletions
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
index 7198c99..22b536a 100644
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -458,6 +458,41 @@ vm_ioapic_pincount(struct vmctx *ctx, int *pincount)
}
int
+vm_isa_assert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq)
+{
+ struct vm_isa_irq isa_irq;
+
+ bzero(&isa_irq, sizeof(struct vm_isa_irq));
+ isa_irq.atpic_irq = atpic_irq;
+ isa_irq.ioapic_irq = ioapic_irq;
+
+ return (ioctl(ctx->fd, VM_ISA_ASSERT_IRQ, &isa_irq));
+}
+
+int
+vm_isa_deassert_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq)
+{
+ struct vm_isa_irq isa_irq;
+
+ bzero(&isa_irq, sizeof(struct vm_isa_irq));
+ isa_irq.atpic_irq = atpic_irq;
+ isa_irq.ioapic_irq = ioapic_irq;
+
+ return (ioctl(ctx->fd, VM_ISA_DEASSERT_IRQ, &isa_irq));
+}
+
+int
+vm_isa_pulse_irq(struct vmctx *ctx, int atpic_irq, int ioapic_irq)
+{
+ struct vm_isa_irq isa_irq;
+ bzero(&isa_irq, sizeof(struct vm_isa_irq));
+ isa_irq.atpic_irq = atpic_irq;
+ isa_irq.ioapic_irq = ioapic_irq;
+
+ return (ioctl(ctx->fd, VM_ISA_PULSE_IRQ, &isa_irq));
+}
+
+int
vm_inject_nmi(struct vmctx *ctx, int vcpu)
{
struct vm_nmi vmnmi;
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
index dcb5a98..085af94 100644
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -71,6 +71,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_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/include/vmm.h b/sys/amd64/include/vmm.h
index e9e06cb..f89d506 100644
--- a/sys/amd64/include/vmm.h
+++ b/sys/amd64/include/vmm.h
@@ -187,6 +187,7 @@ void vcpu_notify_event(struct vm *vm, int vcpuid, bool lapic_intr);
struct vmspace *vm_get_vmspace(struct vm *vm);
int vm_assign_pptdev(struct vm *vm, int bus, int slot, int func);
int vm_unassign_pptdev(struct vm *vm, int bus, int slot, int func);
+struct vatpic *vm_atpic(struct vm *vm);
/*
* Inject exception 'vme' into the guest vcpu. This function returns 0 on
diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h
index c75f5cf..eda9b94 100644
--- a/sys/amd64/include/vmm_dev.h
+++ b/sys/amd64/include/vmm_dev.h
@@ -79,6 +79,11 @@ struct vm_ioapic_irq {
int irq;
};
+struct vm_isa_irq {
+ int atpic_irq;
+ int ioapic_irq;
+};
+
struct vm_capability {
int cpuid;
enum vm_cap_type captype;
@@ -198,6 +203,11 @@ enum {
IOCNUM_SET_X2APIC_STATE = 60,
IOCNUM_GET_X2APIC_STATE = 61,
IOCNUM_GET_HPET_CAPABILITIES = 62,
+
+ /* legacy interrupt injection */
+ IOCNUM_ISA_ASSERT_IRQ = 80,
+ IOCNUM_ISA_DEASSERT_IRQ = 81,
+ IOCNUM_ISA_PULSE_IRQ = 82,
};
#define VM_RUN \
@@ -230,6 +240,12 @@ enum {
_IOW('v', IOCNUM_IOAPIC_PULSE_IRQ, struct vm_ioapic_irq)
#define VM_IOAPIC_PINCOUNT \
_IOR('v', IOCNUM_IOAPIC_PINCOUNT, int)
+#define VM_ISA_ASSERT_IRQ \
+ _IOW('v', IOCNUM_ISA_ASSERT_IRQ, struct vm_isa_irq)
+#define VM_ISA_DEASSERT_IRQ \
+ _IOW('v', IOCNUM_ISA_DEASSERT_IRQ, struct vm_isa_irq)
+#define VM_ISA_PULSE_IRQ \
+ _IOW('v', IOCNUM_ISA_PULSE_IRQ, struct vm_isa_irq)
#define VM_SET_CAPABILITY \
_IOW('v', IOCNUM_SET_CAPABILITY, struct vm_capability)
#define VM_GET_CAPABILITY \
diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
index ddbaf6e..1489a31 100644
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <machine/vmm.h>
#include <machine/vmm_dev.h>
#include "vmm_host.h"
+#include "vmm_ioport.h"
#include "vmm_ipi.h"
#include "vmm_msr.h"
#include "vmm_ktr.h"
@@ -1861,6 +1862,11 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
vmexit->u.inout.rep = (qual & 0x20) ? 1 : 0;
vmexit->u.inout.port = (uint16_t)(qual >> 16);
vmexit->u.inout.eax = (uint32_t)(vmxctx->guest_rax);
+ error = emulate_ioport(vmx->vm, vcpu, vmexit);
+ if (error == 0) {
+ handled = 1;
+ vmxctx->guest_rax = vmexit->u.inout.eax;
+ }
break;
case EXIT_REASON_CPUID:
vmm_stat_incr(vmx->vm, vcpu, VMEXIT_CPUID, 1);
diff --git a/sys/amd64/vmm/io/vatpic.c b/sys/amd64/vmm/io/vatpic.c
new file mode 100644
index 0000000..607484e
--- /dev/null
+++ b/sys/amd64/vmm/io/vatpic.c
@@ -0,0 +1,595 @@
+/*-
+ * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/cpuset.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <x86/apicreg.h>
+#include <dev/ic/i8259.h>
+
+#include <machine/vmm.h>
+
+#include "vmm_ktr.h"
+#include "vmm_lapic.h"
+#include "vioapic.h"
+#include "vatpic.h"
+
+static MALLOC_DEFINE(M_VATPIC, "atpic", "bhyve virtual atpic (8259)");
+
+#define VATPIC_LOCK(vatpic) mtx_lock_spin(&((vatpic)->mtx))
+#define VATPIC_UNLOCK(vatpic) mtx_unlock_spin(&((vatpic)->mtx))
+#define VATPIC_LOCKED(vatpic) mtx_owned(&((vatpic)->mtx))
+
+enum irqstate {
+ IRQSTATE_ASSERT,
+ IRQSTATE_DEASSERT,
+ IRQSTATE_PULSE
+};
+
+struct atpic {
+ bool ready;
+ int icw_num;
+ int rd_cmd_reg;
+
+ bool aeoi;
+ bool poll;
+ bool rotate;
+
+ int irq_base;
+ uint8_t request; /* Interrupt Request Register (IIR) */
+ uint8_t service; /* Interrupt Service (ISR) */
+ uint8_t mask; /* Interrupt Mask Register (IMR) */
+
+ int acnt[8]; /* sum of pin asserts and deasserts */
+ int priority; /* current pin priority */
+};
+
+struct vatpic {
+ struct vm *vm;
+ struct mtx mtx;
+ struct atpic atpic[2];
+ uint8_t elc[2];
+};
+
+#define VATPIC_CTR0(vatpic, fmt) \
+ VM_CTR0((vatpic)->vm, fmt)
+
+#define VATPIC_CTR1(vatpic, fmt, a1) \
+ VM_CTR1((vatpic)->vm, fmt, a1)
+
+#define VATPIC_CTR2(vatpic, fmt, a1, a2) \
+ VM_CTR2((vatpic)->vm, fmt, a1, a2)
+
+#define VATPIC_CTR3(vatpic, fmt, a1, a2, a3) \
+ VM_CTR3((vatpic)->vm, fmt, a1, a2, a3)
+
+#define VATPIC_CTR4(vatpic, fmt, a1, a2, a3, a4) \
+ VM_CTR4((vatpic)->vm, fmt, a1, a2, a3, a4)
+
+
+static __inline int
+vatpic_get_highest_isrpin(struct atpic *atpic)
+{
+ int bit, pin;
+ int i;
+
+ for (i = 0; i <= 7; i++) {
+ pin = ((i + 7 - atpic->priority) & 0x7);
+ bit = (1 << pin);
+
+ if (atpic->service & bit)
+ return (pin);
+ }
+
+ return (-1);
+}
+
+static __inline int
+vatpic_get_highest_irrpin(struct atpic *atpic)
+{
+ int bit, pin;
+ int i, j;
+
+ for (i = 0; i <= 7; i++) {
+ pin = ((i + 7 - atpic->priority) & 0x7);
+ bit = (1 << pin);
+ if (atpic->service & bit)
+ break;
+ }
+
+ for (j = 0; j < i; j++) {
+ pin = ((j + 7 - atpic->priority) & 0x7);
+ bit = (1 << pin);
+ if (atpic->request & bit && (~atpic->mask & bit))
+ return (pin);
+ }
+
+ return (-1);
+}
+
+static void
+vatpic_notify_intr(struct vatpic *vatpic)
+{
+ struct atpic *atpic;
+ int pin;
+
+ KASSERT(VATPIC_LOCKED(vatpic), ("vatpic_notify_intr not locked"));
+
+ /* XXX master only */
+ atpic = &vatpic->atpic[0];
+
+ if ((pin = vatpic_get_highest_irrpin(atpic)) != -1) {
+ VATPIC_CTR4(vatpic, "atpic notify pin = %d "
+ "(imr 0x%x irr 0x%x isr 0x%x)", pin,
+ atpic->mask, atpic->request, atpic->service);
+ lapic_set_local_intr(vatpic->vm, -1, APIC_LVT_LINT0);
+ vioapic_pulse_irq(vatpic->vm, 0);
+ } else {
+ VATPIC_CTR3(vatpic, "atpic no eligible interrupts "
+ "(imr 0x%x irr 0x%x isr 0x%x)",
+ atpic->mask, atpic->request, atpic->service);
+ }
+}
+
+static int
+vatpic_icw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
+{
+ VATPIC_CTR1(vatpic, "atpic icw1 0x%x", val);
+
+ atpic->ready = false;
+
+ atpic->icw_num = 1;
+ atpic->mask = 0;
+ atpic->priority = 0;
+ atpic->rd_cmd_reg = 0;
+
+ if ((val & ICW1_SNGL) != 0) {
+ VATPIC_CTR0(vatpic, "vatpic cascade mode required");
+ return (-1);
+ }
+
+ if ((val & ICW1_IC4) == 0) {
+ VATPIC_CTR0(vatpic, "vatpic icw4 required");
+ return (-1);
+ }
+
+ atpic->icw_num++;
+
+ return (0);
+}
+
+static int
+vatpic_icw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
+{
+ VATPIC_CTR1(vatpic, "atpic icw2 0x%x", val);
+
+ atpic->irq_base = val & 0xf8;
+
+ atpic->icw_num++;
+
+ return (0);
+}
+
+static int
+vatpic_icw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
+{
+ VATPIC_CTR1(vatpic, "atpic icw3 0x%x", val);
+
+ atpic->icw_num++;
+
+ return (0);
+}
+
+static int
+vatpic_icw4(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
+{
+ VATPIC_CTR1(vatpic, "atpic icw4 0x%x", val);
+
+ if ((val & ICW4_8086) == 0) {
+ VATPIC_CTR0(vatpic, "vatpic microprocessor mode required");
+ return (-1);
+ }
+
+ if ((val & ICW4_AEOI) != 0)
+ atpic->aeoi = true;
+
+ atpic->icw_num = 0;
+ atpic->ready = true;
+
+ return (0);
+}
+
+static int
+vatpic_ocw1(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
+{
+ VATPIC_CTR1(vatpic, "atpic ocw1 0x%x", val);
+
+ atpic->mask = val & 0xff;
+
+ return (0);
+}
+
+static int
+vatpic_ocw2(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
+{
+ VATPIC_CTR1(vatpic, "atpic ocw2 0x%x", val);
+
+ atpic->rotate = ((val & OCW2_R) != 0);
+
+ if ((val & OCW2_EOI) != 0) {
+ int isr_bit;
+
+ if ((val & OCW2_SL) != 0) {
+ /* specific EOI */
+ isr_bit = val & 0x7;
+ } else {
+ /* non-specific EOI */
+ isr_bit = vatpic_get_highest_isrpin(atpic);
+ }
+
+ if (isr_bit != -1) {
+ atpic->service &= ~(1 << isr_bit);
+
+ if (atpic->rotate)
+ atpic->priority = isr_bit;
+ }
+ } else if ((val & OCW2_SL) != 0 && atpic->rotate == true) {
+ /* specific priority */
+ atpic->priority = val & 0x7;
+ }
+
+ return (0);
+}
+
+static int
+vatpic_ocw3(struct vatpic *vatpic, struct atpic *atpic, uint8_t val)
+{
+ VATPIC_CTR1(vatpic, "atpic ocw3 0x%x", val);
+
+ atpic->poll = ((val & OCW3_P) != 0);
+
+ if (val & OCW3_RR) {
+ /* read register command */
+ atpic->rd_cmd_reg = val & OCW3_RIS;
+ }
+
+ return (0);
+}
+
+static void
+vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate)
+{
+ struct atpic *atpic;
+ int oldcnt, newcnt;
+ bool level;
+
+ KASSERT(pin >= 0 && pin < 16,
+ ("vatpic_set_pinstate: invalid pin number %d", pin));
+ KASSERT(VATPIC_LOCKED(vatpic),
+ ("vatpic_set_pinstate: vatpic is not locked"));
+
+ atpic = &vatpic->atpic[pin >> 3];
+
+ oldcnt = atpic->acnt[pin & 0x7];
+ if (newstate)
+ atpic->acnt[pin & 0x7]++;
+ else
+ atpic->acnt[pin & 0x7]--;
+ newcnt = atpic->acnt[pin & 0x7];
+
+ if (newcnt < 0) {
+ VATPIC_CTR2(vatpic, "atpic pin%d: bad acnt %d", pin, newcnt);
+ }
+
+ level = ((vatpic->elc[pin >> 3] & (1 << (pin & 0x7))) != 0);
+
+ if ((oldcnt == 0 && newcnt == 1) || (newcnt > 0 && level == true)) {
+ /* rising edge or level */
+ VATPIC_CTR1(vatpic, "atpic pin%d: asserted", pin);
+ atpic->request |= (1 << (pin & 0x7));
+ } else if (oldcnt == 1 && newcnt == 0) {
+ /* falling edge */
+ VATPIC_CTR1(vatpic, "atpic pin%d: deasserted", pin);
+ } else {
+ VATPIC_CTR3(vatpic, "atpic pin%d: %s, ignored, acnt %d",
+ pin, newstate ? "asserted" : "deasserted", newcnt);
+ }
+
+ vatpic_notify_intr(vatpic);
+}
+
+static int
+vatpic_set_irqstate(struct vm *vm, int irq, enum irqstate irqstate)
+{
+ struct vatpic *vatpic;
+ struct atpic *atpic;
+
+ if (irq < 0 || irq > 15)
+ return (EINVAL);
+
+ vatpic = vm_atpic(vm);
+ atpic = &vatpic->atpic[irq >> 3];
+
+ if (atpic->ready == false)
+ return (0);
+
+ VATPIC_LOCK(vatpic);
+ switch (irqstate) {
+ case IRQSTATE_ASSERT:
+ vatpic_set_pinstate(vatpic, irq, true);
+ break;
+ case IRQSTATE_DEASSERT:
+ vatpic_set_pinstate(vatpic, irq, false);
+ break;
+ case IRQSTATE_PULSE:
+ vatpic_set_pinstate(vatpic, irq, true);
+ vatpic_set_pinstate(vatpic, irq, false);
+ break;
+ default:
+ panic("vatpic_set_irqstate: invalid irqstate %d", irqstate);
+ }
+ VATPIC_UNLOCK(vatpic);
+
+ return (0);
+}
+
+int
+vatpic_assert_irq(struct vm *vm, int irq)
+{
+ return (vatpic_set_irqstate(vm, irq, IRQSTATE_ASSERT));
+}
+
+int
+vatpic_deassert_irq(struct vm *vm, int irq)
+{
+ return (vatpic_set_irqstate(vm, irq, IRQSTATE_DEASSERT));
+}
+
+int
+vatpic_pulse_irq(struct vm *vm, int irq)
+{
+ return (vatpic_set_irqstate(vm, irq, IRQSTATE_PULSE));
+}
+
+int
+vatpic_pending_intr(struct vm *vm, int *vecptr)
+{
+ struct vatpic *vatpic;
+ struct atpic *atpic;
+ int pin;
+
+ vatpic = vm_atpic(vm);
+
+ /* XXX master only */
+ atpic = &vatpic->atpic[0];
+
+ VATPIC_LOCK(vatpic);
+
+ pin = vatpic_get_highest_irrpin(atpic);
+ if (pin == -1)
+ pin = 7;
+
+ *vecptr = atpic->irq_base + pin;
+
+ VATPIC_UNLOCK(vatpic);
+
+ return (1);
+}
+
+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);
+ pin = vector & 0x7;
+
+ 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);
+ }
+
+ vatpic_notify_intr(vatpic);
+
+ VATPIC_UNLOCK(vatpic);
+}
+
+int
+vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
+{
+ struct vatpic *vatpic;
+ struct atpic *atpic;
+ int error;
+ uint8_t val;
+
+ vatpic = vm_atpic(vm);
+ atpic = &vatpic->atpic[0];
+
+ if (vmexit->u.inout.bytes != 1)
+ 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 (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;
+ }
+ }
+ }
+ VATPIC_UNLOCK(vatpic);
+
+ return (0);
+ }
+
+ val = vmexit->u.inout.eax;
+
+ VATPIC_LOCK(vatpic);
+
+ if (vmexit->u.inout.port & ICU_IMR_OFFSET) {
+ if (atpic->ready) {
+ error = vatpic_ocw1(vatpic, atpic, val);
+ } else {
+ switch (atpic->icw_num) {
+ case 2:
+ error = vatpic_icw2(vatpic, atpic, val);
+ break;
+ case 3:
+ error = vatpic_icw3(vatpic, atpic, val);
+ break;
+ case 4:
+ error = vatpic_icw4(vatpic, atpic, val);
+ break;
+ }
+ }
+ } else {
+ if (val & (1 << 4))
+ error = vatpic_icw1(vatpic, atpic, val);
+
+ if (atpic->ready) {
+ if (val & (1 << 3))
+ error = vatpic_ocw3(vatpic, atpic, val);
+ else
+ error = vatpic_ocw2(vatpic, atpic, val);
+ }
+ }
+
+ if (atpic->ready)
+ vatpic_notify_intr(vatpic);
+
+ VATPIC_UNLOCK(vatpic);
+
+ return (error);
+}
+
+int
+vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
+{
+ 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;
+ }
+ }
+
+ /* Pretend all accesses to the slave 8259 are alright */
+ return (0);
+}
+
+int
+vatpic_elc_handler(void *vm, int vcpuid, struct vm_exit *vmexit)
+{
+ struct vatpic *vatpic;
+ bool is_master;
+
+ vatpic = vm_atpic(vm);
+ is_master = (vmexit->u.inout.port == IO_ELCR1);
+
+ if (vmexit->u.inout.bytes != 1)
+ return (-1);
+
+ if (vmexit->u.inout.in) {
+ if (is_master)
+ vmexit->u.inout.eax = vatpic->elc[0];
+ else
+ vmexit->u.inout.eax = vatpic->elc[1];
+ } else {
+ /*
+ * For the master PIC the cascade channel (IRQ2), the
+ * heart beat timer (IRQ0), and the keyboard
+ * controller (IRQ1) cannot be programmed for level
+ * mode.
+ *
+ * For the slave PIC the real time clock (IRQ8) and
+ * the floating point error interrupt (IRQ13) cannot
+ * be programmed for level mode.
+ */
+ if (is_master)
+ vatpic->elc[0] = (vmexit->u.inout.eax & 0xf8);
+ else
+ vatpic->elc[1] = (vmexit->u.inout.eax & 0xde);
+ }
+
+ return (0);
+}
+
+struct vatpic *
+vatpic_init(struct vm *vm)
+{
+ struct vatpic *vatpic;
+
+ vatpic = malloc(sizeof(struct vatpic), M_VATPIC, M_WAITOK | M_ZERO);
+ vatpic->vm = vm;
+
+ mtx_init(&vatpic->mtx, "vatpic lock", NULL, MTX_SPIN);
+
+ return (vatpic);
+}
+
+void
+vatpic_cleanup(struct vatpic *vatpic)
+{
+ free(vatpic, M_VATPIC);
+}
diff --git a/sys/amd64/vmm/io/vatpic.h b/sys/amd64/vmm/io/vatpic.h
new file mode 100644
index 0000000..365ccc4
--- /dev/null
+++ b/sys/amd64/vmm/io/vatpic.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _VATPIC_H_
+#define _VATPIC_H_
+
+#include <isa/isareg.h>
+
+#define ICU_IMR_OFFSET 1
+
+#define IO_ELCR1 0x4d0
+#define IO_ELCR2 0x4d1
+
+struct vatpic *vatpic_init(struct vm *vm);
+void vatpic_cleanup(struct vatpic *vatpic);
+
+int vatpic_master_handler(void *vm, int vcpuid, struct vm_exit *vmexit);
+int vatpic_slave_handler(void *vm, int vcpuid, struct vm_exit *vmexit);
+int vatpic_elc_handler(void *vm, int vcpuid, struct vm_exit *vmexit);
+
+int vatpic_assert_irq(struct vm *vm, int irq);
+int vatpic_deassert_irq(struct vm *vm, int irq);
+int vatpic_pulse_irq(struct vm *vm, int irq);
+
+int vatpic_pending_intr(struct vm *vm, int *vecptr);
+void vatpic_intr_accepted(struct vm *vm, int vector);
+
+#endif /* _VATPIC_H_ */
diff --git a/sys/amd64/vmm/io/vhpet.c b/sys/amd64/vmm/io/vhpet.c
index 993d5e6..46e5ca7 100644
--- a/sys/amd64/vmm/io/vhpet.c
+++ b/sys/amd64/vmm/io/vhpet.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <machine/vmm_dev.h>
#include "vmm_lapic.h"
+#include "vatpic.h"
#include "vioapic.h"
#include "vhpet.h"
@@ -167,6 +168,25 @@ vhpet_timer_ioapic_pin(struct vhpet *vhpet, int n)
return ((vhpet->timer[n].cap_config & HPET_TCNF_INT_ROUTE) >> 9);
}
+static __inline int
+vhpet_timer_atpic_pin(struct vhpet *vhpet, int n)
+{
+ if (vhpet->config & HPET_CNF_LEG_RT) {
+ /*
+ * In "legacy routing" timers 0 and 1 are connected to
+ * 8259 master pin 0 and slave pin 0 respectively.
+ */
+ switch (n) {
+ case 0:
+ return (0);
+ case 1:
+ return (8);
+ }
+ }
+
+ return (-1);
+}
+
static uint32_t
vhpet_counter(struct vhpet *vhpet, sbintime_t *nowptr)
{
@@ -196,12 +216,17 @@ vhpet_counter(struct vhpet *vhpet, sbintime_t *nowptr)
static void
vhpet_timer_clear_isr(struct vhpet *vhpet, int n)
{
- int pin;
+ int pin, legacy_pin;
if (vhpet->isr & (1 << n)) {
pin = vhpet_timer_ioapic_pin(vhpet, n);
KASSERT(pin != 0, ("vhpet timer %d irq incorrectly routed", n));
vioapic_deassert_irq(vhpet->vm, pin);
+
+ legacy_pin = vhpet_timer_atpic_pin(vhpet, n);
+ if (legacy_pin != -1)
+ vatpic_deassert_irq(vhpet->vm, legacy_pin);
+
vhpet->isr &= ~(1 << n);
}
}
@@ -242,7 +267,7 @@ vhpet_timer_edge_trig(struct vhpet *vhpet, int n)
static void
vhpet_timer_interrupt(struct vhpet *vhpet, int n)
{
- int pin;
+ int pin, legacy_pin;
/* If interrupts are not enabled for this timer then just return. */
if (!vhpet_timer_interrupt_enabled(vhpet, n))
@@ -268,11 +293,17 @@ vhpet_timer_interrupt(struct vhpet *vhpet, int n)
return;
}
+ legacy_pin = vhpet_timer_atpic_pin(vhpet, n);
+
if (vhpet_timer_edge_trig(vhpet, n)) {
vioapic_pulse_irq(vhpet->vm, pin);
+ if (legacy_pin != -1)
+ vatpic_pulse_irq(vhpet->vm, legacy_pin);
} else {
vhpet->isr |= 1 << n;
vioapic_assert_irq(vhpet->vm, pin);
+ if (legacy_pin != -1)
+ vatpic_assert_irq(vhpet->vm, legacy_pin);
}
}
diff --git a/sys/amd64/vmm/io/vlapic.c b/sys/amd64/vmm/io/vlapic.c
index 6e8c433..69219b4 100644
--- a/sys/amd64/vmm/io/vlapic.c
+++ b/sys/amd64/vmm/io/vlapic.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include "vlapic.h"
#include "vlapic_priv.h"
+#include "vatpic.h"
#include "vioapic.h"
#define PRIO(x) ((x) >> 4)
@@ -299,6 +300,16 @@ vlapic_set_intr_ready(struct vlapic *vlapic, int vector, bool level)
return (1);
}
+static VMM_STAT(VLAPIC_EXTINT_COUNT, "number of ExtINTs received by vlapic");
+
+static void
+vlapic_deliver_extint(struct vlapic *vlapic)
+{
+ vmm_stat_incr(vlapic->vm, vlapic->vcpuid, VLAPIC_EXTINT_COUNT, 1);
+ vlapic->extint_pending = true;
+ vcpu_notify_event(vlapic->vm, vlapic->vcpuid, false);
+}
+
static __inline uint32_t *
vlapic_get_lvtptr(struct vlapic *vlapic, uint32_t offset)
{
@@ -448,6 +459,9 @@ vlapic_fire_lvt(struct vlapic *vlapic, uint32_t lvt)
case APIC_LVT_DM_NMI:
vm_inject_nmi(vlapic->vm, vlapic->vcpuid);
break;
+ case APIC_LVT_DM_EXTINT:
+ vlapic_deliver_extint(vlapic);
+ break;
default:
// Other modes ignored
return (0);
@@ -651,6 +665,25 @@ vlapic_trigger_lvt(struct vlapic *vlapic, int vector)
{
uint32_t lvt;
+ if (vlapic_enabled(vlapic) == false) {
+ /*
+ * When the local APIC is global/hardware disabled,
+ * LINT[1:0] pins are configured as INTR and NMI pins,
+ * respectively.
+ */
+ switch (vector) {
+ case APIC_LVT_LINT0:
+ vlapic_deliver_extint(vlapic);
+ break;
+ case APIC_LVT_LINT1:
+ vm_inject_nmi(vlapic->vm, vlapic->vcpuid);
+ break;
+ default:
+ break;
+ }
+ return (0);
+ }
+
switch (vector) {
case APIC_LVT_LINT0:
lvt = vlapic_get_lvt(vlapic, APIC_OFFSET_LINT0_LVT);
@@ -1020,6 +1053,9 @@ vlapic_pending_intr(struct vlapic *vlapic, int *vecptr)
int idx, i, bitpos, vector;
uint32_t *irrptr, val;
+ if (vlapic->extint_pending)
+ return (vatpic_pending_intr(vlapic->vm, vecptr));
+
if (vlapic->ops.pending_intr)
return ((*vlapic->ops.pending_intr)(vlapic, vecptr));
@@ -1054,6 +1090,12 @@ vlapic_intr_accepted(struct vlapic *vlapic, int vector)
uint32_t *irrptr, *isrptr;
int idx, stk_top;
+ if (vlapic->extint_pending) {
+ vlapic->extint_pending = false;
+ vatpic_intr_accepted(vlapic->vm, vector);
+ return;
+ }
+
if (vlapic->ops.intr_accepted)
return ((*vlapic->ops.intr_accepted)(vlapic, vector));
@@ -1474,11 +1516,13 @@ vlapic_deliver_intr(struct vm *vm, bool level, uint32_t dest, bool phys,
int vcpuid;
cpuset_t dmask;
- if (delmode != APIC_DELMODE_FIXED && delmode != APIC_DELMODE_LOWPRIO) {
+ if (delmode != IOART_DELFIXED &&
+ delmode != IOART_DELLOPRI &&
+ delmode != IOART_DELEXINT) {
VM_CTR1(vm, "vlapic intr invalid delmode %#x", delmode);
return;
}
- lowprio = (delmode == APIC_DELMODE_LOWPRIO);
+ lowprio = (delmode == IOART_DELLOPRI);
/*
* We don't provide any virtual interrupt redirection hardware so
@@ -1490,7 +1534,11 @@ vlapic_deliver_intr(struct vm *vm, bool level, uint32_t dest, bool phys,
while ((vcpuid = CPU_FFS(&dmask)) != 0) {
vcpuid--;
CPU_CLR(vcpuid, &dmask);
- lapic_set_intr(vm, vcpuid, vec, level);
+ if (delmode == IOART_DELEXINT) {
+ vlapic_deliver_extint(vm_lapic(vm, vcpuid));
+ } else {
+ lapic_set_intr(vm, vcpuid, vec, level);
+ }
}
}
diff --git a/sys/amd64/vmm/io/vlapic_priv.h b/sys/amd64/vmm/io/vlapic_priv.h
index 08592c8..d2a4bc0 100644
--- a/sys/amd64/vmm/io/vlapic_priv.h
+++ b/sys/amd64/vmm/io/vlapic_priv.h
@@ -156,6 +156,8 @@ struct vlapic {
uint32_t esr_pending;
int esr_firing;
+ bool extint_pending;
+
struct callout callout; /* vlapic timer */
struct bintime timer_fire_bt; /* callout expiry time */
struct bintime timer_freq_bt; /* timer frequency */
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index 241eb6c..e34d8e2 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$");
#include "vmm_host.h"
#include "vmm_mem.h"
#include "vmm_util.h"
+#include "vatpic.h"
#include "vhpet.h"
#include "vioapic.h"
#include "vlapic.h"
@@ -116,6 +117,7 @@ struct vm {
void *iommu; /* iommu-specific data */
struct vhpet *vhpet; /* virtual HPET */
struct vioapic *vioapic; /* virtual ioapic */
+ struct vatpic *vatpic; /* virtual atpic */
struct vmspace *vmspace; /* guest's address space */
struct vcpu vcpu[VM_MAXCPU];
int num_mem_segs;
@@ -345,6 +347,7 @@ vm_create(const char *name, struct vm **retvm)
vm->cookie = VMINIT(vm, vmspace_pmap(vmspace));
vm->vioapic = vioapic_init(vm);
vm->vhpet = vhpet_init(vm);
+ vm->vatpic = vatpic_init(vm);
for (i = 0; i < VM_MAXCPU; i++) {
vcpu_init(vm, i);
@@ -378,6 +381,7 @@ vm_destroy(struct vm *vm)
iommu_destroy_domain(vm->iommu);
vhpet_cleanup(vm->vhpet);
+ vatpic_cleanup(vm->vatpic);
vioapic_cleanup(vm->vioapic);
for (i = 0; i < vm->num_mem_segs; i++)
@@ -1637,3 +1641,9 @@ restart:
vm_handle_rendezvous(vm, vcpuid);
}
+
+struct vatpic *
+vm_atpic(struct vm *vm)
+{
+ return (vm->vatpic);
+}
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
index 6db2b98..5733685 100644
--- a/sys/amd64/vmm/vmm_dev.c
+++ b/sys/amd64/vmm/vmm_dev.c
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include "vmm_stat.h"
#include "vmm_mem.h"
#include "io/ppt.h"
+#include "io/vatpic.h"
#include "io/vioapic.h"
#include "io/vhpet.h"
@@ -154,6 +155,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
struct vm_lapic_irq *vmirq;
struct vm_lapic_msi *vmmsi;
struct vm_ioapic_irq *ioapic_irq;
+ struct vm_isa_irq *isa_irq;
struct vm_capability *vmcap;
struct vm_pptdev *pptdev;
struct vm_pptdev_mmio *pptmmio;
@@ -318,6 +320,26 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
case VM_IOAPIC_PINCOUNT:
*(int *)data = vioapic_pincount(sc->vm);
break;
+ case VM_ISA_ASSERT_IRQ:
+ isa_irq = (struct vm_isa_irq *)data;
+ error = vatpic_assert_irq(sc->vm, isa_irq->atpic_irq);
+ if (error == 0 && isa_irq->ioapic_irq != -1)
+ error = vioapic_assert_irq(sc->vm,
+ isa_irq->ioapic_irq);
+ break;
+ case VM_ISA_DEASSERT_IRQ:
+ isa_irq = (struct vm_isa_irq *)data;
+ error = vatpic_deassert_irq(sc->vm, isa_irq->atpic_irq);
+ if (error == 0 && isa_irq->ioapic_irq != -1)
+ error = vioapic_deassert_irq(sc->vm,
+ isa_irq->ioapic_irq);
+ break;
+ case VM_ISA_PULSE_IRQ:
+ isa_irq = (struct vm_isa_irq *)data;
+ error = vatpic_pulse_irq(sc->vm, isa_irq->atpic_irq);
+ if (error == 0 && isa_irq->ioapic_irq != -1)
+ error = vioapic_pulse_irq(sc->vm, isa_irq->ioapic_irq);
+ break;
case VM_MAP_MEMORY:
seg = (struct vm_memory_segment *)data;
error = vm_malloc(sc->vm, seg->gpa, seg->len);
diff --git a/usr.sbin/bhyve/elcr.c b/sys/amd64/vmm/vmm_ioport.c
index 190b5c6..7783dc2 100644
--- a/usr.sbin/bhyve/elcr.c
+++ b/sys/amd64/vmm/vmm_ioport.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2011 NetApp, Inc.
+ * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -11,10 +11,10 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -22,46 +22,44 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $FreeBSD$
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/param.h>
#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/cpuset.h>
+#include <sys/systm.h>
-#include "inout.h"
-#include "pci_lpc.h"
+#include <machine/vmm.h>
-/*
- * EISA interrupt Level Control Register.
- *
- * This is a 16-bit register with one bit for each of the IRQ0 through IRQ15.
- * A level triggered irq is indicated by setting the corresponding bit to '1'.
- */
-#define ELCR_PORT 0x4d0
+#include "vatpic.h"
+#include "vmm_ioport.h"
-static uint8_t elcr[2] = { 0x00, 0x00 };
+#define MAX_IOPORTS 1280
-static int
-elcr_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
- uint32_t *eax, void *arg)
+ioport_handler_func_t ioport_handler[MAX_IOPORTS] = {
+ [IO_ICU1] = vatpic_master_handler,
+ [IO_ICU1 + ICU_IMR_OFFSET] = vatpic_master_handler,
+ [IO_ICU2] = vatpic_slave_handler,
+ [IO_ICU2 + ICU_IMR_OFFSET] = vatpic_slave_handler,
+ [IO_ELCR1] = vatpic_elc_handler,
+ [IO_ELCR2] = vatpic_elc_handler,
+};
+
+int
+emulate_ioport(struct vm *vm, int vcpuid, struct vm_exit *vmexit)
{
- int idx;
+ ioport_handler_func_t handler;
- if (bytes != 1)
+ if (vmexit->u.inout.port >= MAX_IOPORTS)
return (-1);
- idx = port - ELCR_PORT;
-
- if (in)
- *eax = elcr[idx];
- else
- elcr[idx] = *eax;
+ handler = ioport_handler[vmexit->u.inout.port];
+ if (handler == NULL)
+ return (-1);
- return (0);
+ return ((*handler)(vm, vcpuid, vmexit));
}
-INOUT_PORT(elcr, ELCR_PORT + 0, IOPORT_F_INOUT, elcr_handler);
-INOUT_PORT(elcr, ELCR_PORT + 1, IOPORT_F_INOUT, elcr_handler);
-SYSRES_IO(ELCR_PORT, 2);
diff --git a/sys/amd64/vmm/vmm_ioport.h b/sys/amd64/vmm/vmm_ioport.h
new file mode 100644
index 0000000..5573146
--- /dev/null
+++ b/sys/amd64/vmm/vmm_ioport.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _VMM_IOPORT_H_
+#define _VMM_IOPORT_H_
+
+typedef int (*ioport_handler_func_t)(void *vm, int vcpuid,
+ struct vm_exit *vmexit);
+
+int emulate_ioport(struct vm *vm, int vcpuid, struct vm_exit *vmexit);
+
+#endif /* _VMM_IOPORT_H_ */
diff --git a/sys/modules/vmm/Makefile b/sys/modules/vmm/Makefile
index ea367a4..7a2b2df 100644
--- a/sys/modules/vmm/Makefile
+++ b/sys/modules/vmm/Makefile
@@ -15,6 +15,7 @@ SRCS+= vmm.c \
vmm_dev.c \
vmm_host.c \
vmm_instruction_emul.c \
+ vmm_ioport.c \
vmm_ipi.c \
vmm_lapic.c \
vmm_mem.c \
@@ -27,6 +28,7 @@ SRCS+= vmm.c \
.PATH: ${.CURDIR}/../../amd64/vmm/io
SRCS+= iommu.c \
ppt.c \
+ vatpic.c \
vhpet.c \
vioapic.c \
vlapic.c
diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
index e8bf793..98ead03 100644
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -10,12 +10,10 @@ MAN= bhyve.8
SRCS= \
acpi.c \
- atpic.c \
bhyverun.c \
block_if.c \
consport.c \
dbgport.c \
- elcr.c \
inout.c \
ioapic.c \
mem.c \
diff --git a/usr.sbin/bhyve/atpic.c b/usr.sbin/bhyve/atpic.c
deleted file mode 100644
index a23aee8..0000000
--- a/usr.sbin/bhyve/atpic.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*-
- * Copyright (c) 2011 NetApp, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-#include "acpi.h"
-#include "inout.h"
-#include "pci_lpc.h"
-
-#define IO_ICU1 0x20
-#define IO_ICU2 0xA0
-#define ICU_IMR_OFFSET 1
-
-static int
-atpic_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
- uint32_t *eax, void *arg)
-{
- if (bytes != 1)
- return (-1);
-
- if (in) {
- if (port & ICU_IMR_OFFSET) {
- /* all interrupts masked */
- *eax = 0xff;
- } else {
- *eax = 0x00;
- }
- }
-
- /* Pretend all writes to the 8259 are alright */
- return (0);
-}
-
-INOUT_PORT(atpic, IO_ICU1, IOPORT_F_INOUT, atpic_handler);
-INOUT_PORT(atpic, IO_ICU1 + ICU_IMR_OFFSET, IOPORT_F_INOUT, atpic_handler);
-INOUT_PORT(atpic, IO_ICU2, IOPORT_F_INOUT, atpic_handler);
-INOUT_PORT(atpic, IO_ICU2 + ICU_IMR_OFFSET, IOPORT_F_INOUT, atpic_handler);
-
-static void
-atpic_dsdt(void)
-{
-
- dsdt_line("");
- dsdt_line("Device (PIC)");
- dsdt_line("{");
- dsdt_line(" Name (_HID, EisaId (\"PNP0000\"))");
- dsdt_line(" Name (_CRS, ResourceTemplate ()");
- dsdt_line(" {");
- dsdt_indent(2);
- dsdt_fixed_ioport(IO_ICU1, 2);
- dsdt_fixed_ioport(IO_ICU2, 2);
- dsdt_fixed_irq(2);
- dsdt_unindent(2);
- dsdt_line(" })");
- dsdt_line("}");
-}
-LPC_DSDT(atpic_dsdt);
diff --git a/usr.sbin/bhyve/pci_lpc.c b/usr.sbin/bhyve/pci_lpc.c
index 30b0401..0ef9403 100644
--- a/usr.sbin/bhyve/pci_lpc.c
+++ b/usr.sbin/bhyve/pci_lpc.c
@@ -46,9 +46,15 @@ __FBSDID("$FreeBSD$");
#include "pci_lpc.h"
#include "uart_emul.h"
+#define IO_ICU1 0x20
+#define IO_ICU2 0xA0
+
SET_DECLARE(lpc_dsdt_set, struct lpc_dsdt);
SET_DECLARE(lpc_sysres_set, struct lpc_sysres);
+#define ELCR_PORT 0x4d0
+SYSRES_IO(ELCR_PORT, 2);
+
static struct pci_devinst *lpc_bridge;
#define LPC_UART_NUM 2
@@ -100,7 +106,7 @@ lpc_uart_intr_assert(void *arg)
assert(sc->irq >= 0);
- vm_ioapic_pulse_irq(lpc_bridge->pi_vmctx, sc->irq);
+ vm_isa_pulse_irq(lpc_bridge->pi_vmctx, sc->irq, sc->irq);
}
static void
@@ -192,6 +198,20 @@ pci_lpc_write_dsdt(struct pci_devinst *pi)
ldp = *ldpp;
ldp->handler();
}
+
+ dsdt_line("");
+ dsdt_line("Device (PIC)");
+ dsdt_line("{");
+ dsdt_line(" Name (_HID, EisaId (\"PNP0000\"))");
+ dsdt_line(" Name (_CRS, ResourceTemplate ()");
+ dsdt_line(" {");
+ dsdt_indent(2);
+ dsdt_fixed_ioport(IO_ICU1, 2);
+ dsdt_fixed_ioport(IO_ICU2, 2);
+ dsdt_fixed_irq(2);
+ dsdt_unindent(2);
+ dsdt_line(" })");
+ dsdt_line("}");
dsdt_unindent(1);
dsdt_line("}");
diff --git a/usr.sbin/bhyve/pit_8254.c b/usr.sbin/bhyve/pit_8254.c
index 26fb03d..b45b100 100644
--- a/usr.sbin/bhyve/pit_8254.c
+++ b/usr.sbin/bhyve/pit_8254.c
@@ -107,7 +107,7 @@ pit_mevent_cb(int fd, enum ev_type type, void *param)
pit_mev_count++;
- vm_ioapic_pulse_irq(c->ctx, 2);
+ vm_isa_pulse_irq(c->ctx, 0, 2);
/*
* Delete the timer for one-shots
OpenPOWER on IntegriCloud