Move the ioapic device model from userspace into vmm.ko. This is needed for
upcoming in-kernel device emulations like the HPET. The ioctls VM_IOAPIC_ASSERT_IRQ and VM_IOAPIC_DEASSERT_IRQ are used to manipulate the ioapic pin state. Discussed with: grehan@ Submitted by: Tycho Nightingale (tycho.nightingale@pluribusnetworks.com)
This commit is contained in:
@@ -396,6 +396,28 @@ vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector)
|
||||
return (ioctl(ctx->fd, VM_LAPIC_IRQ, &vmirq));
|
||||
}
|
||||
|
||||
int
|
||||
vm_ioapic_assert_irq(struct vmctx *ctx, int irq)
|
||||
{
|
||||
struct vm_ioapic_irq ioapic_irq;
|
||||
|
||||
bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq));
|
||||
ioapic_irq.irq = irq;
|
||||
|
||||
return (ioctl(ctx->fd, VM_IOAPIC_ASSERT_IRQ, &ioapic_irq));
|
||||
}
|
||||
|
||||
int
|
||||
vm_ioapic_deassert_irq(struct vmctx *ctx, int irq)
|
||||
{
|
||||
struct vm_ioapic_irq ioapic_irq;
|
||||
|
||||
bzero(&ioapic_irq, sizeof(struct vm_ioapic_irq));
|
||||
ioapic_irq.irq = irq;
|
||||
|
||||
return (ioctl(ctx->fd, VM_IOAPIC_DEASSERT_IRQ, &ioapic_irq));
|
||||
}
|
||||
|
||||
int
|
||||
vm_inject_nmi(struct vmctx *ctx, int vcpu)
|
||||
{
|
||||
|
||||
@@ -67,6 +67,8 @@ int vm_inject_event(struct vmctx *ctx, int vcpu, enum vm_event_type type,
|
||||
int vm_inject_event2(struct vmctx *ctx, int vcpu, enum vm_event_type type,
|
||||
int vector, int error_code);
|
||||
int vm_lapic_irq(struct vmctx *ctx, int vcpu, int vector);
|
||||
int vm_ioapic_assert_irq(struct vmctx *ctx, int irq);
|
||||
int vm_ioapic_deassert_irq(struct vmctx *ctx, int irq);
|
||||
int vm_inject_nmi(struct vmctx *ctx, int vcpu);
|
||||
int vm_capability_name2type(const char *capname);
|
||||
const char *vm_capability_type2name(int type);
|
||||
|
||||
@@ -38,6 +38,7 @@ struct vm_memory_segment;
|
||||
struct seg_desc;
|
||||
struct vm_exit;
|
||||
struct vm_run;
|
||||
struct vioapic;
|
||||
struct vlapic;
|
||||
struct vmspace;
|
||||
struct vm_object;
|
||||
@@ -116,10 +117,12 @@ int vm_nmi_pending(struct vm *vm, int vcpuid);
|
||||
void vm_nmi_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);
|
||||
int vm_get_capability(struct vm *vm, int vcpu, int type, int *val);
|
||||
int vm_set_capability(struct vm *vm, int vcpu, int type, int val);
|
||||
int vm_get_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state *state);
|
||||
int vm_set_x2apic_state(struct vm *vm, int vcpu, enum x2apic_state state);
|
||||
int vm_apicid2vcpuid(struct vm *vm, int apicid);
|
||||
void vm_activate_cpu(struct vm *vm, int vcpu);
|
||||
cpuset_t vm_active_cpus(struct vm *vm);
|
||||
struct vm_exit *vm_exitinfo(struct vm *vm, int vcpuid);
|
||||
|
||||
@@ -71,6 +71,10 @@ struct vm_lapic_irq {
|
||||
int vector;
|
||||
};
|
||||
|
||||
struct vm_ioapic_irq {
|
||||
int irq;
|
||||
};
|
||||
|
||||
struct vm_capability {
|
||||
int cpuid;
|
||||
enum vm_cap_type captype;
|
||||
@@ -164,6 +168,8 @@ enum {
|
||||
IOCNUM_INJECT_EVENT = 30,
|
||||
IOCNUM_LAPIC_IRQ = 31,
|
||||
IOCNUM_INJECT_NMI = 32,
|
||||
IOCNUM_IOAPIC_ASSERT_IRQ = 33,
|
||||
IOCNUM_IOAPIC_DEASSERT_IRQ = 34,
|
||||
|
||||
/* PCI pass-thru */
|
||||
IOCNUM_BIND_PPTDEV = 40,
|
||||
@@ -199,6 +205,10 @@ enum {
|
||||
_IOW('v', IOCNUM_INJECT_EVENT, struct vm_event)
|
||||
#define VM_LAPIC_IRQ \
|
||||
_IOW('v', IOCNUM_LAPIC_IRQ, struct vm_lapic_irq)
|
||||
#define VM_IOAPIC_ASSERT_IRQ \
|
||||
_IOW('v', IOCNUM_IOAPIC_ASSERT_IRQ, struct vm_ioapic_irq)
|
||||
#define VM_IOAPIC_DEASSERT_IRQ \
|
||||
_IOW('v', IOCNUM_IOAPIC_DEASSERT_IRQ, struct vm_ioapic_irq)
|
||||
#define VM_SET_CAPABILITY \
|
||||
_IOW('v', IOCNUM_SET_CAPABILITY, struct vm_capability)
|
||||
#define VM_GET_CAPABILITY \
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
/*-
|
||||
* Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
|
||||
* Copyright (c) 2013 Neel Natu <neel@freebsd.org>
|
||||
* 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 <sys/queue.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <x86/apicreg.h>
|
||||
#include <machine/vmm.h>
|
||||
|
||||
#include "vmm_ktr.h"
|
||||
#include "vmm_lapic.h"
|
||||
#include "vioapic.h"
|
||||
|
||||
#define IOREGSEL 0x00
|
||||
#define IOWIN 0x10
|
||||
|
||||
#define REDIR_ENTRIES 16
|
||||
#define INTR_ASSERTED(vioapic, pin) ((vioapic)->rtbl[(pin)].pinstate == true)
|
||||
|
||||
struct vioapic {
|
||||
struct vm *vm;
|
||||
struct mtx mtx;
|
||||
uint32_t id;
|
||||
uint32_t ioregsel;
|
||||
struct {
|
||||
uint64_t reg;
|
||||
bool pinstate;
|
||||
bool pending;
|
||||
} rtbl[REDIR_ENTRIES];
|
||||
};
|
||||
|
||||
#define VIOAPIC_LOCK(vioapic) mtx_lock(&((vioapic)->mtx))
|
||||
#define VIOAPIC_UNLOCK(vioapic) mtx_unlock(&((vioapic)->mtx))
|
||||
#define VIOAPIC_LOCKED(vioapic) mtx_owned(&((vioapic)->mtx))
|
||||
|
||||
static MALLOC_DEFINE(M_VIOAPIC, "vioapic", "bhyve virtual ioapic");
|
||||
|
||||
#define VIOAPIC_CTR1(vioapic, fmt, a1) \
|
||||
VM_CTR1((vioapic)->vm, fmt, a1)
|
||||
|
||||
#define VIOAPIC_CTR2(vioapic, fmt, a1, a2) \
|
||||
VM_CTR2((vioapic)->vm, fmt, a1, a2)
|
||||
|
||||
#define VIOAPIC_CTR3(vioapic, fmt, a1, a2, a3) \
|
||||
VM_CTR3((vioapic)->vm, fmt, a1, a2, a3)
|
||||
|
||||
#ifdef KTR
|
||||
static const char *
|
||||
pinstate_str(bool asserted)
|
||||
{
|
||||
|
||||
if (asserted)
|
||||
return ("asserted");
|
||||
else
|
||||
return ("deasserted");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
vioapic_set_pinstate(struct vioapic *vioapic, int pin, bool newstate)
|
||||
{
|
||||
int vector, apicid, vcpuid;
|
||||
uint32_t low, high;
|
||||
cpuset_t dmask;
|
||||
|
||||
KASSERT(pin >= 0 && pin < REDIR_ENTRIES,
|
||||
("vioapic_set_pinstate: invalid pin number %d", pin));
|
||||
|
||||
KASSERT(VIOAPIC_LOCKED(vioapic),
|
||||
("vioapic_set_pinstate: vioapic is not locked"));
|
||||
|
||||
VIOAPIC_CTR2(vioapic, "ioapic pin%d %s", pin, pinstate_str(newstate));
|
||||
|
||||
/* Nothing to do if interrupt pin has not changed state */
|
||||
if (vioapic->rtbl[pin].pinstate == newstate)
|
||||
return;
|
||||
|
||||
vioapic->rtbl[pin].pinstate = newstate; /* record it */
|
||||
|
||||
/* Nothing to do if interrupt pin is deasserted */
|
||||
if (!INTR_ASSERTED(vioapic, pin))
|
||||
return;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* We only deal with:
|
||||
* - edge triggered interrupts
|
||||
* - fixed delivery mode
|
||||
* Level-triggered sources will work so long as there is no sharing.
|
||||
*/
|
||||
low = vioapic->rtbl[pin].reg;
|
||||
high = vioapic->rtbl[pin].reg >> 32;
|
||||
if ((low & IOART_INTMASK) == IOART_INTMCLR &&
|
||||
(low & IOART_DESTMOD) == IOART_DESTPHY &&
|
||||
(low & IOART_DELMOD) == IOART_DELFIXED) {
|
||||
vector = low & IOART_INTVEC;
|
||||
apicid = high >> APIC_ID_SHIFT;
|
||||
if (apicid != 0xff) {
|
||||
/* unicast */
|
||||
vcpuid = vm_apicid2vcpuid(vioapic->vm, apicid);
|
||||
VIOAPIC_CTR3(vioapic, "ioapic pin%d triggering "
|
||||
"intr vector %d on vcpuid %d", pin, vector, vcpuid);
|
||||
lapic_set_intr(vioapic->vm, vcpuid, vector);
|
||||
} else {
|
||||
/* broadcast */
|
||||
VIOAPIC_CTR2(vioapic, "ioapic pin%d triggering intr "
|
||||
"vector %d on all vcpus", pin, vector);
|
||||
dmask = vm_active_cpus(vioapic->vm);
|
||||
while ((vcpuid = CPU_FFS(&dmask)) != 0) {
|
||||
vcpuid--;
|
||||
CPU_CLR(vcpuid, &dmask);
|
||||
lapic_set_intr(vioapic->vm, vcpuid, vector);
|
||||
}
|
||||
}
|
||||
} else if ((low & IOART_INTMASK) != IOART_INTMCLR &&
|
||||
(low & IOART_TRGRLVL) != 0) {
|
||||
/*
|
||||
* For level-triggered interrupts that have been
|
||||
* masked, set the pending bit so that an interrupt
|
||||
* will be generated on unmask and if the level is
|
||||
* still asserted
|
||||
*/
|
||||
VIOAPIC_CTR1(vioapic, "ioapic pin%d interrupt pending", pin);
|
||||
vioapic->rtbl[pin].pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vioapic_set_irqstate(struct vm *vm, int irq, bool state)
|
||||
{
|
||||
struct vioapic *vioapic;
|
||||
|
||||
if (irq < 0 || irq >= REDIR_ENTRIES)
|
||||
return (EINVAL);
|
||||
|
||||
vioapic = vm_ioapic(vm);
|
||||
|
||||
VIOAPIC_LOCK(vioapic);
|
||||
vioapic_set_pinstate(vioapic, irq, state);
|
||||
VIOAPIC_UNLOCK(vioapic);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
vioapic_assert_irq(struct vm *vm, int irq)
|
||||
{
|
||||
|
||||
return (vioapic_set_irqstate(vm, irq, true));
|
||||
}
|
||||
|
||||
int
|
||||
vioapic_deassert_irq(struct vm *vm, int irq)
|
||||
{
|
||||
|
||||
return (vioapic_set_irqstate(vm, irq, false));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
vioapic_read(struct vioapic *vioapic, uint32_t addr)
|
||||
{
|
||||
int regnum, pin, rshift;
|
||||
|
||||
regnum = addr & 0xff;
|
||||
switch (regnum) {
|
||||
case IOAPIC_ID:
|
||||
return (vioapic->id);
|
||||
break;
|
||||
case IOAPIC_VER:
|
||||
return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11);
|
||||
break;
|
||||
case IOAPIC_ARB:
|
||||
return (vioapic->id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* redirection table entries */
|
||||
if (regnum >= IOAPIC_REDTBL &&
|
||||
regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
|
||||
pin = (regnum - IOAPIC_REDTBL) / 2;
|
||||
if ((regnum - IOAPIC_REDTBL) % 2)
|
||||
rshift = 32;
|
||||
else
|
||||
rshift = 0;
|
||||
|
||||
return (vioapic->rtbl[pin].reg >> rshift);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
vioapic_write(struct vioapic *vioapic, uint32_t addr, uint32_t data)
|
||||
{
|
||||
int regnum, pin, lshift;
|
||||
|
||||
regnum = addr & 0xff;
|
||||
switch (regnum) {
|
||||
case IOAPIC_ID:
|
||||
vioapic->id = data & APIC_ID_MASK;
|
||||
break;
|
||||
case IOAPIC_VER:
|
||||
case IOAPIC_ARB:
|
||||
/* readonly */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* redirection table entries */
|
||||
if (regnum >= IOAPIC_REDTBL &&
|
||||
regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
|
||||
pin = (regnum - IOAPIC_REDTBL) / 2;
|
||||
if ((regnum - IOAPIC_REDTBL) % 2)
|
||||
lshift = 32;
|
||||
else
|
||||
lshift = 0;
|
||||
|
||||
vioapic->rtbl[pin].reg &= ~((uint64_t)0xffffffff << lshift);
|
||||
vioapic->rtbl[pin].reg |= ((uint64_t)data << lshift);
|
||||
|
||||
VIOAPIC_CTR2(vioapic, "ioapic pin%d redir table entry %#lx",
|
||||
pin, vioapic->rtbl[pin].reg);
|
||||
|
||||
if (vioapic->rtbl[pin].pending &&
|
||||
((vioapic->rtbl[pin].reg & IOART_INTMASK) ==
|
||||
IOART_INTMCLR)) {
|
||||
vioapic->rtbl[pin].pending = false;
|
||||
/*
|
||||
* Inject the deferred level-triggered int if it is
|
||||
* still asserted. Simulate by toggling the pin
|
||||
* off and then on.
|
||||
*/
|
||||
if (vioapic->rtbl[pin].pinstate == true) {
|
||||
VIOAPIC_CTR1(vioapic, "ioapic pin%d pending "
|
||||
"interrupt delivered", pin);
|
||||
vioapic_set_pinstate(vioapic, pin, false);
|
||||
vioapic_set_pinstate(vioapic, pin, true);
|
||||
} else {
|
||||
VIOAPIC_CTR1(vioapic, "ioapic pin%d pending "
|
||||
"interrupt dismissed", pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
vioapic_mmio_rw(struct vioapic *vioapic, uint64_t gpa, uint64_t *data,
|
||||
int size, bool doread)
|
||||
{
|
||||
uint64_t offset;
|
||||
|
||||
offset = gpa - VIOAPIC_BASE;
|
||||
|
||||
/*
|
||||
* The IOAPIC specification allows 32-bit wide accesses to the
|
||||
* IOREGSEL (offset 0) and IOWIN (offset 16) registers.
|
||||
*/
|
||||
if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
|
||||
if (doread)
|
||||
*data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
VIOAPIC_LOCK(vioapic);
|
||||
if (offset == IOREGSEL) {
|
||||
if (doread)
|
||||
*data = vioapic->ioregsel;
|
||||
else
|
||||
vioapic->ioregsel = *data;
|
||||
} else {
|
||||
if (doread)
|
||||
*data = vioapic_read(vioapic, vioapic->ioregsel);
|
||||
else
|
||||
vioapic_write(vioapic, vioapic->ioregsel, *data);
|
||||
}
|
||||
VIOAPIC_UNLOCK(vioapic);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa, uint64_t *rval,
|
||||
int size, void *arg)
|
||||
{
|
||||
int error;
|
||||
struct vioapic *vioapic;
|
||||
|
||||
vioapic = vm_ioapic(vm);
|
||||
error = vioapic_mmio_rw(vioapic, gpa, rval, size, true);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa, uint64_t wval,
|
||||
int size, void *arg)
|
||||
{
|
||||
int error;
|
||||
struct vioapic *vioapic;
|
||||
|
||||
vioapic = vm_ioapic(vm);
|
||||
error = vioapic_mmio_rw(vioapic, gpa, &wval, size, false);
|
||||
return (error);
|
||||
}
|
||||
|
||||
struct vioapic *
|
||||
vioapic_init(struct vm *vm)
|
||||
{
|
||||
int i;
|
||||
struct vioapic *vioapic;
|
||||
|
||||
vioapic = malloc(sizeof(struct vioapic), M_VIOAPIC, M_WAITOK | M_ZERO);
|
||||
|
||||
vioapic->vm = vm;
|
||||
mtx_init(&vioapic->mtx, "vioapic lock", NULL, MTX_DEF);
|
||||
|
||||
/* Initialize all redirection entries to mask all interrupts */
|
||||
for (i = 0; i < REDIR_ENTRIES; i++)
|
||||
vioapic->rtbl[i].reg = 0x0001000000010000UL;
|
||||
|
||||
return (vioapic);
|
||||
}
|
||||
|
||||
void
|
||||
vioapic_cleanup(struct vioapic *vioapic)
|
||||
{
|
||||
|
||||
free(vioapic, M_VIOAPIC);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 NetApp, Inc.
|
||||
* Copyright (c) 2013 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
|
||||
* Copyright (c) 2013 Neel Natu <neel@freebsd.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,13 +27,23 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _IOAPIC_H_
|
||||
#define _IOAPIC_H_
|
||||
#ifndef _VIOAPIC_H_
|
||||
#define _VIOAPIC_H_
|
||||
|
||||
struct vmctx;
|
||||
struct vm;
|
||||
struct vioapic;
|
||||
|
||||
void ioapic_init(int num);
|
||||
void ioapic_deassert_pin(struct vmctx *ctx, int pin);
|
||||
void ioapic_assert_pin(struct vmctx *ctx, int pin);
|
||||
#define VIOAPIC_BASE 0xFEC00000
|
||||
#define VIOAPIC_SIZE 4096
|
||||
|
||||
struct vioapic *vioapic_init(struct vm *vm);
|
||||
void vioapic_cleanup(struct vioapic *vioapic);
|
||||
|
||||
int vioapic_assert_irq(struct vm *vm, int irq);
|
||||
int vioapic_deassert_irq(struct vm *vm, int irq);
|
||||
|
||||
int vioapic_mmio_write(void *vm, int vcpuid, uint64_t gpa,
|
||||
uint64_t wval, int size, void *arg);
|
||||
int vioapic_mmio_read(void *vm, int vcpuid, uint64_t gpa,
|
||||
uint64_t *rval, int size, void *arg);
|
||||
#endif
|
||||
+33
-4
@@ -59,11 +59,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/vmparam.h>
|
||||
|
||||
#include <machine/vmm.h>
|
||||
#include <machine/vmm_dev.h>
|
||||
|
||||
#include "vmm_ktr.h"
|
||||
#include "vmm_host.h"
|
||||
#include "vmm_mem.h"
|
||||
#include "vmm_util.h"
|
||||
#include <machine/vmm_dev.h>
|
||||
#include "vioapic.h"
|
||||
#include "vlapic.h"
|
||||
#include "vmm_msr.h"
|
||||
#include "vmm_ipi.h"
|
||||
@@ -106,6 +108,7 @@ struct mem_seg {
|
||||
struct vm {
|
||||
void *cookie; /* processor-specific data */
|
||||
void *iommu; /* iommu-specific data */
|
||||
struct vioapic *vioapic; /* virtual ioapic */
|
||||
struct vmspace *vmspace; /* guest's address space */
|
||||
struct vcpu vcpu[VM_MAXCPU];
|
||||
int num_mem_segs;
|
||||
@@ -300,6 +303,7 @@ vm_create(const char *name, struct vm **retvm)
|
||||
vm = malloc(sizeof(struct vm), M_VM, M_WAITOK | M_ZERO);
|
||||
strcpy(vm->name, name);
|
||||
vm->cookie = VMINIT(vm, vmspace_pmap(vmspace));
|
||||
vm->vioapic = vioapic_init(vm);
|
||||
|
||||
for (i = 0; i < VM_MAXCPU; i++) {
|
||||
vcpu_init(vm, i);
|
||||
@@ -341,6 +345,8 @@ vm_destroy(struct vm *vm)
|
||||
for (i = 0; i < VM_MAXCPU; i++)
|
||||
vcpu_cleanup(&vm->vcpu[i]);
|
||||
|
||||
vioapic_cleanup(vm->vioapic);
|
||||
|
||||
VMSPACE_FREE(vm->vmspace);
|
||||
|
||||
VMCLEANUP(vm->cookie);
|
||||
@@ -938,6 +944,8 @@ vm_handle_inst_emul(struct vm *vm, int vcpuid, boolean_t *retu)
|
||||
struct vm_exit *vme;
|
||||
int error, inst_length;
|
||||
uint64_t rip, gla, gpa, cr3;
|
||||
mem_region_read_t mread;
|
||||
mem_region_write_t mwrite;
|
||||
|
||||
vcpu = &vm->vcpu[vcpuid];
|
||||
vme = &vcpu->exitinfo;
|
||||
@@ -960,13 +968,18 @@ vm_handle_inst_emul(struct vm *vm, int vcpuid, boolean_t *retu)
|
||||
return (EFAULT);
|
||||
|
||||
/* return to userland unless this is a local apic access */
|
||||
if (gpa < DEFAULT_APIC_BASE || gpa >= DEFAULT_APIC_BASE + PAGE_SIZE) {
|
||||
if (gpa >= DEFAULT_APIC_BASE && gpa < DEFAULT_APIC_BASE + PAGE_SIZE) {
|
||||
mread = lapic_mmio_read;
|
||||
mwrite = lapic_mmio_write;
|
||||
} else if (gpa >= VIOAPIC_BASE && gpa < VIOAPIC_BASE + VIOAPIC_SIZE) {
|
||||
mread = vioapic_mmio_read;
|
||||
mwrite = vioapic_mmio_write;
|
||||
} else {
|
||||
*retu = TRUE;
|
||||
return (0);
|
||||
}
|
||||
|
||||
error = vmm_emulate_instruction(vm, vcpuid, gpa, vie,
|
||||
lapic_mmio_read, lapic_mmio_write, 0);
|
||||
error = vmm_emulate_instruction(vm, vcpuid, gpa, vie, mread, mwrite, 0);
|
||||
|
||||
/* return to userland to spin up the AP */
|
||||
if (error == 0 && vme->exitcode == VM_EXITCODE_SPINUP_AP)
|
||||
@@ -1149,6 +1162,13 @@ vm_lapic(struct vm *vm, int cpu)
|
||||
return (vm->vcpu[cpu].vlapic);
|
||||
}
|
||||
|
||||
struct vioapic *
|
||||
vm_ioapic(struct vm *vm)
|
||||
{
|
||||
|
||||
return (vm->vioapic);
|
||||
}
|
||||
|
||||
boolean_t
|
||||
vmm_is_pptdev(int bus, int slot, int func)
|
||||
{
|
||||
@@ -1313,3 +1333,12 @@ vm_get_vmspace(struct vm *vm)
|
||||
|
||||
return (vm->vmspace);
|
||||
}
|
||||
|
||||
int
|
||||
vm_apicid2vcpuid(struct vm *vm, int apicid)
|
||||
{
|
||||
/*
|
||||
* XXX apic id is assumed to be numerically identical to vcpu id
|
||||
*/
|
||||
return (apicid);
|
||||
}
|
||||
|
||||
+11
-1
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include "vmm_stat.h"
|
||||
#include "vmm_mem.h"
|
||||
#include "io/ppt.h"
|
||||
#include "io/vioapic.h"
|
||||
#include <machine/vmm_dev.h>
|
||||
|
||||
struct vmmdev_softc {
|
||||
@@ -146,10 +147,11 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
|
||||
struct vmmdev_softc *sc;
|
||||
struct vm_memory_segment *seg;
|
||||
struct vm_register *vmreg;
|
||||
struct vm_seg_desc* vmsegdesc;
|
||||
struct vm_seg_desc *vmsegdesc;
|
||||
struct vm_run *vmrun;
|
||||
struct vm_event *vmevent;
|
||||
struct vm_lapic_irq *vmirq;
|
||||
struct vm_ioapic_irq *ioapic_irq;
|
||||
struct vm_capability *vmcap;
|
||||
struct vm_pptdev *pptdev;
|
||||
struct vm_pptdev_mmio *pptmmio;
|
||||
@@ -293,6 +295,14 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
|
||||
vmirq = (struct vm_lapic_irq *)data;
|
||||
error = lapic_set_intr(sc->vm, vmirq->cpuid, vmirq->vector);
|
||||
break;
|
||||
case VM_IOAPIC_ASSERT_IRQ:
|
||||
ioapic_irq = (struct vm_ioapic_irq *)data;
|
||||
error = vioapic_assert_irq(sc->vm, ioapic_irq->irq);
|
||||
break;
|
||||
case VM_IOAPIC_DEASSERT_IRQ:
|
||||
ioapic_irq = (struct vm_ioapic_irq *)data;
|
||||
error = vioapic_deassert_irq(sc->vm, ioapic_irq->irq);
|
||||
break;
|
||||
case VM_MAP_MEMORY:
|
||||
seg = (struct vm_memory_segment *)data;
|
||||
error = vm_malloc(sc->vm, seg->gpa, seg->len);
|
||||
|
||||
@@ -27,6 +27,7 @@ SRCS+= vmm.c \
|
||||
.PATH: ${.CURDIR}/../../amd64/vmm/io
|
||||
SRCS+= iommu.c \
|
||||
ppt.c \
|
||||
vioapic.c \
|
||||
vlapic.c
|
||||
|
||||
# intel-specific files
|
||||
|
||||
@@ -7,7 +7,7 @@ PROG= bhyve
|
||||
DEBUG_FLAGS= -g -O0
|
||||
|
||||
SRCS= acpi.c atpic.c bhyverun.c block_if.c consport.c dbgport.c elcr.c
|
||||
SRCS+= inout.c ioapic.c legacy_irq.c mem.c mevent.c mptbl.c pci_ahci.c
|
||||
SRCS+= inout.c legacy_irq.c mem.c mevent.c mptbl.c pci_ahci.c
|
||||
SRCS+= pci_emul.c pci_hostbridge.c pci_lpc.c pci_passthru.c pci_virtio_block.c
|
||||
SRCS+= pci_virtio_net.c pci_uart.c pit_8254.c pmtmr.c post.c rtc.c
|
||||
SRCS+= uart_emul.c virtio.c xmsr.c spinup_ap.c
|
||||
|
||||
@@ -61,7 +61,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include "pci_emul.h"
|
||||
#include "pci_lpc.h"
|
||||
#include "xmsr.h"
|
||||
#include "ioapic.h"
|
||||
#include "spinup_ap.h"
|
||||
#include "rtc.h"
|
||||
|
||||
@@ -663,8 +662,6 @@ main(int argc, char *argv[])
|
||||
if (init_pci(ctx) != 0)
|
||||
exit(1);
|
||||
|
||||
ioapic_init(0);
|
||||
|
||||
if (gdb_port != 0)
|
||||
init_dbgport(gdb_port);
|
||||
|
||||
|
||||
@@ -1,378 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 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 <x86/apicreg.h>
|
||||
#include <machine/vmm.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <vmmapi.h>
|
||||
|
||||
#include "inout.h"
|
||||
#include "mem.h"
|
||||
#include "bhyverun.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static uint64_t ioapic_clearpend, ioapic_togglepend, ioapic_setpend;
|
||||
|
||||
#define IOAPIC_PADDR 0xFEC00000
|
||||
|
||||
#define IOREGSEL 0x00
|
||||
#define IOWIN 0x10
|
||||
|
||||
#define REDIR_ENTRIES 16
|
||||
#define INTR_ASSERTED(ioapic, pin) \
|
||||
((ioapic)->rtbl[(pin)].pinstate == true)
|
||||
|
||||
struct ioapic {
|
||||
int inited;
|
||||
uint32_t id;
|
||||
struct {
|
||||
uint64_t reg;
|
||||
bool pinstate;
|
||||
bool pending;
|
||||
} rtbl[REDIR_ENTRIES];
|
||||
|
||||
uintptr_t paddr; /* gpa where the ioapic is mapped */
|
||||
uint32_t ioregsel;
|
||||
struct memory_region *region;
|
||||
pthread_mutex_t mtx;
|
||||
};
|
||||
|
||||
static struct ioapic ioapics[1]; /* only a single ioapic for now */
|
||||
|
||||
static int ioapic_region_read(struct vmctx *vm, struct ioapic *ioapic,
|
||||
uintptr_t paddr, int size, uint64_t *data);
|
||||
static int ioapic_region_write(struct vmctx *vm, struct ioapic *ioapic,
|
||||
uintptr_t paddr, int size, uint64_t data);
|
||||
static int ioapic_region_handler(struct vmctx *vm, int vcpu, int dir,
|
||||
uintptr_t paddr, int size, uint64_t *val, void *arg1, long arg2);
|
||||
|
||||
static void
|
||||
ioapic_set_pinstate(struct vmctx *ctx, int pin, bool newstate)
|
||||
{
|
||||
int vector, apicid, vcpu;
|
||||
uint32_t low, high;
|
||||
struct ioapic *ioapic;
|
||||
|
||||
ioapic = &ioapics[0]; /* assume a single ioapic */
|
||||
|
||||
/* Nothing to do if interrupt pin has not changed state */
|
||||
if (ioapic->rtbl[pin].pinstate == newstate)
|
||||
return;
|
||||
|
||||
ioapic->rtbl[pin].pinstate = newstate; /* record it */
|
||||
|
||||
/* Nothing to do if interrupt pin is deasserted */
|
||||
if (!INTR_ASSERTED(ioapic, pin))
|
||||
return;
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* We only deal with:
|
||||
* - edge triggered interrupts
|
||||
* - fixed delivery mode
|
||||
* Level-triggered sources will work so long as there is
|
||||
* no sharing.
|
||||
*/
|
||||
low = ioapic->rtbl[pin].reg;
|
||||
high = ioapic->rtbl[pin].reg >> 32;
|
||||
if ((low & IOART_INTMASK) == IOART_INTMCLR &&
|
||||
(low & IOART_DESTMOD) == IOART_DESTPHY &&
|
||||
(low & IOART_DELMOD) == IOART_DELFIXED) {
|
||||
vector = low & IOART_INTVEC;
|
||||
apicid = high >> APIC_ID_SHIFT;
|
||||
if (apicid != 0xff) {
|
||||
/* unicast */
|
||||
vcpu = vm_apicid2vcpu(ctx, apicid);
|
||||
vm_lapic_irq(ctx, vcpu, vector);
|
||||
} else {
|
||||
/* broadcast */
|
||||
vcpu = 0;
|
||||
while (vcpu < guest_ncpus) {
|
||||
vm_lapic_irq(ctx, vcpu, vector);
|
||||
vcpu++;
|
||||
}
|
||||
}
|
||||
} else if ((low & IOART_INTMASK) != IOART_INTMCLR &&
|
||||
low & IOART_TRGRLVL) {
|
||||
/*
|
||||
* For level-triggered interrupts that have been
|
||||
* masked, set the pending bit so that an interrupt
|
||||
* will be generated on unmask and if the level is
|
||||
* still asserted
|
||||
*/
|
||||
ioapic_setpend++;
|
||||
ioapic->rtbl[pin].pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ioapic_set_pinstate_locked(struct vmctx *ctx, int pin, bool newstate)
|
||||
{
|
||||
struct ioapic *ioapic;
|
||||
|
||||
if (pin < 0 || pin >= REDIR_ENTRIES)
|
||||
return;
|
||||
|
||||
ioapic = &ioapics[0];
|
||||
|
||||
pthread_mutex_lock(&ioapic->mtx);
|
||||
ioapic_set_pinstate(ctx, pin, newstate);
|
||||
pthread_mutex_unlock(&ioapic->mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
* External entry points require locking
|
||||
*/
|
||||
void
|
||||
ioapic_deassert_pin(struct vmctx *ctx, int pin)
|
||||
{
|
||||
ioapic_set_pinstate_locked(ctx, pin, false);
|
||||
}
|
||||
|
||||
void
|
||||
ioapic_assert_pin(struct vmctx *ctx, int pin)
|
||||
{
|
||||
ioapic_set_pinstate_locked(ctx, pin, true);
|
||||
}
|
||||
|
||||
void
|
||||
ioapic_init(int which)
|
||||
{
|
||||
struct mem_range memp;
|
||||
struct ioapic *ioapic;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
assert(which == 0);
|
||||
|
||||
ioapic = &ioapics[which];
|
||||
assert(ioapic->inited == 0);
|
||||
|
||||
bzero(ioapic, sizeof(struct ioapic));
|
||||
|
||||
pthread_mutex_init(&ioapic->mtx, NULL);
|
||||
|
||||
/* Initialize all redirection entries to mask all interrupts */
|
||||
for (i = 0; i < REDIR_ENTRIES; i++)
|
||||
ioapic->rtbl[i].reg = 0x0001000000010000UL;
|
||||
|
||||
ioapic->paddr = IOAPIC_PADDR;
|
||||
|
||||
/* Register emulated memory region */
|
||||
memp.name = "ioapic";
|
||||
memp.flags = MEM_F_RW;
|
||||
memp.handler = ioapic_region_handler;
|
||||
memp.arg1 = ioapic;
|
||||
memp.arg2 = which;
|
||||
memp.base = ioapic->paddr;
|
||||
memp.size = sizeof(struct IOAPIC);
|
||||
error = register_mem(&memp);
|
||||
|
||||
assert (error == 0);
|
||||
|
||||
ioapic->inited = 1;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ioapic_read(struct ioapic *ioapic, uint32_t addr)
|
||||
{
|
||||
int regnum, pin, rshift;
|
||||
|
||||
assert(ioapic->inited);
|
||||
|
||||
regnum = addr & 0xff;
|
||||
switch (regnum) {
|
||||
case IOAPIC_ID:
|
||||
return (ioapic->id);
|
||||
break;
|
||||
case IOAPIC_VER:
|
||||
return ((REDIR_ENTRIES << MAXREDIRSHIFT) | 0x11);
|
||||
break;
|
||||
case IOAPIC_ARB:
|
||||
return (ioapic->id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* redirection table entries */
|
||||
if (regnum >= IOAPIC_REDTBL &&
|
||||
regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
|
||||
pin = (regnum - IOAPIC_REDTBL) / 2;
|
||||
if ((regnum - IOAPIC_REDTBL) % 2)
|
||||
rshift = 32;
|
||||
else
|
||||
rshift = 0;
|
||||
|
||||
return (ioapic->rtbl[pin].reg >> rshift);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ioapic_write(struct vmctx *vm, struct ioapic *ioapic, uint32_t addr,
|
||||
uint32_t data)
|
||||
{
|
||||
int regnum, pin, lshift;
|
||||
|
||||
assert(ioapic->inited);
|
||||
|
||||
regnum = addr & 0xff;
|
||||
switch (regnum) {
|
||||
case IOAPIC_ID:
|
||||
ioapic->id = data & APIC_ID_MASK;
|
||||
break;
|
||||
case IOAPIC_VER:
|
||||
case IOAPIC_ARB:
|
||||
/* readonly */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* redirection table entries */
|
||||
if (regnum >= IOAPIC_REDTBL &&
|
||||
regnum < IOAPIC_REDTBL + REDIR_ENTRIES * 2) {
|
||||
pin = (regnum - IOAPIC_REDTBL) / 2;
|
||||
if ((regnum - IOAPIC_REDTBL) % 2)
|
||||
lshift = 32;
|
||||
else
|
||||
lshift = 0;
|
||||
|
||||
ioapic->rtbl[pin].reg &= ~((uint64_t)0xffffffff << lshift);
|
||||
ioapic->rtbl[pin].reg |= ((uint64_t)data << lshift);
|
||||
|
||||
if (ioapic->rtbl[pin].pending &&
|
||||
((ioapic->rtbl[pin].reg & IOART_INTMASK) ==
|
||||
IOART_INTMCLR)) {
|
||||
ioapic->rtbl[pin].pending = false;
|
||||
ioapic_clearpend++;
|
||||
/*
|
||||
* Inject the deferred level-triggered int if it is
|
||||
* still asserted. Simulate by toggling the pin
|
||||
* off and then on.
|
||||
*/
|
||||
if (ioapic->rtbl[pin].pinstate == true) {
|
||||
ioapic_togglepend++;
|
||||
ioapic_set_pinstate(vm, pin, false);
|
||||
ioapic_set_pinstate(vm, pin, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ioapic_region_read(struct vmctx *vm, struct ioapic *ioapic, uintptr_t paddr,
|
||||
int size, uint64_t *data)
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = paddr - ioapic->paddr;
|
||||
|
||||
/*
|
||||
* The IOAPIC specification allows 32-bit wide accesses to the
|
||||
* IOREGSEL (offset 0) and IOWIN (offset 16) registers.
|
||||
*/
|
||||
if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
|
||||
#if 1
|
||||
printf("invalid access to ioapic%d: size %d, offset %d\n",
|
||||
(int)(ioapic - ioapics), size, offset);
|
||||
#endif
|
||||
*data = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (offset == IOREGSEL)
|
||||
*data = ioapic->ioregsel;
|
||||
else
|
||||
*data = ioapic_read(ioapic, ioapic->ioregsel);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ioapic_region_write(struct vmctx *vm, struct ioapic *ioapic, uintptr_t paddr,
|
||||
int size, uint64_t data)
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = paddr - ioapic->paddr;
|
||||
|
||||
/*
|
||||
* The ioapic specification allows 32-bit wide accesses to the
|
||||
* IOREGSEL (offset 0) and IOWIN (offset 16) registers.
|
||||
*/
|
||||
if (size != 4 || (offset != IOREGSEL && offset != IOWIN)) {
|
||||
#if 1
|
||||
printf("invalid access to ioapic%d: size %d, offset %d\n",
|
||||
(int)(ioapic - ioapics), size, offset);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (offset == IOREGSEL)
|
||||
ioapic->ioregsel = data;
|
||||
else
|
||||
ioapic_write(vm, ioapic, ioapic->ioregsel, data);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ioapic_region_handler(struct vmctx *vm, int vcpu, int dir, uintptr_t paddr,
|
||||
int size, uint64_t *val, void *arg1, long arg2)
|
||||
{
|
||||
struct ioapic *ioapic;
|
||||
int which;
|
||||
|
||||
ioapic = arg1;
|
||||
which = arg2;
|
||||
|
||||
assert(ioapic == &ioapics[which]);
|
||||
|
||||
pthread_mutex_lock(&ioapic->mtx);
|
||||
if (dir == MEM_F_READ)
|
||||
ioapic_region_read(vm, ioapic, paddr, size, val);
|
||||
else
|
||||
ioapic_region_write(vm, ioapic, paddr, size, *val);
|
||||
pthread_mutex_unlock(&ioapic->mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include "legacy_irq.h"
|
||||
#include "mem.h"
|
||||
#include "pci_emul.h"
|
||||
#include "ioapic.h"
|
||||
|
||||
#define CONF1_ADDR_PORT 0x0cf8
|
||||
#define CONF1_DATA_PORT 0x0cfc
|
||||
@@ -1136,7 +1135,7 @@ pci_lintr_assert(struct pci_devinst *pi)
|
||||
{
|
||||
|
||||
assert(pi->pi_lintr_pin >= 0);
|
||||
ioapic_assert_pin(pi->pi_vmctx, pi->pi_lintr_pin);
|
||||
vm_ioapic_assert_irq(pi->pi_vmctx, pi->pi_lintr_pin);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1144,7 +1143,7 @@ pci_lintr_deassert(struct pci_devinst *pi)
|
||||
{
|
||||
|
||||
assert(pi->pi_lintr_pin >= 0);
|
||||
ioapic_deassert_pin(pi->pi_vmctx, pi->pi_lintr_pin);
|
||||
vm_ioapic_deassert_irq(pi->pi_vmctx, pi->pi_lintr_pin);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -31,13 +31,16 @@
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <machine/vmm.h>
|
||||
#include <machine/vmm_dev.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vmmapi.h>
|
||||
|
||||
#include "inout.h"
|
||||
#include "ioapic.h"
|
||||
#include "pci_emul.h"
|
||||
#include "uart_emul.h"
|
||||
|
||||
@@ -91,7 +94,7 @@ lpc_uart_intr_assert(void *arg)
|
||||
|
||||
assert(sc->irq >= 0);
|
||||
|
||||
ioapic_assert_pin(lpc_bridge->pi_vmctx, sc->irq);
|
||||
vm_ioapic_assert_irq(lpc_bridge->pi_vmctx, sc->irq);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -101,7 +104,7 @@ lpc_uart_intr_deassert(void *arg)
|
||||
|
||||
assert(sc->irq >= 0);
|
||||
|
||||
ioapic_deassert_pin(lpc_bridge->pi_vmctx, sc->irq);
|
||||
vm_ioapic_deassert_irq(lpc_bridge->pi_vmctx, sc->irq);
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
@@ -44,7 +44,6 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "bhyverun.h"
|
||||
#include "inout.h"
|
||||
#include "ioapic.h"
|
||||
#include "mevent.h"
|
||||
#include "pit_8254.h"
|
||||
|
||||
@@ -106,8 +105,8 @@ pit_mevent_cb(int fd, enum ev_type type, void *param)
|
||||
|
||||
pit_mev_count++;
|
||||
|
||||
ioapic_assert_pin(c->ctx, 2);
|
||||
ioapic_deassert_pin(c->ctx, 2);
|
||||
vm_ioapic_assert_irq(c->ctx, 2);
|
||||
vm_ioapic_deassert_irq(c->ctx, 2);
|
||||
|
||||
/*
|
||||
* Delete the timer for one-shots
|
||||
|
||||
Reference in New Issue
Block a user