diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile index b381b8cb5607..7f4806ae58b0 100644 --- a/usr.sbin/bhyve/Makefile +++ b/usr.sbin/bhyve/Makefile @@ -5,7 +5,7 @@ PROG= bhyve SRCS= atpic.c consport.c dbgport.c elcr.c fbsdrun.c inout.c -SRCS+= instruction_emul.c mevent.c +SRCS+= instruction_emul.c ioapic.c mevent.c SRCS+= pci_emul.c pci_hostbridge.c pci_passthru.c pci_virtio_block.c SRCS+= pci_virtio_net.c pci_uart.c pit_8254.c post.c rtc.c uart.c xmsr.c diff --git a/usr.sbin/bhyve/fbsdrun.c b/usr.sbin/bhyve/fbsdrun.c index cb34477246c6..b988b1f459cd 100644 --- a/usr.sbin/bhyve/fbsdrun.c +++ b/usr.sbin/bhyve/fbsdrun.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include "pci_emul.h" #include "xmsr.h" #include "instruction_emul.h" +#include "ioapic.h" #define DEFAULT_GUEST_HZ 100 #define DEFAULT_GUEST_TSLICE 200 @@ -651,6 +652,8 @@ main(int argc, char *argv[]) init_inout(); init_pci(ctx); + if (ioapic) + ioapic_init(0); if (gdb_port != 0) init_dbgport(gdb_port); diff --git a/usr.sbin/bhyve/ioapic.c b/usr.sbin/bhyve/ioapic.c new file mode 100644 index 000000000000..dc74cfa9ce6f --- /dev/null +++ b/usr.sbin/bhyve/ioapic.c @@ -0,0 +1,302 @@ +/*- + * 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 "inout.h" +#include "instruction_emul.h" +#include "fbsdrun.h" + +#include + +#define IOAPIC_PADDR 0xFEC00000 + +#define IOREGSEL 0x00 +#define IOWIN 0x10 + +#define REDIR_ENTRIES 16 +#define INTR_ASSERTED(ioapic, pin) ((ioapic)->pinstate[(pin)] == true) + +struct ioapic { + int inited; + uint32_t id; + uint64_t redtbl[REDIR_ENTRIES]; + bool pinstate[REDIR_ENTRIES]; + + uintptr_t paddr; /* gpa where the ioapic is mapped */ + uint32_t ioregsel; + struct memory_region *region; +}; + +static struct ioapic ioapics[1]; /* only a single ioapic for now */ + +static int ioapic_region_read(struct vmctx *vm, int vcpu, uintptr_t paddr, + int size, uint64_t *data, void *arg); +static int ioapic_region_write(struct vmctx *vm, int vcpu, uintptr_t paddr, + int size, uint64_t data, void *arg); + +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 */ + + if (pin < 0 || pin >= REDIR_ENTRIES) + return; + + /* Nothing to do if interrupt pin has not changed state */ + if (ioapic->pinstate[pin] == newstate) + return; + + ioapic->pinstate[pin] = 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 + * - physical destination mode + * - fixed delivery mode + */ + low = ioapic->redtbl[pin]; + high = ioapic->redtbl[pin] >> 32; + if ((low & IOART_INTMASK) == IOART_INTMCLR && + (low & IOART_TRGRMOD) == IOART_TRGREDG && + (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++; + } + } + } +} + +void +ioapic_deassert_pin(struct vmctx *ctx, int pin) +{ + ioapic_set_pinstate(ctx, pin, false); +} + +void +ioapic_assert_pin(struct vmctx *ctx, int pin) +{ + ioapic_set_pinstate(ctx, pin, true); +} + +void +ioapic_init(int which) +{ + int i; + struct ioapic *ioapic; + + assert(which == 0); + + ioapic = &ioapics[which]; + assert(ioapic->inited == 0); + + bzero(ioapic, sizeof(struct ioapic)); + + /* Initialize all redirection entries to mask all interrupts */ + for (i = 0; i < REDIR_ENTRIES; i++) + ioapic->redtbl[i] = 0x0001000000010000UL; + + /* Register emulated memory region */ + ioapic->paddr = IOAPIC_PADDR; + ioapic->region = register_emulated_memory(ioapic->paddr, + sizeof(struct IOAPIC), + ioapic_region_read, + ioapic_region_write, + (void *)(uintptr_t)which); + assert(ioapic->region != NULL); + + 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->redtbl[pin] >> rshift); + } + + return (0); +} + +static void +ioapic_write(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->redtbl[pin] &= ~((uint64_t)0xffffffff << lshift); + ioapic->redtbl[pin] |= ((uint64_t)data << lshift); + } +} + +static int +ioapic_region_read(struct vmctx *vm, int vcpu, uintptr_t paddr, int size, + uint64_t *data, void *arg) +{ + int which, offset; + struct ioapic *ioapic; + + which = (uintptr_t)arg; + + ioapic = &ioapics[which]; + 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", + which, 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, int vcpu, uintptr_t paddr, int size, + uint64_t data, void *arg) +{ + int which, offset; + struct ioapic *ioapic; + + which = (uintptr_t)arg; + + ioapic = &ioapics[which]; + 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", + which, size, offset); +#endif + return (0); + } + + if (offset == IOREGSEL) + ioapic->ioregsel = data; + else + ioapic_write(ioapic, ioapic->ioregsel, data); + + return (0); +} diff --git a/usr.sbin/bhyve/ioapic.h b/usr.sbin/bhyve/ioapic.h new file mode 100644 index 000000000000..4696f9a55274 --- /dev/null +++ b/usr.sbin/bhyve/ioapic.h @@ -0,0 +1,38 @@ +/*- + * 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 diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c index faaea73a98db..5f8436c005ec 100644 --- a/usr.sbin/bhyve/pci_emul.c +++ b/usr.sbin/bhyve/pci_emul.c @@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$"); #include "inout.h" #include "pci_emul.h" #include "instruction_emul.h" +#include "ioapic.h" #define CONF1_ADDR_PORT 0x0cf8 #define CONF1_DATA_PORT 0x0cfc @@ -835,7 +836,7 @@ pci_lintr_assert(struct pci_devinst *pi) { assert(pi->pi_lintr_pin); - /* ioapic_assert_pin(pi->pi_vmctx, pi->pi_lintr_pin); */ + ioapic_assert_pin(pi->pi_vmctx, pi->pi_lintr_pin); } void @@ -843,7 +844,7 @@ pci_lintr_deassert(struct pci_devinst *pi) { assert(pi->pi_lintr_pin); - /* ioapic_deassert_pin(pi->pi_vmctx, pi->pi_lintr_pin); */ + ioapic_deassert_pin(pi->pi_vmctx, pi->pi_lintr_pin); }