Split up the IOAPIC analogously to APIC and i8259. KVM will share the device description, reset logic and certain init parts with the user space model.
Signed-off-by: Jan Kiszka <jan.kis...@siemens.com> --- Makefile.target | 2 +- hw/ioapic.c | 130 ++++------------------------------------------- hw/ioapic_common.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/ioapic_internal.h | 105 ++++++++++++++++++++++++++++++++++++++ hw/pc_piix.c | 1 + 5 files changed, 254 insertions(+), 121 deletions(-) create mode 100644 hw/ioapic_common.c create mode 100644 hw/ioapic_internal.h diff --git a/Makefile.target b/Makefile.target index c46f062..b549988 100644 --- a/Makefile.target +++ b/Makefile.target @@ -231,7 +231,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o # Hardware support obj-i386-y += vga.o obj-i386-y += mc146818rtc.o pc.o -obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic.o piix_pci.o +obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o obj-i386-y += vmport.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o diff --git a/hw/ioapic.c b/hw/ioapic.c index 27b07c6..2db72e0 100644 --- a/hw/ioapic.c +++ b/hw/ioapic.c @@ -24,9 +24,7 @@ #include "pc.h" #include "apic.h" #include "ioapic.h" -#include "qemu-timer.h" -#include "host-utils.h" -#include "sysbus.h" +#include "ioapic_internal.h" //#define DEBUG_IOAPIC @@ -37,62 +35,6 @@ #define DPRINTF(fmt, ...) #endif -#define MAX_IOAPICS 1 - -#define IOAPIC_VERSION 0x11 - -#define IOAPIC_LVT_DEST_SHIFT 56 -#define IOAPIC_LVT_MASKED_SHIFT 16 -#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15 -#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14 -#define IOAPIC_LVT_POLARITY_SHIFT 13 -#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12 -#define IOAPIC_LVT_DEST_MODE_SHIFT 11 -#define IOAPIC_LVT_DELIV_MODE_SHIFT 8 - -#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT) -#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT) - -#define IOAPIC_TRIGGER_EDGE 0 -#define IOAPIC_TRIGGER_LEVEL 1 - -/*io{apic,sapic} delivery mode*/ -#define IOAPIC_DM_FIXED 0x0 -#define IOAPIC_DM_LOWEST_PRIORITY 0x1 -#define IOAPIC_DM_PMI 0x2 -#define IOAPIC_DM_NMI 0x4 -#define IOAPIC_DM_INIT 0x5 -#define IOAPIC_DM_SIPI 0x6 -#define IOAPIC_DM_EXTINT 0x7 -#define IOAPIC_DM_MASK 0x7 - -#define IOAPIC_VECTOR_MASK 0xff - -#define IOAPIC_IOREGSEL 0x00 -#define IOAPIC_IOWIN 0x10 - -#define IOAPIC_REG_ID 0x00 -#define IOAPIC_REG_VER 0x01 -#define IOAPIC_REG_ARB 0x02 -#define IOAPIC_REG_REDTBL_BASE 0x10 -#define IOAPIC_ID 0x00 - -#define IOAPIC_ID_SHIFT 24 -#define IOAPIC_ID_MASK 0xf - -#define IOAPIC_VER_ENTRIES_SHIFT 16 - -typedef struct IOAPICState IOAPICState; - -struct IOAPICState { - SysBusDevice busdev; - MemoryRegion io_memory; - uint8_t id; - uint8_t ioregsel; - uint32_t irr; - uint64_t ioredtbl[IOAPIC_NUM_PINS]; -}; - static IOAPICState *ioapics[MAX_IOAPICS]; static void ioapic_service(IOAPICState *s) @@ -278,83 +220,31 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val, } } -static int ioapic_post_load(void *opaque, int version_id) -{ - IOAPICState *s = opaque; - - if (version_id == 1) { - /* set sane value */ - s->irr = 0; - } - return 0; -} - -static const VMStateDescription vmstate_ioapic = { - .name = "ioapic", - .version_id = 3, - .post_load = ioapic_post_load, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8(id, IOAPICState), - VMSTATE_UINT8(ioregsel, IOAPICState), - VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */ - VMSTATE_UINT32_V(irr, IOAPICState, 2), - VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS), - VMSTATE_END_OF_LIST() - } -}; - -static void ioapic_reset(DeviceState *d) -{ - IOAPICState *s = DO_UPCAST(IOAPICState, busdev.qdev, d); - int i; - - s->id = 0; - s->ioregsel = 0; - s->irr = 0; - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT; - } -} - static const MemoryRegionOps ioapic_io_ops = { .read = ioapic_mem_read, .write = ioapic_mem_write, .endianness = DEVICE_NATIVE_ENDIAN, }; -static int ioapic_init1(SysBusDevice *dev) +static void ioapic_backend_init(IOAPICState *s, int index) { - IOAPICState *s = FROM_SYSBUS(IOAPICState, dev); - static int ioapic_no; - - if (ioapic_no >= MAX_IOAPICS) { - return -1; - } - memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000); - sysbus_init_mmio(dev, &s->io_memory); - - qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS); - ioapics[ioapic_no++] = s; + qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS); - return 0; + ioapics[index] = s; } -static SysBusDeviceInfo ioapic_info = { - .init = ioapic_init1, - .qdev.name = "ioapic", - .qdev.size = sizeof(IOAPICState), - .qdev.vmsd = &vmstate_ioapic, - .qdev.reset = ioapic_reset, - .qdev.no_user = 1, +static IOAPICBackend ioapic_backend = { + .name = "QEMU", + .init = ioapic_backend_init, + .reset = ioapic_reset_internal, }; static void ioapic_register_devices(void) { - sysbus_register_withprop(&ioapic_info); + ioapic_register_device(); + ioapic_register_backend(&ioapic_backend); } device_init(ioapic_register_devices) diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c new file mode 100644 index 0000000..094551c --- /dev/null +++ b/hw/ioapic_common.c @@ -0,0 +1,137 @@ +/* + * IOAPIC emulation logic - common bits of emulated and KVM kernel model + * + * Copyright (c) 2004-2005 Fabrice Bellard + * Copyright (c) 2009 Xiantao Zhang, Intel + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "ioapic.h" +#include "ioapic_internal.h" +#include "sysbus.h" + +static QSIMPLEQ_HEAD(, IOAPICBackend) backends = + QSIMPLEQ_HEAD_INITIALIZER(backends); + +void ioapic_reset_internal(IOAPICState *s) +{ + int i; + + s->id = 0; + s->ioregsel = 0; + s->irr = 0; + for (i = 0; i < IOAPIC_NUM_PINS; i++) { + s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT; + } +} + +static void ioapic_dispatch_pre_save(void *opaque) +{ + IOAPICState *s = opaque; + + if (s->backend->pre_save) { + s->backend->pre_save(s); + } +} + +static int ioapic_post_load(void *opaque, int version_id) +{ + IOAPICState *s = opaque; + + if (version_id == 1) { + /* set sane value */ + s->irr = 0; + } + if (s->backend->post_load) { + s->backend->post_load(s); + } + return 0; +} + +const VMStateDescription vmstate_ioapic = { + .name = "ioapic", + .version_id = 3, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = ioapic_dispatch_pre_save, + .post_load = ioapic_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT8(id, IOAPICState), + VMSTATE_UINT8(ioregsel, IOAPICState), + VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */ + VMSTATE_UINT32_V(irr, IOAPICState, 2), + VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS), + VMSTATE_END_OF_LIST() + } +}; + +static int ioapic_init(SysBusDevice *dev) +{ + IOAPICState *s = FROM_SYSBUS(IOAPICState, dev); + static int ioapic_no; + IOAPICBackend *b; + + if (ioapic_no >= MAX_IOAPICS) { + return -1; + } + + QSIMPLEQ_FOREACH(b, &backends, entry) { + if (strcmp(b->name, s->backend_name) == 0) { + s->backend = b; + break; + } + } + if (!s->backend) { + hw_error("IOAPIC backend '%s' not found!", s->backend_name); + exit(1); + } + + b->init(s, ioapic_no++); + + sysbus_init_mmio(&s->busdev, &s->io_memory); + + return 0; +} + +static void ioapic_reset(DeviceState *dev) +{ + IOAPICState *s = DO_UPCAST(IOAPICState, busdev.qdev, dev); + + s->backend->reset(s); +} + +static SysBusDeviceInfo ioapic_info = { + .init = ioapic_init, + .qdev.name = "ioapic", + .qdev.size = sizeof(IOAPICState), + .qdev.vmsd = &vmstate_ioapic, + .qdev.reset = ioapic_reset, + .qdev.no_user = 1, + .qdev.props = (Property[]) { + DEFINE_PROP_STRING("backend", IOAPICState, backend_name), + DEFINE_PROP_END_OF_LIST(), + }, +}; + +void ioapic_register_backend(IOAPICBackend *backend) +{ + QSIMPLEQ_INSERT_TAIL(&backends, backend, entry); +} + +void ioapic_register_device(void) +{ + sysbus_register_withprop(&ioapic_info); +} diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h new file mode 100644 index 0000000..c5fab8b --- /dev/null +++ b/hw/ioapic_internal.h @@ -0,0 +1,105 @@ +/* + * IOAPIC emulation logic - internal interfaces + * + * Copyright (c) 2004-2005 Fabrice Bellard + * Copyright (c) 2009 Xiantao Zhang, Intel + * Copyright (c) 2011 Jan Kiszka, Siemens AG + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef QEMU_IOAPIC_INTERNAL_H +#define QEMU_IOAPIC_INTERNAL_H + +#include "hw.h" +#include "memory.h" +#include "sysbus.h" +#include "qemu-queue.h" + +#define MAX_IOAPICS 1 + +#define IOAPIC_VERSION 0x11 + +#define IOAPIC_LVT_DEST_SHIFT 56 +#define IOAPIC_LVT_MASKED_SHIFT 16 +#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15 +#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14 +#define IOAPIC_LVT_POLARITY_SHIFT 13 +#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12 +#define IOAPIC_LVT_DEST_MODE_SHIFT 11 +#define IOAPIC_LVT_DELIV_MODE_SHIFT 8 + +#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT) +#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT) + +#define IOAPIC_TRIGGER_EDGE 0 +#define IOAPIC_TRIGGER_LEVEL 1 + +/*io{apic,sapic} delivery mode*/ +#define IOAPIC_DM_FIXED 0x0 +#define IOAPIC_DM_LOWEST_PRIORITY 0x1 +#define IOAPIC_DM_PMI 0x2 +#define IOAPIC_DM_NMI 0x4 +#define IOAPIC_DM_INIT 0x5 +#define IOAPIC_DM_SIPI 0x6 +#define IOAPIC_DM_EXTINT 0x7 +#define IOAPIC_DM_MASK 0x7 + +#define IOAPIC_VECTOR_MASK 0xff + +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 + +#define IOAPIC_REG_ID 0x00 +#define IOAPIC_REG_VER 0x01 +#define IOAPIC_REG_ARB 0x02 +#define IOAPIC_REG_REDTBL_BASE 0x10 +#define IOAPIC_ID 0x00 + +#define IOAPIC_ID_SHIFT 24 +#define IOAPIC_ID_MASK 0xf + +#define IOAPIC_VER_ENTRIES_SHIFT 16 + +typedef struct IOAPICBackend IOAPICBackend; +typedef struct IOAPICState IOAPICState; + +struct IOAPICBackend { + const char *name; + void (*init)(IOAPICState *s, int index); + void (*reset)(IOAPICState *s); + void (*pre_save)(IOAPICState *s); + void (*post_load)(IOAPICState *s); + + QSIMPLEQ_ENTRY(IOAPICBackend) entry; +}; + +struct IOAPICState { + SysBusDevice busdev; + MemoryRegion io_memory; + uint8_t id; + uint8_t ioregsel; + uint32_t irr; + uint64_t ioredtbl[IOAPIC_NUM_PINS]; + + char *backend_name; + IOAPICBackend *backend; +}; + +void ioapic_register_device(void); +void ioapic_register_backend(IOAPICBackend *backend); + +void ioapic_reset_internal(IOAPICState *s); + +#endif /* !QEMU_IOAPIC_INTERNAL_H */ diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 530fe9c..98f2822 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -60,6 +60,7 @@ static void ioapic_init(GSIState *gsi_state) unsigned int i; dev = qdev_create(NULL, "ioapic"); + qdev_prop_set_string(dev, "backend", g_strdup("QEMU")); qdev_init_nofail(dev); d = sysbus_from_qdev(dev); sysbus_mmio_map(d, 0, 0xfec00000); -- 1.7.3.4