Index: lib/libvmmapi/vmmapi.c =================================================================== --- lib/libvmmapi/vmmapi.c (revision 257423) +++ lib/libvmmapi/vmmapi.c (working copy) @@ -397,6 +397,28 @@ } 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) { struct vm_nmi vmnmi; Index: lib/libvmmapi/vmmapi.h =================================================================== --- lib/libvmmapi/vmmapi.h (revision 257423) +++ lib/libvmmapi/vmmapi.h (working copy) @@ -67,6 +67,8 @@ 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); Index: sys/amd64/conf/GENERIC =================================================================== --- sys/amd64/conf/GENERIC (revision 257423) +++ sys/amd64/conf/GENERIC (working copy) @@ -352,3 +352,5 @@ # VMware support device vmx # VMware VMXNET3 Ethernet + +options KTR Index: sys/amd64/include/vmm.h =================================================================== --- sys/amd64/include/vmm.h (revision 257423) +++ sys/amd64/include/vmm.h (working copy) @@ -38,6 +38,7 @@ struct seg_desc; struct vm_exit; struct vm_run; +struct vioapic; struct vlapic; struct vmspace; struct vm_object; @@ -116,10 +117,12 @@ 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); Index: sys/amd64/include/vmm_dev.h =================================================================== --- sys/amd64/include/vmm_dev.h (revision 257423) +++ sys/amd64/include/vmm_dev.h (working copy) @@ -71,6 +71,10 @@ int vector; }; +struct vm_ioapic_irq { + int irq; +}; + struct vm_capability { int cpuid; enum vm_cap_type captype; @@ -164,6 +168,8 @@ 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 @@ _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 \ Index: sys/amd64/vmm/io/vioapic.c =================================================================== --- sys/amd64/vmm/io/vioapic.c (revision 0) +++ sys/amd64/vmm/io/vioapic.c (working copy) @@ -0,0 +1,366 @@ +/*- + * Copyright (c) 2013 Tycho Nightingale + * Copyright (c) 2013 Neel Natu + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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); +} Property changes on: sys/amd64/vmm/io/vioapic.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: sys/amd64/vmm/io/vioapic.h =================================================================== --- sys/amd64/vmm/io/vioapic.h (revision 0) +++ sys/amd64/vmm/io/vioapic.h (working copy) @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2013 Tycho Nightingale + * Copyright (c) 2013 Neel Natu + * 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$ + */ + +#ifndef _VIOAPIC_H_ +#define _VIOAPIC_H_ + +struct vm; +struct vioapic; + +#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 Property changes on: sys/amd64/vmm/io/vioapic.h ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: sys/amd64/vmm/vmm.c =================================================================== --- sys/amd64/vmm/vmm.c (revision 257423) +++ sys/amd64/vmm/vmm.c (working copy) @@ -59,11 +59,13 @@ #include #include +#include + #include "vmm_ktr.h" #include "vmm_host.h" #include "vmm_mem.h" #include "vmm_util.h" -#include +#include "vioapic.h" #include "vlapic.h" #include "vmm_msr.h" #include "vmm_ipi.h" @@ -106,6 +108,7 @@ 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 = 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); +} Index: sys/amd64/vmm/vmm_dev.c =================================================================== --- sys/amd64/vmm/vmm_dev.c (revision 257423) +++ sys/amd64/vmm/vmm_dev.c (working copy) @@ -53,6 +53,7 @@ #include "vmm_stat.h" #include "vmm_mem.h" #include "io/ppt.h" +#include "io/vioapic.h" #include struct vmmdev_softc { @@ -146,10 +147,11 @@ 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 @@ 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); Index: sys/modules/vmm/Makefile =================================================================== --- sys/modules/vmm/Makefile (revision 257423) +++ sys/modules/vmm/Makefile (working copy) @@ -28,6 +28,7 @@ SRCS+= iommu.c \ ppt.c \ vdev.c \ + vioapic.c \ vlapic.c # intel-specific files Index: usr.sbin/bhyve/Makefile =================================================================== --- usr.sbin/bhyve/Makefile (revision 257423) +++ usr.sbin/bhyve/Makefile (working copy) @@ -7,7 +7,7 @@ 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 Index: usr.sbin/bhyve/bhyverun.c =================================================================== --- usr.sbin/bhyve/bhyverun.c (revision 257423) +++ usr.sbin/bhyve/bhyverun.c (working copy) @@ -61,7 +61,6 @@ #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 @@ if (init_pci(ctx) != 0) exit(1); - ioapic_init(0); - if (gdb_port != 0) init_dbgport(gdb_port); Index: usr.sbin/bhyve/ioapic.c =================================================================== --- usr.sbin/bhyve/ioapic.c (revision 257423) +++ usr.sbin/bhyve/ioapic.c (working copy) @@ -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 -__FBSDID("$FreeBSD$"); - -#include - -#include -#include - -#include -#include -#include -#include - -#include - -#include "inout.h" -#include "mem.h" -#include "bhyverun.h" - -#include - -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); -} Index: usr.sbin/bhyve/ioapic.h =================================================================== --- usr.sbin/bhyve/ioapic.h (revision 257423) +++ usr.sbin/bhyve/ioapic.h (working copy) @@ -1,38 +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$ - */ - -#ifndef _IOAPIC_H_ -#define _IOAPIC_H_ - -struct vmctx; - -void ioapic_init(int num); -void ioapic_deassert_pin(struct vmctx *ctx, int pin); -void ioapic_assert_pin(struct vmctx *ctx, int pin); - -#endif Index: usr.sbin/bhyve/pci_emul.c =================================================================== --- usr.sbin/bhyve/pci_emul.c (revision 257423) +++ usr.sbin/bhyve/pci_emul.c (working copy) @@ -49,7 +49,6 @@ #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 @@ { 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 @@ { 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); } /* Index: usr.sbin/bhyve/pci_lpc.c =================================================================== --- usr.sbin/bhyve/pci_lpc.c (revision 257423) +++ usr.sbin/bhyve/pci_lpc.c (working copy) @@ -31,13 +31,16 @@ __FBSDID("$FreeBSD$"); #include +#include +#include #include #include #include +#include + #include "inout.h" -#include "ioapic.h" #include "pci_emul.h" #include "uart_emul.h" @@ -91,7 +94,7 @@ 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 @@ 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 Index: usr.sbin/bhyve/pit_8254.c =================================================================== --- usr.sbin/bhyve/pit_8254.c (revision 257423) +++ usr.sbin/bhyve/pit_8254.c (working copy) @@ -44,7 +44,6 @@ #include "bhyverun.h" #include "inout.h" -#include "ioapic.h" #include "mevent.h" #include "pit_8254.h" @@ -106,8 +105,8 @@ pit_mev_count++; - ioapic_assert_pin(c->ctx, 0); - ioapic_deassert_pin(c->ctx, 0); + vm_ioapic_assert_irq(c->ctx, 0); + vm_ioapic_deassert_irq(c->ctx, 0); /* * Delete the timer for one-shots