summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2014-07-19 22:06:46 +0000
committerjhb <jhb@FreeBSD.org>2014-07-19 22:06:46 +0000
commit3da9c304ee7b72e7136f1708976a950b3b0a9d41 (patch)
tree50c938e6aaf17b42cd20cf1cf4b8e2204a814064
parentba55949ac368dc3605b73d26161b12730d968366 (diff)
downloadFreeBSD-src-3da9c304ee7b72e7136f1708976a950b3b0a9d41.zip
FreeBSD-src-3da9c304ee7b72e7136f1708976a950b3b0a9d41.tar.gz
MFC 259942,262274,263035,263054,263211,263744,264179,264324,264468,264631,
264648,264650,264651,266572,267558: Flesh out the AT PIC and 8254 PIT emulations and move them into the kernel.
-rw-r--r--lib/libvmmapi/vmmapi.c35
-rw-r--r--lib/libvmmapi/vmmapi.h3
-rw-r--r--sys/amd64/include/vmm.h5
-rw-r--r--sys/amd64/include/vmm_dev.h16
-rw-r--r--sys/amd64/vmm/intel/vmx.c83
-rw-r--r--sys/amd64/vmm/io/vatpic.c697
-rw-r--r--sys/amd64/vmm/io/vatpic.h56
-rw-r--r--sys/amd64/vmm/io/vatpit.c458
-rw-r--r--sys/amd64/vmm/io/vatpit.h (renamed from usr.sbin/bhyve/pit_8254.h)26
-rw-r--r--sys/amd64/vmm/io/vhpet.c35
-rw-r--r--sys/amd64/vmm/io/vlapic.c34
-rw-r--r--sys/amd64/vmm/vmm.c68
-rw-r--r--sys/amd64/vmm/vmm_dev.c23
-rw-r--r--sys/amd64/vmm/vmm_ioport.c107
-rw-r--r--sys/amd64/vmm/vmm_ioport.h (renamed from usr.sbin/bhyve/elcr.c)48
-rw-r--r--sys/modules/vmm/Makefile3
-rw-r--r--usr.sbin/bhyve/Makefile3
-rw-r--r--usr.sbin/bhyve/atpic.c89
-rw-r--r--usr.sbin/bhyve/inout.c27
-rw-r--r--usr.sbin/bhyve/pci_lpc.c40
-rw-r--r--usr.sbin/bhyve/pit_8254.c291
-rw-r--r--usr.sbin/bhyve/pm.c4
22 files changed, 1695 insertions, 456 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..f8921d3 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_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_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..d50e7bc 100644
--- a/sys/amd64/include/vmm.h
+++ b/sys/amd64/include/vmm.h
@@ -117,6 +117,9 @@ int vm_run(struct vm *vm, struct vm_run *vmrun);
int vm_inject_nmi(struct vm *vm, int vcpu);
int vm_nmi_pending(struct vm *vm, int vcpuid);
void vm_nmi_clear(struct vm *vm, int vcpuid);
+int vm_inject_extint(struct vm *vm, int vcpu);
+int vm_extint_pending(struct vm *vm, int vcpuid);
+void vm_extint_clear(struct vm *vm, int vcpuid);
uint64_t *vm_guest_msrs(struct vm *vm, int cpu);
struct vlapic *vm_lapic(struct vm *vm, int cpu);
struct vioapic *vm_ioapic(struct vm *vm);
@@ -187,6 +190,8 @@ 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);
+struct vatpit *vm_atpit(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 54efe3d..2da0ab7 100644
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -52,10 +52,12 @@ __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"
#include "vmm_stat.h"
+#include "vatpic.h"
#include "vlapic.h"
#include "vlapic_priv.h"
@@ -1046,6 +1048,7 @@ vmx_set_pcpu_defaults(struct vmx *vmx, int vcpu, pmap_t pmap)
invvpid_desc._res1 = 0;
invvpid_desc._res2 = 0;
invvpid_desc.vpid = vmxstate->vpid;
+ invvpid_desc.linear_addr = 0;
invvpid(INVVPID_TYPE_SINGLE_CONTEXT, invvpid_desc);
} else {
/*
@@ -1143,7 +1146,7 @@ static void
vmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic)
{
struct vm_exception exc;
- int vector, need_nmi_exiting;
+ int vector, need_nmi_exiting, extint_pending;
uint64_t rflags;
uint32_t gi, info;
@@ -1195,7 +1198,9 @@ vmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic)
vmx_set_nmi_window_exiting(vmx, vcpu);
}
- if (virtual_interrupt_delivery) {
+ extint_pending = vm_extint_pending(vmx->vm, vcpu);
+
+ if (!extint_pending && virtual_interrupt_delivery) {
vmx_inject_pir(vlapic);
return;
}
@@ -1211,11 +1216,32 @@ vmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic)
return;
}
- /* Ask the local apic for a vector to inject */
- if (!vlapic_pending_intr(vlapic, &vector))
- return;
+ if (!extint_pending) {
+ /* Ask the local apic for a vector to inject */
+ if (!vlapic_pending_intr(vlapic, &vector))
+ return;
- KASSERT(vector >= 32 && vector <= 255, ("invalid vector %d", vector));
+ /*
+ * From the Intel SDM, Volume 3, Section "Maskable
+ * Hardware Interrupts":
+ * - maskable interrupt vectors [16,255] can be delivered
+ * through the local APIC.
+ */
+ KASSERT(vector >= 16 && vector <= 255,
+ ("invalid vector %d from local APIC", vector));
+ } else {
+ /* Ask the legacy pic for a vector to inject */
+ vatpic_pending_intr(vmx->vm, &vector);
+
+ /*
+ * From the Intel SDM, Volume 3, Section "Maskable
+ * Hardware Interrupts":
+ * - maskable interrupt vectors [0,255] can be delivered
+ * through the INTR pin.
+ */
+ KASSERT(vector >= 0 && vector <= 255,
+ ("invalid vector %d from INTR", vector));
+ }
/* Check RFLAGS.IF and the interruptibility state of the guest */
rflags = vmcs_read(VMCS_GUEST_RFLAGS);
@@ -1251,8 +1277,22 @@ vmx_inject_interrupts(struct vmx *vmx, int vcpu, struct vlapic *vlapic)
info |= vector;
vmcs_write(VMCS_ENTRY_INTR_INFO, info);
- /* Update the Local APIC ISR */
- vlapic_intr_accepted(vlapic, vector);
+ if (!extint_pending) {
+ /* Update the Local APIC ISR */
+ vlapic_intr_accepted(vlapic, vector);
+ } else {
+ vm_extint_clear(vmx->vm, vcpu);
+ vatpic_intr_accepted(vmx->vm, vector);
+
+ /*
+ * After we accepted the current ExtINT the PIC may
+ * have posted another one. If that is the case, set
+ * the Interrupt Window Exiting execution control so
+ * we can inject that one too.
+ */
+ if (vm_extint_pending(vmx->vm, vcpu))
+ vmx_set_int_window_exiting(vmx, vcpu);
+ }
VCPU_CTR1(vmx->vm, vcpu, "Injecting hwintr at vector %d", vector);
@@ -1388,6 +1428,7 @@ vmx_emulate_cr_access(struct vmx *vmx, int vcpu, uint64_t exitqual)
if (cr != 0 && cr != 4)
return (UNHANDLED);
+ regval = 0; /* silence gcc */
vmxctx = &vmx->ctx[vcpu];
/*
@@ -1882,6 +1923,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);
@@ -2719,7 +2765,7 @@ vmx_inject_pir(struct vlapic *vlapic)
struct pir_desc *pir_desc;
struct LAPIC *lapic;
uint64_t val, pirval;
- int rvi, pirbase;
+ int rvi, pirbase = -1;
uint16_t intr_status_old, intr_status_new;
vlapic_vtx = (struct vlapic_vtx *)vlapic;
@@ -2731,6 +2777,7 @@ vmx_inject_pir(struct vlapic *vlapic)
}
pirval = 0;
+ pirbase = -1;
lapic = vlapic->apic_page;
val = atomic_readandclear_long(&pir_desc->pir[0]);
@@ -2764,11 +2811,29 @@ vmx_inject_pir(struct vlapic *vlapic)
pirbase = 192;
pirval = val;
}
+
VLAPIC_CTR_IRR(vlapic, "vmx_inject_pir");
/*
* Update RVI so the processor can evaluate pending virtual
* interrupts on VM-entry.
+ *
+ * It is possible for pirval to be 0 here, even though the
+ * pending bit has been set. The scenario is:
+ * CPU-Y is sending a posted interrupt to CPU-X, which
+ * is running a guest and processing posted interrupts in h/w.
+ * CPU-X will eventually exit and the state seen in s/w is
+ * the pending bit set, but no PIR bits set.
+ *
+ * CPU-X CPU-Y
+ * (vm running) (host running)
+ * rx posted interrupt
+ * CLEAR pending bit
+ * SET PIR bit
+ * READ/CLEAR PIR bits
+ * SET pending bit
+ * (vm exit)
+ * pending bit set, PIR 0
*/
if (pirval != 0) {
rvi = pirbase + flsl(pirval) - 1;
diff --git a/sys/amd64/vmm/io/vatpic.c b/sys/amd64/vmm/io/vatpic.c
new file mode 100644
index 0000000..1b9e121
--- /dev/null
+++ b/sys/amd64/vmm/io/vatpic.c
@@ -0,0 +1,697 @@
+/*-
+ * 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;
+ bool sfn; /* special fully-nested mode */
+
+ 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 */
+
+ bool intr_raised;
+};
+
+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 void vatpic_set_pinstate(struct vatpic *vatpic, int pin, bool newstate);
+
+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 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 (serviced & 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"));
+
+ /*
+ * 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);
+
+ /*
+ * 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);
+ }
+
+ /*
+ * 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);
+
+ /*
+ * PIC interrupts are routed to both the Local APIC
+ * and the I/O APIC to support operation in 1 of 3
+ * modes.
+ *
+ * 1. Legacy PIC Mode: the PIC effectively bypasses
+ * all APIC components. In mode '1' the local APIC is
+ * disabled and LINT0 is reconfigured as INTR to
+ * deliver the PIC interrupt directly to the CPU.
+ *
+ * 2. Virtual Wire Mode: the APIC is treated as a
+ * virtual wire which delivers interrupts from the PIC
+ * to the CPU. In mode '2' LINT0 is programmed as
+ * ExtINT to indicate that the PIC is the source of
+ * the interrupt.
+ *
+ * 3. Symmetric I/O Mode: PIC interrupts are fielded
+ * by the I/O APIC and delivered to the appropriate
+ * CPU. In mode '3' the I/O APIC input 0 is
+ * 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);
+ } else {
+ VATPIC_CTR3(vatpic, "atpic master 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));
+}
+
+void
+vatpic_pending_intr(struct vm *vm, int *vecptr)
+{
+ struct vatpic *vatpic;
+ struct atpic *atpic;
+ int pin;
+
+ vatpic = vm_atpic(vm);
+
+ atpic = &vatpic->atpic[0];
+
+ VATPIC_LOCK(vatpic);
+
+ 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;
+ int pin;
+
+ vatpic = vm_atpic(vm);
+
+ VATPIC_LOCK(vatpic);
+
+ pin = vector & 0x7;
+
+ 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 {
+ vatpic_pin_accepted(&vatpic->atpic[0], pin);
+ }
+
+ vatpic_notify_intr(vatpic);
+
+ VATPIC_UNLOCK(vatpic);
+}
+
+static int
+vatpic_read(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
+ int bytes, uint32_t *eax)
+{
+ VATPIC_LOCK(vatpic);
+
+ if (atpic->poll) {
+ VATPIC_CTR0(vatpic, "vatpic polled mode not supported");
+ VATPIC_UNLOCK(vatpic);
+ return (-1);
+ } else {
+ if (port & ICU_IMR_OFFSET) {
+ /* read interrrupt mask register */
+ *eax = atpic->mask;
+ } else {
+ if (atpic->rd_cmd_reg == OCW3_RIS) {
+ /* read interrupt service register */
+ *eax = atpic->service;
+ } else {
+ /* read interrupt request register */
+ *eax = atpic->request;
+ }
+ }
+ }
+
+ VATPIC_UNLOCK(vatpic);
+
+ return (0);
+
+}
+
+static int
+vatpic_write(struct vatpic *vatpic, struct atpic *atpic, bool in, int port,
+ int bytes, uint32_t *eax)
+{
+ int error;
+ uint8_t val;
+
+ error = 0;
+ val = *eax;
+
+ VATPIC_LOCK(vatpic);
+
+ if (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_master_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *eax)
+{
+ struct vatpic *vatpic;
+ struct atpic *atpic;
+
+ vatpic = vm_atpic(vm);
+ atpic = &vatpic->atpic[0];
+
+ if (bytes != 1)
+ return (-1);
+
+ if (in) {
+ return (vatpic_read(vatpic, atpic, in, port, bytes, eax));
+ }
+
+ return (vatpic_write(vatpic, atpic, in, port, bytes, eax));
+}
+
+int
+vatpic_slave_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *eax)
+{
+ struct vatpic *vatpic;
+ struct atpic *atpic;
+
+ vatpic = vm_atpic(vm);
+ atpic = &vatpic->atpic[1];
+
+ if (bytes != 1)
+ return (-1);
+
+ if (in) {
+ return (vatpic_read(vatpic, atpic, in, port, bytes, eax));
+ }
+
+ return (vatpic_write(vatpic, atpic, in, port, bytes, eax));
+}
+
+int
+vatpic_elc_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *eax)
+{
+ struct vatpic *vatpic;
+ bool is_master;
+
+ vatpic = vm_atpic(vm);
+ is_master = (port == IO_ELCR1);
+
+ if (bytes != 1)
+ return (-1);
+
+ VATPIC_LOCK(vatpic);
+
+ if (in) {
+ if (is_master)
+ *eax = vatpic->elc[0];
+ else
+ *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] = (*eax & 0xf8);
+ else
+ vatpic->elc[1] = (*eax & 0xde);
+ }
+
+ VATPIC_UNLOCK(vatpic);
+
+ 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..d4d6b26c
--- /dev/null
+++ b/sys/amd64/vmm/io/vatpic.h
@@ -0,0 +1,56 @@
+/*-
+ * 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, bool in, int port, int bytes,
+ uint32_t *eax);
+int vatpic_slave_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *eax);
+int vatpic_elc_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *eax);
+
+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);
+
+void 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/vatpit.c b/sys/amd64/vmm/io/vatpit.c
new file mode 100644
index 0000000..9132bae
--- /dev/null
+++ b/sys/amd64/vmm/io/vatpit.c
@@ -0,0 +1,458 @@
+/*-
+ * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
+ * 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.
+ */
+
+#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 <machine/vmm.h>
+
+#include "vmm_ktr.h"
+#include "vatpic.h"
+#include "vioapic.h"
+#include "vatpit.h"
+
+static MALLOC_DEFINE(M_VATPIT, "atpit", "bhyve virtual atpit (8254)");
+
+#define VATPIT_LOCK(vatpit) mtx_lock_spin(&((vatpit)->mtx))
+#define VATPIT_UNLOCK(vatpit) mtx_unlock_spin(&((vatpit)->mtx))
+#define VATPIT_LOCKED(vatpit) mtx_owned(&((vatpit)->mtx))
+
+#define TIMER_SEL_MASK 0xc0
+#define TIMER_RW_MASK 0x30
+#define TIMER_MODE_MASK 0x0f
+#define TIMER_SEL_READBACK 0xc0
+
+#define TIMER_STS_OUT 0x80
+#define TIMER_STS_NULLCNT 0x40
+
+#define TIMER_RB_LCTR 0x20
+#define TIMER_RB_LSTATUS 0x10
+#define TIMER_RB_CTR_2 0x08
+#define TIMER_RB_CTR_1 0x04
+#define TIMER_RB_CTR_0 0x02
+
+#define TMR2_OUT_STS 0x20
+
+#define PIT_8254_FREQ 1193182
+#define TIMER_DIV(freq, hz) (((freq) + (hz) / 2) / (hz))
+
+struct vatpit_callout_arg {
+ struct vatpit *vatpit;
+ int channel_num;
+};
+
+
+struct channel {
+ int mode;
+ uint16_t initial; /* initial counter value */
+ sbintime_t now_sbt; /* uptime when counter was loaded */
+ uint8_t cr[2];
+ uint8_t ol[2];
+ bool slatched; /* status latched */
+ uint8_t status;
+ int crbyte;
+ int olbyte;
+ int frbyte;
+ struct callout callout;
+ sbintime_t callout_sbt; /* target time */
+ struct vatpit_callout_arg callout_arg;
+};
+
+struct vatpit {
+ struct vm *vm;
+ struct mtx mtx;
+
+ sbintime_t freq_sbt;
+
+ struct channel channel[3];
+};
+
+static void pit_timer_start_cntr0(struct vatpit *vatpit);
+
+static int
+vatpit_get_out(struct vatpit *vatpit, int channel)
+{
+ struct channel *c;
+ sbintime_t delta_ticks;
+ int out;
+
+ c = &vatpit->channel[channel];
+
+ switch (c->mode) {
+ case TIMER_INTTC:
+ delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt;
+ out = ((c->initial - delta_ticks) <= 0);
+ break;
+ default:
+ out = 0;
+ break;
+ }
+
+ return (out);
+}
+
+static void
+vatpit_callout_handler(void *a)
+{
+ struct vatpit_callout_arg *arg = a;
+ struct vatpit *vatpit;
+ struct callout *callout;
+ struct channel *c;
+
+ vatpit = arg->vatpit;
+ c = &vatpit->channel[arg->channel_num];
+ callout = &c->callout;
+
+ VM_CTR1(vatpit->vm, "atpit t%d fired", arg->channel_num);
+
+ VATPIT_LOCK(vatpit);
+
+ if (callout_pending(callout)) /* callout was reset */
+ goto done;
+
+ if (!callout_active(callout)) /* callout was stopped */
+ goto done;
+
+ callout_deactivate(callout);
+
+ if (c->mode == TIMER_RATEGEN) {
+ pit_timer_start_cntr0(vatpit);
+ }
+
+ vatpic_pulse_irq(vatpit->vm, 0);
+ vioapic_pulse_irq(vatpit->vm, 2);
+
+done:
+ VATPIT_UNLOCK(vatpit);
+ return;
+}
+
+static void
+pit_timer_start_cntr0(struct vatpit *vatpit)
+{
+ struct channel *c;
+ sbintime_t now, delta, precision;
+
+ c = &vatpit->channel[0];
+ if (c->initial != 0) {
+ delta = c->initial * vatpit->freq_sbt;
+ precision = delta >> tc_precexp;
+ c->callout_sbt = c->callout_sbt + delta;
+
+ /*
+ * Reset 'callout_sbt' if the time that the callout
+ * was supposed to fire is more than 'c->initial'
+ * ticks in the past.
+ */
+ now = sbinuptime();
+ if (c->callout_sbt < now)
+ c->callout_sbt = now + delta;
+
+ callout_reset_sbt(&c->callout, c->callout_sbt,
+ precision, vatpit_callout_handler, &c->callout_arg,
+ C_ABSOLUTE);
+ }
+}
+
+static uint16_t
+pit_update_counter(struct vatpit *vatpit, struct channel *c, bool latch)
+{
+ uint16_t lval;
+ sbintime_t delta_ticks;
+
+ /* cannot latch a new value until the old one has been consumed */
+ if (latch && c->olbyte != 0)
+ return (0);
+
+ if (c->initial == 0) {
+ /*
+ * This is possibly an o/s bug - reading the value of
+ * the timer without having set up the initial value.
+ *
+ * The original user-space version of this code set
+ * the timer to 100hz in this condition; do the same
+ * here.
+ */
+ c->initial = TIMER_DIV(PIT_8254_FREQ, 100);
+ c->now_sbt = sbinuptime();
+ c->status &= ~TIMER_STS_NULLCNT;
+ }
+
+ delta_ticks = (sbinuptime() - c->now_sbt) / vatpit->freq_sbt;
+
+ lval = c->initial - delta_ticks % c->initial;
+
+ if (latch) {
+ c->olbyte = 2;
+ c->ol[1] = lval; /* LSB */
+ c->ol[0] = lval >> 8; /* MSB */
+ }
+
+ return (lval);
+}
+
+static int
+pit_readback1(struct vatpit *vatpit, int channel, uint8_t cmd)
+{
+ struct channel *c;
+
+ c = &vatpit->channel[channel];
+
+ /*
+ * Latch the count/status of the timer if not already latched.
+ * N.B. that the count/status latch-select bits are active-low.
+ */
+ if (!(cmd & TIMER_RB_LCTR) && !c->olbyte) {
+ (void) pit_update_counter(vatpit, c, true);
+ }
+
+ if (!(cmd & TIMER_RB_LSTATUS) && !c->slatched) {
+ c->slatched = true;
+ /*
+ * For mode 0, see if the elapsed time is greater
+ * than the initial value - this results in the
+ * output pin being set to 1 in the status byte.
+ */
+ if (c->mode == TIMER_INTTC && vatpit_get_out(vatpit, channel))
+ c->status |= TIMER_STS_OUT;
+ else
+ c->status &= ~TIMER_STS_OUT;
+ }
+
+ return (0);
+}
+
+static int
+pit_readback(struct vatpit *vatpit, uint8_t cmd)
+{
+ int error;
+
+ /*
+ * The readback command can apply to all timers.
+ */
+ error = 0;
+ if (cmd & TIMER_RB_CTR_0)
+ error = pit_readback1(vatpit, 0, cmd);
+ if (!error && cmd & TIMER_RB_CTR_1)
+ error = pit_readback1(vatpit, 1, cmd);
+ if (!error && cmd & TIMER_RB_CTR_2)
+ error = pit_readback1(vatpit, 2, cmd);
+
+ return (error);
+}
+
+
+static int
+vatpit_update_mode(struct vatpit *vatpit, uint8_t val)
+{
+ struct channel *c;
+ int sel, rw, mode;
+
+ sel = val & TIMER_SEL_MASK;
+ rw = val & TIMER_RW_MASK;
+ mode = val & TIMER_MODE_MASK;
+
+ if (sel == TIMER_SEL_READBACK)
+ return (pit_readback(vatpit, val));
+
+ if (rw != TIMER_LATCH && rw != TIMER_16BIT)
+ return (-1);
+
+ if (rw != TIMER_LATCH) {
+ /*
+ * Counter mode is not affected when issuing a
+ * latch command.
+ */
+ if (mode != TIMER_INTTC &&
+ mode != TIMER_RATEGEN &&
+ mode != TIMER_SQWAVE &&
+ mode != TIMER_SWSTROBE)
+ return (-1);
+ }
+
+ c = &vatpit->channel[sel >> 6];
+ if (rw == TIMER_LATCH)
+ pit_update_counter(vatpit, c, true);
+ else {
+ c->mode = mode;
+ c->olbyte = 0; /* reset latch after reprogramming */
+ c->status |= TIMER_STS_NULLCNT;
+ }
+
+ return (0);
+}
+
+int
+vatpit_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *eax)
+{
+ struct vatpit *vatpit;
+ struct channel *c;
+ uint8_t val;
+ int error;
+
+ vatpit = vm_atpit(vm);
+
+ if (bytes != 1)
+ return (-1);
+
+ val = *eax;
+
+ if (port == TIMER_MODE) {
+ if (in) {
+ VM_CTR0(vatpit->vm, "vatpit attempt to read mode");
+ return (-1);
+ }
+
+ VATPIT_LOCK(vatpit);
+ error = vatpit_update_mode(vatpit, val);
+ VATPIT_UNLOCK(vatpit);
+
+ return (error);
+ }
+
+ /* counter ports */
+ KASSERT(port >= TIMER_CNTR0 && port <= TIMER_CNTR2,
+ ("invalid port 0x%x", port));
+ c = &vatpit->channel[port - TIMER_CNTR0];
+
+ VATPIT_LOCK(vatpit);
+ if (in && c->slatched) {
+ /*
+ * Return the status byte if latched
+ */
+ *eax = c->status;
+ c->slatched = false;
+ c->status = 0;
+ } else if (in) {
+ /*
+ * The spec says that once the output latch is completely
+ * read it should revert to "following" the counter. Use
+ * the free running counter for this case (i.e. Linux
+ * TSC calibration). Assuming the access mode is 16-bit,
+ * toggle the MSB/LSB bit on each read.
+ */
+ if (c->olbyte == 0) {
+ uint16_t tmp;
+
+ tmp = pit_update_counter(vatpit, c, false);
+ if (c->frbyte)
+ tmp >>= 8;
+ tmp &= 0xff;
+ *eax = tmp;
+ c->frbyte ^= 1;
+ } else
+ *eax = c->ol[--c->olbyte];
+ } else {
+ c->cr[c->crbyte++] = *eax;
+ if (c->crbyte == 2) {
+ c->status &= ~TIMER_STS_NULLCNT;
+ c->frbyte = 0;
+ c->crbyte = 0;
+ c->initial = c->cr[0] | (uint16_t)c->cr[1] << 8;
+ c->now_sbt = sbinuptime();
+ /* Start an interval timer for channel 0 */
+ if (port == TIMER_CNTR0) {
+ c->callout_sbt = c->now_sbt;
+ pit_timer_start_cntr0(vatpit);
+ }
+ if (c->initial == 0)
+ c->initial = 0xffff;
+ }
+ }
+ VATPIT_UNLOCK(vatpit);
+
+ return (0);
+}
+
+int
+vatpit_nmisc_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *eax)
+{
+ struct vatpit *vatpit;
+
+ vatpit = vm_atpit(vm);
+
+ if (in) {
+ VATPIT_LOCK(vatpit);
+ if (vatpit_get_out(vatpit, 2))
+ *eax = TMR2_OUT_STS;
+ else
+ *eax = 0;
+
+ VATPIT_UNLOCK(vatpit);
+ }
+
+ return (0);
+}
+
+struct vatpit *
+vatpit_init(struct vm *vm)
+{
+ struct vatpit *vatpit;
+ struct bintime bt;
+ struct vatpit_callout_arg *arg;
+ int i;
+
+ vatpit = malloc(sizeof(struct vatpit), M_VATPIT, M_WAITOK | M_ZERO);
+ vatpit->vm = vm;
+
+ mtx_init(&vatpit->mtx, "vatpit lock", NULL, MTX_SPIN);
+
+ FREQ2BT(PIT_8254_FREQ, &bt);
+ vatpit->freq_sbt = bttosbt(bt);
+
+ for (i = 0; i < 3; i++) {
+ callout_init(&vatpit->channel[i].callout, true);
+ arg = &vatpit->channel[i].callout_arg;
+ arg->vatpit = vatpit;
+ arg->channel_num = i;
+ }
+
+ return (vatpit);
+}
+
+void
+vatpit_cleanup(struct vatpit *vatpit)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ callout_drain(&vatpit->channel[i].callout);
+
+ free(vatpit, M_VATPIT);
+}
diff --git a/usr.sbin/bhyve/pit_8254.h b/sys/amd64/vmm/io/vatpit.h
index 61bd15d..3350455 100644
--- a/usr.sbin/bhyve/pit_8254.h
+++ b/sys/amd64/vmm/io/vatpit.h
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
* Copyright (c) 2011 NetApp, Inc.
* All rights reserved.
*
@@ -26,20 +27,19 @@
* $FreeBSD$
*/
-#ifndef _PIT_8254_H_
-#define _PIT_8254_H_
+#ifndef _VATPIT_H_
+#define _VATPIT_H_
-/*
- * Borrowed from amd64/include/timerreg.h because in that file it is
- * conditionally compiled for #ifdef _KERNEL only.
- */
+#include <machine/timerreg.h>
+
+#define NMISC_PORT 0x61
-#include <dev/ic/i8253reg.h>
+struct vatpit *vatpit_init(struct vm *vm);
+void vatpit_cleanup(struct vatpit *vatpit);
-#define IO_TIMER1 0x40 /* 8253 Timer #1 */
-#define TIMER_CNTR0 (IO_TIMER1 + TIMER_REG_CNTR0)
-#define TIMER_CNTR1 (IO_TIMER1 + TIMER_REG_CNTR1)
-#define TIMER_CNTR2 (IO_TIMER1 + TIMER_REG_CNTR2)
-#define TIMER_MODE (IO_TIMER1 + TIMER_REG_MODE)
+int vatpit_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *eax);
+int vatpit_nmisc_handler(void *vm, int vcpuid, bool in, int port, int bytes,
+ uint32_t *eax);
-#endif /* _PIT_8254_H_ */
+#endif /* _VATPIT_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..2e0a575 100644
--- a/sys/amd64/vmm/io/vlapic.c
+++ b/sys/amd64/vmm/io/vlapic.c
@@ -448,6 +448,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:
+ vm_inject_extint(vlapic->vm, vlapic->vcpuid);
+ break;
default:
// Other modes ignored
return (0);
@@ -651,6 +654,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:
+ vm_inject_extint(vlapic->vm, vlapic->vcpuid);
+ 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);
@@ -1474,11 +1496,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 +1514,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) {
+ vm_inject_extint(vm, vcpuid);
+ } else {
+ lapic_set_intr(vm, vcpuid, vec, level);
+ }
}
}
diff --git a/sys/amd64/vmm/vmm.c b/sys/amd64/vmm/vmm.c
index 353da06..9d740d1 100644
--- a/sys/amd64/vmm/vmm.c
+++ b/sys/amd64/vmm/vmm.c
@@ -67,6 +67,8 @@ __FBSDID("$FreeBSD$");
#include "vmm_host.h"
#include "vmm_mem.h"
#include "vmm_util.h"
+#include "vatpic.h"
+#include "vatpit.h"
#include "vhpet.h"
#include "vioapic.h"
#include "vlapic.h"
@@ -94,6 +96,7 @@ struct vcpu {
struct vm_exit exitinfo;
enum x2apic_state x2apic_state;
int nmi_pending;
+ int extint_pending;
struct vm_exception exception;
int exception_pending;
};
@@ -116,6 +119,8 @@ struct vm {
void *iommu; /* iommu-specific data */
struct vhpet *vhpet; /* virtual HPET */
struct vioapic *vioapic; /* virtual ioapic */
+ struct vatpic *vatpic; /* virtual atpic */
+ struct vatpit *vatpit; /* virtual atpit */
struct vmspace *vmspace; /* guest's address space */
struct vcpu vcpu[VM_MAXCPU];
int num_mem_segs;
@@ -345,6 +350,8 @@ 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);
+ vm->vatpit = vatpit_init(vm);
for (i = 0; i < VM_MAXCPU; i++) {
vcpu_init(vm, i);
@@ -377,7 +384,9 @@ vm_destroy(struct vm *vm)
if (vm->iommu != NULL)
iommu_destroy_domain(vm->iommu);
+ vatpit_cleanup(vm->vatpit);
vhpet_cleanup(vm->vhpet);
+ vatpic_cleanup(vm->vatpic);
vioapic_cleanup(vm->vioapic);
for (i = 0; i < vm->num_mem_segs; i++)
@@ -1360,6 +1369,53 @@ vm_nmi_clear(struct vm *vm, int vcpuid)
vmm_stat_incr(vm, vcpuid, VCPU_NMI_COUNT, 1);
}
+static VMM_STAT(VCPU_EXTINT_COUNT, "number of ExtINTs delivered to vcpu");
+
+int
+vm_inject_extint(struct vm *vm, int vcpuid)
+{
+ struct vcpu *vcpu;
+
+ if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
+ return (EINVAL);
+
+ vcpu = &vm->vcpu[vcpuid];
+
+ vcpu->extint_pending = 1;
+ vcpu_notify_event(vm, vcpuid, false);
+ return (0);
+}
+
+int
+vm_extint_pending(struct vm *vm, int vcpuid)
+{
+ struct vcpu *vcpu;
+
+ if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
+ panic("vm_extint_pending: invalid vcpuid %d", vcpuid);
+
+ vcpu = &vm->vcpu[vcpuid];
+
+ return (vcpu->extint_pending);
+}
+
+void
+vm_extint_clear(struct vm *vm, int vcpuid)
+{
+ struct vcpu *vcpu;
+
+ if (vcpuid < 0 || vcpuid >= VM_MAXCPU)
+ panic("vm_extint_pending: invalid vcpuid %d", vcpuid);
+
+ vcpu = &vm->vcpu[vcpuid];
+
+ if (vcpu->extint_pending == 0)
+ panic("vm_extint_clear: inconsistent extint_pending state");
+
+ vcpu->extint_pending = 0;
+ vmm_stat_incr(vm, vcpuid, VCPU_EXTINT_COUNT, 1);
+}
+
int
vm_get_capability(struct vm *vm, int vcpu, int type, int *retval)
{
@@ -1682,3 +1738,15 @@ restart:
vm_handle_rendezvous(vm, vcpuid);
}
+
+struct vatpic *
+vm_atpic(struct vm *vm)
+{
+ return (vm->vatpic);
+}
+
+struct vatpit *
+vm_atpit(struct vm *vm)
+{
+ return (vm->vatpit);
+}
diff --git a/sys/amd64/vmm/vmm_dev.c b/sys/amd64/vmm/vmm_dev.c
index 6db2b98..6defd13 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;
@@ -169,6 +171,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
if (sc == NULL)
return (ENXIO);
+ error = 0;
vcpu = -1;
state_changed = 0;
@@ -318,6 +321,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/sys/amd64/vmm/vmm_ioport.c b/sys/amd64/vmm/vmm_ioport.c
new file mode 100644
index 0000000..ed17e40
--- /dev/null
+++ b/sys/amd64/vmm/vmm_ioport.c
@@ -0,0 +1,107 @@
+/*-
+ * 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/systm.h>
+
+#include <machine/vmm.h>
+
+#include "vatpic.h"
+#include "vatpit.h"
+#include "vmm_ioport.h"
+
+#define MAX_IOPORTS 1280
+
+ioport_handler_func_t ioport_handler[MAX_IOPORTS] = {
+ [TIMER_MODE] = vatpit_handler,
+ [TIMER_CNTR0] = vatpit_handler,
+ [TIMER_CNTR1] = vatpit_handler,
+ [TIMER_CNTR2] = vatpit_handler,
+ [NMISC_PORT] = vatpit_nmisc_handler,
+ [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)
+{
+ ioport_handler_func_t handler;
+ uint32_t mask, val;
+ int error;
+
+ if (vmexit->u.inout.port >= MAX_IOPORTS)
+ return (-1);
+
+ handler = ioport_handler[vmexit->u.inout.port];
+ if (handler == NULL)
+ return (-1);
+
+ if (!vmexit->u.inout.in) {
+ switch (vmexit->u.inout.bytes) {
+ case 1:
+ mask = 0xff;
+ break;
+ case 2:
+ mask = 0xffff;
+ break;
+ default:
+ mask = 0xffffffff;
+ break;
+ }
+ val = vmexit->u.inout.eax & mask;
+ }
+
+ error = (*handler)(vm, vcpuid, vmexit->u.inout.in,
+ vmexit->u.inout.port, vmexit->u.inout.bytes, &val);
+
+ if (!error && vmexit->u.inout.in) {
+ switch (vmexit->u.inout.bytes) {
+ case 1:
+ mask = 0xff;
+ break;
+ case 2:
+ mask = 0xffff;
+ break;
+ default:
+ mask = 0xffffffff;
+ break;
+ }
+ vmexit->u.inout.eax &= ~mask;
+ vmexit->u.inout.eax |= val & mask;
+ }
+
+ return (error);
+}
diff --git a/usr.sbin/bhyve/elcr.c b/sys/amd64/vmm/vmm_ioport.h
index 190b5c6..02e543a 100644
--- a/usr.sbin/bhyve/elcr.c
+++ b/sys/amd64/vmm/vmm_ioport.h
@@ -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)
@@ -26,42 +26,12 @@
* $FreeBSD$
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+#ifndef _VMM_IOPORT_H_
+#define _VMM_IOPORT_H_
-#include <sys/types.h>
+typedef int (*ioport_handler_func_t)(void *vm, int vcpuid,
+ bool in, int port, int bytes, uint32_t *val);
-#include "inout.h"
-#include "pci_lpc.h"
+int emulate_ioport(struct vm *vm, int vcpuid, struct vm_exit *vmexit);
-/*
- * 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
-
-static uint8_t elcr[2] = { 0x00, 0x00 };
-
-static int
-elcr_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
- uint32_t *eax, void *arg)
-{
- int idx;
-
- if (bytes != 1)
- return (-1);
-
- idx = port - ELCR_PORT;
-
- if (in)
- *eax = elcr[idx];
- else
- elcr[idx] = *eax;
-
- return (0);
-}
-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);
+#endif /* _VMM_IOPORT_H_ */
diff --git a/sys/modules/vmm/Makefile b/sys/modules/vmm/Makefile
index ea367a4..76f9364 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,8 @@ SRCS+= vmm.c \
.PATH: ${.CURDIR}/../../amd64/vmm/io
SRCS+= iommu.c \
ppt.c \
+ vatpic.c \
+ vatpit.c \
vhpet.c \
vioapic.c \
vlapic.c
diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
index e8bf793..116fb60 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 \
@@ -29,7 +27,6 @@ SRCS= \
pci_virtio_block.c \
pci_virtio_net.c \
pci_uart.c \
- pit_8254.c \
pm.c \
pmtmr.c \
post.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/inout.c b/usr.sbin/bhyve/inout.c
index a200265..9fec70a 100644
--- a/usr.sbin/bhyve/inout.c
+++ b/usr.sbin/bhyve/inout.c
@@ -95,9 +95,10 @@ emulate_inout(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
uint32_t *eax, int strict)
{
int flags;
- uint32_t mask;
+ uint32_t mask, val;
inout_func_t handler;
void *arg;
+ int error;
assert(port < MAX_IOPORTS);
@@ -118,16 +119,34 @@ emulate_inout(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
mask = 0xffffffff;
break;
}
- *eax = *eax & mask;
+ val = *eax & mask;
}
flags = inout_handlers[port].flags;
arg = inout_handlers[port].arg;
if ((in && (flags & IOPORT_F_IN)) || (!in && (flags & IOPORT_F_OUT)))
- return ((*handler)(ctx, vcpu, in, port, bytes, eax, arg));
+ error = (*handler)(ctx, vcpu, in, port, bytes, &val, arg);
else
- return (-1);
+ error = -1;
+
+ if (!error && in) {
+ switch (bytes) {
+ case 1:
+ mask = 0xff;
+ break;
+ case 2:
+ mask = 0xffff;
+ break;
+ default:
+ mask = 0xffffffff;
+ break;
+ }
+ *eax &= ~mask;
+ *eax |= val & mask;
+ }
+
+ return (error);
}
void
diff --git a/usr.sbin/bhyve/pci_lpc.c b/usr.sbin/bhyve/pci_lpc.c
index 30b0401..5b1b4a8 100644
--- a/usr.sbin/bhyve/pci_lpc.c
+++ b/usr.sbin/bhyve/pci_lpc.c
@@ -46,9 +46,20 @@ __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);
+
+#define IO_TIMER1_PORT 0x40
+
+#define NMISC_PORT 0x61
+SYSRES_IO(NMISC_PORT, 1);
+
static struct pci_devinst *lpc_bridge;
#define LPC_UART_NUM 2
@@ -100,7 +111,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 +203,33 @@ 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_line("");
+ dsdt_line("Device (TIMR)");
+ dsdt_line("{");
+ dsdt_line(" Name (_HID, EisaId (\"PNP0100\"))");
+ dsdt_line(" Name (_CRS, ResourceTemplate ()");
+ dsdt_line(" {");
+ dsdt_indent(2);
+ dsdt_fixed_ioport(IO_TIMER1_PORT, 4);
+ dsdt_fixed_irq(0);
+ 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
deleted file mode 100644
index 3eb1aa7..0000000
--- a/usr.sbin/bhyve/pit_8254.c
+++ /dev/null
@@ -1,291 +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/types.h>
-#include <sys/time.h>
-#include <machine/vmm.h>
-
-#include <machine/clock.h>
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <vmmapi.h>
-
-#include "acpi.h"
-#include "bhyverun.h"
-#include "inout.h"
-#include "mevent.h"
-#include "pci_lpc.h"
-#include "pit_8254.h"
-
-#define TIMER_SEL_MASK 0xc0
-#define TIMER_RW_MASK 0x30
-#define TIMER_MODE_MASK 0x0f
-#define TIMER_SEL_READBACK 0xc0
-
-#define TIMER_DIV(freq, hz) (((freq) + (hz) / 2) / (hz))
-
-#define PIT_8254_FREQ 1193182
-static const int nsecs_per_tick = 1000000000 / PIT_8254_FREQ;
-
-struct counter {
- struct vmctx *ctx;
- struct mevent *tevp;
- struct timeval tv; /* uptime when counter was loaded */
- int mode;
- uint16_t initial; /* initial counter value */
- uint8_t cr[2];
- uint8_t ol[2];
- int crbyte;
- int olbyte;
- int frbyte;
-};
-
-
-static void
-timevalfix(struct timeval *t1)
-{
-
- if (t1->tv_usec < 0) {
- t1->tv_sec--;
- t1->tv_usec += 1000000;
- }
- if (t1->tv_usec >= 1000000) {
- t1->tv_sec++;
- t1->tv_usec -= 1000000;
- }
-}
-
-static void
-timevalsub(struct timeval *t1, const struct timeval *t2)
-{
-
- t1->tv_sec -= t2->tv_sec;
- t1->tv_usec -= t2->tv_usec;
- timevalfix(t1);
-}
-
-static uint64_t pit_mev_count;
-
-static void
-pit_mevent_cb(int fd, enum ev_type type, void *param)
-{
- struct counter *c;
-
- c = param;
-
- pit_mev_count++;
-
- vm_ioapic_pulse_irq(c->ctx, 2);
-
- /*
- * Delete the timer for one-shots
- */
- if (c->mode != TIMER_RATEGEN) {
- mevent_delete(c->tevp);
- c->tevp = NULL;
- }
-}
-
-static void
-pit_timer_start(struct vmctx *ctx, struct counter *c)
-{
- int msecs;
-
- if (c->initial != 0) {
- msecs = c->initial * nsecs_per_tick / 1000000;
- if (msecs == 0)
- msecs = 1;
-
- if (c->tevp == NULL)
- c->tevp = mevent_add(msecs, EVF_TIMER, pit_mevent_cb,
- c);
- }
-}
-
-static uint16_t
-pit_update_counter(struct counter *c, int latch)
-{
- struct timeval tv2;
- uint16_t lval;
- uint64_t delta_nsecs, delta_ticks;
-
- /* cannot latch a new value until the old one has been consumed */
- if (latch && c->olbyte != 0)
- return (0);
-
- if (c->initial == 0 || c->initial == 1) {
- /*
- * XXX the program that runs the VM can be stopped and
- * restarted at any time. This means that state that was
- * created by the guest is destroyed between invocations
- * of the program.
- *
- * If the counter's initial value is not programmed we
- * assume a value that would be set to generate 100
- * interrupts per second.
- */
- c->initial = TIMER_DIV(PIT_8254_FREQ, 100);
- gettimeofday(&c->tv, NULL);
- }
-
- (void)gettimeofday(&tv2, NULL);
- timevalsub(&tv2, &c->tv);
- delta_nsecs = tv2.tv_sec * 1000000000 + tv2.tv_usec * 1000;
- delta_ticks = delta_nsecs / nsecs_per_tick;
-
- lval = c->initial - delta_ticks % c->initial;
-
- if (latch) {
- c->olbyte = 2;
- c->ol[1] = lval; /* LSB */
- c->ol[0] = lval >> 8; /* MSB */
- }
-
- return (lval);
-}
-
-static int
-pit_8254_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
- uint32_t *eax, void *arg)
-{
- int sel, rw, mode;
- uint8_t val;
- struct counter *c;
-
- static struct counter counter[3];
-
- if (bytes != 1)
- return (-1);
-
- val = *eax;
-
- if (port == TIMER_MODE) {
- assert(in == 0);
- sel = val & TIMER_SEL_MASK;
- rw = val & TIMER_RW_MASK;
- mode = val & TIMER_MODE_MASK;
-
- if (sel == TIMER_SEL_READBACK)
- return (-1);
- if (rw != TIMER_LATCH && rw != TIMER_16BIT)
- return (-1);
-
- if (rw != TIMER_LATCH) {
- /*
- * Counter mode is not affected when issuing a
- * latch command.
- */
- if (mode != TIMER_INTTC &&
- mode != TIMER_RATEGEN &&
- mode != TIMER_SQWAVE &&
- mode != TIMER_SWSTROBE)
- return (-1);
- }
-
- c = &counter[sel >> 6];
- c->ctx = ctx;
- c->mode = mode;
- if (rw == TIMER_LATCH)
- pit_update_counter(c, 1);
- else
- c->olbyte = 0; /* reset latch after reprogramming */
-
- return (0);
- }
-
- /* counter ports */
- assert(port >= TIMER_CNTR0 && port <= TIMER_CNTR2);
- c = &counter[port - TIMER_CNTR0];
-
- if (in) {
- /*
- * The spec says that once the output latch is completely
- * read it should revert to "following" the counter. Use
- * the free running counter for this case (i.e. Linux
- * TSC calibration). Assuming the access mode is 16-bit,
- * toggle the MSB/LSB bit on each read.
- */
- if (c->olbyte == 0) {
- uint16_t tmp;
-
- tmp = pit_update_counter(c, 0);
- if (c->frbyte)
- tmp >>= 8;
- tmp &= 0xff;
- *eax = tmp;
- c->frbyte ^= 1;
- } else
- *eax = c->ol[--c->olbyte];
- } else {
- c->cr[c->crbyte++] = *eax;
- if (c->crbyte == 2) {
- c->frbyte = 0;
- c->crbyte = 0;
- c->initial = c->cr[0] | (uint16_t)c->cr[1] << 8;
- /* Start an interval timer for counter 0 */
- if (port == 0x40)
- pit_timer_start(ctx, c);
- if (c->initial == 0)
- c->initial = 0xffff;
- gettimeofday(&c->tv, NULL);
- }
- }
-
- return (0);
-}
-
-INOUT_PORT(8254, TIMER_MODE, IOPORT_F_OUT, pit_8254_handler);
-INOUT_PORT(8254, TIMER_CNTR0, IOPORT_F_INOUT, pit_8254_handler);
-INOUT_PORT(8254, TIMER_CNTR1, IOPORT_F_INOUT, pit_8254_handler);
-INOUT_PORT(8254, TIMER_CNTR2, IOPORT_F_INOUT, pit_8254_handler);
-
-static void
-pit_dsdt(void)
-{
-
- dsdt_line("");
- dsdt_line("Device (TIMR)");
- dsdt_line("{");
- dsdt_line(" Name (_HID, EisaId (\"PNP0100\"))");
- dsdt_line(" Name (_CRS, ResourceTemplate ()");
- dsdt_line(" {");
- dsdt_indent(2);
- dsdt_fixed_ioport(IO_TIMER1, 4);
- dsdt_fixed_irq(0);
- dsdt_unindent(2);
- dsdt_line(" })");
- dsdt_line("}");
-}
-LPC_DSDT(pit_dsdt);
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