Patchwork [v5,1/3] eliminate piix_pci.c and module i440fx and piix3

login
register
mail settings
Submitter Wanpeng Li
Date Nov. 8, 2012, 5:36 a.m.
Message ID <1352352972-2510-2-git-send-email-liwanp@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/197767/
State New
Headers show

Comments

Wanpeng Li - Nov. 8, 2012, 5:36 a.m.
The big picture about the patch is shown as follows:

1) pc_init creates an I440FX, any bus devices (ISA serial port, PCI
vga and nics, etc.), sets properties appropriately, and realizes the
devices.
2) I440FX is-a PCIHost, has-a I440FX-PMC, has-a PIIX3

i440fx-pcihost => i440fx
i440fx => i440fx-pmc

i440fx_pmc is Programmable Memory Controller which integrated in I440FX
chipset, and move ram initialization into i440fx-pmc.

It might seem like a small change, but it better reflects the fact
that the PMC is contained within the i440fx which we will now reflect in
composition in the next few changesets.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Wanpeng Li <liwanp@linux.vnet.ibm.com>

---
 hw/i386/Makefile.objs |    2 +-
 hw/i440fx.c           |  434 ++++++++++++++++++++++++++++++++++
 hw/i440fx.h           |   76 ++++++
 hw/pc.c               |   39 +---
 hw/pc.h               |   20 +--
 hw/pc_piix.c          |   52 +++--
 hw/piix3.c            |  258 ++++++++++++++++++++
 hw/piix3.h            |   73 ++++++
 hw/piix_pci.c         |  622 -------------------------------------------------
 9 files changed, 882 insertions(+), 694 deletions(-)
 create mode 100644 hw/i440fx.c
 create mode 100644 hw/i440fx.h
 create mode 100644 hw/piix3.c
 create mode 100644 hw/piix3.h
 delete mode 100644 hw/piix_pci.c

Patch

diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index 8c764bb..49b32d0 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -1,6 +1,6 @@ 
 obj-y += mc146818rtc.o pc.o
 obj-y += apic_common.o apic.o kvmvapic.o
-obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o
+obj-y += sga.o ioapic_common.o ioapic.o i440fx.o piix3.o
 obj-y += vmport.o
 obj-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-y += debugcon.o multiboot.o
diff --git a/hw/i440fx.c b/hw/i440fx.c
new file mode 100644
index 0000000..235dab6
--- /dev/null
+++ b/hw/i440fx.c
@@ -0,0 +1,434 @@ 
+/*
+ * QEMU i440FX PCI Host Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "i440fx.h"
+#include "range.h"
+#include "xen.h"
+#include "loader.h"
+#include "pc.h"
+
+#define BIOS_FILENAME "bios.bin"
+
+/*
+ * I440FX chipset data sheet.
+ * http://download.intel.com/design/chipsets/datashts/29054901.pdf
+ *
+ * The I440FX is a package that contains an integrated PCI Host controller,
+ * memory controller, and is usually packaged with a PCI-ISA bus and super I/O
+ * chipset.
+ *
+ * The "i440FX" device is the PCI host controller.  On function 0.0, there is a
+ * memory controller called the Programmable Memory Controller (PMC).  On
+ * function 1.0, there is the PCI-ISA bus/super I/O chip called the PIIX3.
+ */
+
+#define I440FX_PMC_PCI_HOLE     0xE0000000ULL
+#define I440FX_PMC_PCI_HOLE_END 0x100000000ULL
+
+#define I440FX_PAM      0x59
+#define I440FX_PAM_SIZE 7
+#define I440FX_SMRAM    0x72
+
+/*
+ * return the global irq number corresponding to a given device irq
+ * pin. We could also use the bus number to have a more precise
+ * mapping.
+ */
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
+{
+    int slot_addend;
+    slot_addend = (pci_dev->devfn >> 3) - 1;
+    return (pci_intx + slot_addend) & 3;
+}
+
+static void init_pam(I440FXPMCState *d, PAMMemoryRegion *mem,
+                     uint32_t start, uint32_t size)
+{
+    int i;
+
+    /* RAM */
+    memory_region_init_alias(&mem->alias[3], "pam-ram",
+                                           d->ram_memory, start, size);
+    /* ROM (XXX: not quite correct) */
+    memory_region_init_alias(&mem->alias[1], "pam-rom",
+                                           d->ram_memory, start, size);
+    memory_region_set_readonly(&mem->alias[1], true);
+
+    /* XXX: should distinguish read/write cases */
+    memory_region_init_alias(&mem->alias[0], "pam-pci", d->pci_address_space,
+                             start, size);
+    memory_region_init_alias(&mem->alias[2], "pam-pci", d->pci_address_space,
+                             start, size);
+
+    for (i = 0; i < 4; ++i) {
+        memory_region_set_enabled(&mem->alias[i], false);
+        memory_region_add_subregion_overlap(d->system_memory,
+                                                  start, &mem->alias[i], 1);
+    }
+    mem->current = 0;
+}
+
+static void update_pam(PAMMemoryRegion *pam, unsigned r)
+{
+    memory_region_set_enabled(&pam->alias[pam->current], false);
+    pam->current = r;
+    memory_region_set_enabled(&pam->alias[pam->current], true);
+}
+
+static void i440fx_pmc_update_memory_mappings(I440FXPMCState *d)
+{
+    int i, r;
+    uint32_t smram;
+    bool smram_enabled;
+
+    memory_region_transaction_begin();
+    update_pam(&d->pam_regions[0], (d->dev.config[I440FX_PAM] >> 4) & 3);
+    for (i = 0; i < 12; i++) {
+        r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3;
+        update_pam(&d->pam_regions[i+1], r);
+    }
+    smram = d->dev.config[I440FX_SMRAM];
+    smram_enabled = (d->smm_enabled && (smram & 0x08)) || (smram & 0x40);
+    memory_region_set_enabled(&d->smram_region, !smram_enabled);
+    memory_region_transaction_commit();
+}
+
+static void i440fx_pmc_set_smm(int val, void *arg)
+{
+    I440FXPMCState *d = arg;
+
+    val = (val != 0);
+    if (d->smm_enabled != val) {
+        d->smm_enabled = val;
+        i440fx_pmc_update_memory_mappings(d);
+    }
+}
+
+
+static void i440fx_pmc_write_config(PCIDevice *dev,
+                                    uint32_t address, uint32_t val, int len)
+{
+    I440FXPMCState *d = DO_UPCAST(I440FXPMCState, dev, dev);
+
+    /* XXX: implement SMRAM.D_LOCK */
+    pci_default_write_config(dev, address, val, len);
+    if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
+        range_covers_byte(address, len, I440FX_SMRAM)) {
+        i440fx_pmc_update_memory_mappings(d);
+    }
+}
+
+static int i440fx_pmc_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    I440FXPMCState *d = opaque;
+    int ret, i;
+
+    ret = pci_device_load(&d->dev, f);
+    if (ret < 0) {
+        return ret;
+    }
+    i440fx_pmc_update_memory_mappings(d);
+    qemu_get_8s(f, &d->smm_enabled);
+
+    if (version_id == 2) {
+        for (i = 0; i < PIIX_NUM_PIRQS; i++) {
+            qemu_get_be32(f); /* dummy load for compatibility */
+        }
+    }
+
+    return 0;
+}
+
+static int i440fx_pmc_post_load(void *opaque, int version_id)
+{
+    I440FXPMCState *d = opaque;
+
+    i440fx_pmc_update_memory_mappings(d);
+    return 0;
+}
+
+static const VMStateDescription vmstate_i440fx_pmc = {
+    .name = "I440FX", /* this is wrong but we can't change it */
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = i440fx_pmc_load_old,
+    .post_load = i440fx_pmc_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, I440FXPMCState),
+        VMSTATE_UINT8(smm_enabled, I440FXPMCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int i440fx_realize(SysBusDevice *dev)
+{
+    I440FXState *s = I440FX(dev);
+    PCIHostState *h = PCI_HOST_BRIDGE(s);
+    int bios_size, isa_bios_size;
+    char *filename;
+    int ret;
+
+    g_assert(h->address_space != NULL);
+    g_assert(s->address_space_io != NULL);
+
+    h->bus = pci_bus_new(DEVICE(s), NULL, &s->pci_address_space,
+                         s->address_space_io, 0);
+
+    memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, s,
+                          "pci-conf-idx", 4);
+    sysbus_add_io(dev, 0xcf8, &h->conf_mem);
+    sysbus_init_ioports(&h->busdev, 0xcf8, 4);
+
+    memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, s,
+                          "pci-conf-data", 4);
+    sysbus_add_io(dev, 0xcfc, &h->data_mem);
+    sysbus_init_ioports(&h->busdev, 0xcfc, 4);
+
+    s->pmc.system_memory = h->address_space;
+    s->pmc.pci_address_space = &s->pci_address_space;
+
+    qdev_set_parent_bus(DEVICE(&s->pmc), BUS(h->bus));
+    qdev_init_nofail(DEVICE(&s->pmc));
+
+    qdev_set_parent_bus(DEVICE(&s->piix3), BUS(h->bus));
+    qdev_init_nofail(DEVICE(&s->piix3));
+
+    if (xen_enabled()) {
+        pci_bus_irqs(h->bus, xen_piix3_set_irq, xen_pci_slot_get_pirq,
+                     &s->piix3, XEN_PIIX_NUM_PIRQS);
+    } else {
+        pci_bus_irqs(h->bus, piix3_set_irq, pci_slot_get_pirq, &s->piix3,
+                PIIX_NUM_PIRQS);
+        pci_bus_set_route_irq_fn(h->bus, piix3_route_intx_pin_to_irq);
+    }
+
+    /* BIOS load */
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name);
+    if (filename) {
+        bios_size = get_image_size(filename);
+    } else {
+        bios_size = -1;
+    }
+    if (bios_size <= 0 ||
+        (bios_size % 65536) != 0) {
+        goto bios_error;
+    }
+    memory_region_init_ram(&s->bios, "pc.bios", bios_size);
+    vmstate_register_ram_global(&s->bios);
+    memory_region_set_readonly(&s->bios, true);
+    ret = rom_add_file_fixed(s->bios_name, (uint32_t)(-bios_size), -1);
+    if (ret != 0) {
+    bios_error:
+        fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", s->bios_name);
+        exit(1);
+    }
+    if (filename) {
+        g_free(filename);
+    }
+
+    /* map the last 128KB of the BIOS in ISA space */
+    isa_bios_size = bios_size;
+    if (isa_bios_size > (128 * 1024)) {
+        isa_bios_size = 128 * 1024;
+    }
+    memory_region_init_alias(&s->isa_bios, "isa-bios", &s->bios,
+                             bios_size - isa_bios_size, isa_bios_size);
+    memory_region_add_subregion_overlap(&s->pci_address_space,
+                                        0x100000 - isa_bios_size,
+                                        &s->isa_bios,
+                                        1);
+    memory_region_set_readonly(&s->isa_bios, true);
+
+    memory_region_init_ram(&s->option_roms, "pc.rom", PC_ROM_SIZE);
+    vmstate_register_ram_global(&s->option_roms);
+    memory_region_add_subregion_overlap(&s->pci_address_space,
+                                        PC_ROM_MIN_VGA,
+                                        &s->option_roms,
+                                        1);
+
+    /* map all the bios at the top of memory */
+    memory_region_add_subregion(&s->pci_address_space,
+                                (uint32_t)(-bios_size),
+                                &s->bios);
+
+    return 0;
+}
+
+static void i440fx_initfn(Object *obj)
+{
+    I440FXState *s = I440FX(obj);
+
+    object_initialize(&s->pmc, TYPE_I440FX_PMC);
+    object_property_add_child(obj, "pmc", OBJECT(&s->pmc), NULL);
+    qdev_prop_set_uint32(DEVICE(&s->pmc), "addr", PCI_DEVFN(0, 0));
+
+    /* Xen supports additional interrupt routes from the PCI devices to
+     * the IOAPIC: the four pins of each PCI device on the bus are also
+     * connected to the IOAPIC directly.
+     * These additional routes can be discovered through ACPI. */
+    if (xen_enabled()) {
+        object_initialize(&s->piix3, "PIIX3-xen");
+    } else {
+        object_initialize(&s->piix3, "PIIX3");
+    }
+    object_property_add_child(OBJECT(s), "piix3", OBJECT(&s->piix3), NULL);
+
+    s->bios_name = g_strdup(BIOS_FILENAME);
+
+    memory_region_init(&s->pci_address_space, "pci", INT64_MAX);
+}
+
+static int i440fx_pmc_realize(PCIDevice *dev)
+{
+    int i;
+    I440FXPMCState *d = DO_UPCAST(I440FXPMCState, dev, dev);
+    ram_addr_t ram_size;
+    uint64_t below_4g_mem_size, above_4g_mem_size;
+    uint64_t pci_hole_start, pci_hole_size;
+    uint64_t pci_hole64_start, pci_hole64_size;
+
+    g_assert(d->ram_size != 0);
+    g_assert(d->system_memory != NULL);
+    g_assert(d->pci_address_space != NULL);
+
+    /* Calculate memory geometry from RAM size */
+    if (d->ram_size > I440FX_PMC_PCI_HOLE) {
+        below_4g_mem_size = I440FX_PMC_PCI_HOLE;
+        above_4g_mem_size = d->ram_size - I440FX_PMC_PCI_HOLE;
+    } else {
+        below_4g_mem_size = d->ram_size;
+        above_4g_mem_size = 0;
+    }
+
+    /* Allocate RAM.  We allocate it as a single memory region and use
+     * aliases to address portions of it, mostly for backwards compatibility
+     * with older qemus that used qemu_ram_alloc().
+     */
+    memory_region_init_ram(&d->ram, "pc.ram",
+                           below_4g_mem_size + above_4g_mem_size);
+    vmstate_register_ram_global(&d->ram);
+
+    memory_region_init_alias(&d->ram_below_4g, "ram-below-4g", &d->ram,
+                             0, below_4g_mem_size);
+    memory_region_add_subregion(d->system_memory, 0, &d->ram_below_4g);
+    if (above_4g_mem_size > 0) {
+        memory_region_init_alias(&d->ram_above_4g, "ram-above-4g", &d->ram,
+                                 below_4g_mem_size, above_4g_mem_size);
+        memory_region_add_subregion(d->system_memory, 0x100000000ULL,
+                                    &d->ram_above_4g);
+    }
+
+    pci_hole_start = below_4g_mem_size;
+    pci_hole_size = I440FX_PMC_PCI_HOLE_END - pci_hole_start;
+
+    pci_hole64_start = I440FX_PMC_PCI_HOLE_END + d->ram_size - pci_hole_start;
+    if (sizeof(hwaddr) == 4) {
+        pci_hole64_size = 0;
+    } else {
+        pci_hole64_size = (1ULL << 62);
+    }
+
+    memory_region_init_alias(&d->pci_hole, "pci-hole", d->pci_address_space,
+                             pci_hole_start, pci_hole_size);
+    memory_region_add_subregion(d->system_memory, pci_hole_start, &d->pci_hole);
+    memory_region_init_alias(&d->pci_hole_64bit, "pci-hole64",
+                             d->pci_address_space,
+                             pci_hole64_start, pci_hole64_size);
+    if (pci_hole64_size) {
+        memory_region_add_subregion(d->system_memory, pci_hole64_start,
+                                    &d->pci_hole_64bit);
+    }
+    memory_region_init_alias(&d->smram_region, "smram-region",
+                             d->pci_address_space, 0xa0000, 0x20000);
+    memory_region_add_subregion_overlap(d->system_memory, 0xa0000,
+                                        &d->smram_region, 1);
+    memory_region_set_enabled(&d->smram_region, false);
+    init_pam(d, &d->pam_regions[0], 0xf0000, 0x10000);
+    for (i = 0; i < 12; ++i) {
+        init_pam(d, &d->pam_regions[i+1], 0xc0000 + i * 0x4000, 0x4000);
+    }
+
+    ram_size = d->ram_size / 8 / 1024 / 1024;
+    if (ram_size > 255) {
+        ram_size = 255;
+    }
+    d->dev.config[0x57] = ram_size;
+
+    i440fx_pmc_update_memory_mappings(d);
+
+    d->dev.config[I440FX_SMRAM] = 0x02;
+
+    cpu_smm_register(&i440fx_pmc_set_smm, d);
+    return 0;
+}
+
+static void i440fx_pmc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->no_hotplug = 1;
+    k->init = i440fx_pmc_realize;
+    k->config_write = i440fx_pmc_write_config;
+    k->vendor_id = PCI_VENDOR_ID_INTEL;
+    k->device_id = PCI_DEVICE_ID_INTEL_82441;
+    k->class_id = PCI_CLASS_BRIDGE_HOST;
+    k->revision = 0x02;
+    dc->desc = "Host bridge";
+    dc->no_user = 1;
+    dc->vmsd = &vmstate_i440fx_pmc;
+}
+
+static TypeInfo i440fx_pmc_info = {
+    .name          = TYPE_I440FX_PMC,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(I440FXPMCState),
+    .class_init    = i440fx_pmc_class_init,
+};
+
+static void i440fx_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = i440fx_realize;
+    dc->fw_name = "pci";
+    dc->no_user = 1;
+}
+
+static TypeInfo i440fx_info = {
+    .name          = TYPE_I440FX,
+    .parent        = TYPE_PCI_HOST_BRIDGE,
+    .instance_size = sizeof(I440FXState),
+    .instance_init = i440fx_initfn,
+    .class_init    = i440fx_class_init,
+};
+
+static void register_devices(void)
+{
+    type_register_static(&i440fx_info);
+    type_register_static(&i440fx_pmc_info);
+}
+type_init(register_devices);
diff --git a/hw/i440fx.h b/hw/i440fx.h
new file mode 100644
index 0000000..9c578ae
--- /dev/null
+++ b/hw/i440fx.h
@@ -0,0 +1,76 @@ 
+/*
+ * QEMU i440FX PCI Host Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I440FX_H
+#define QEMU_I440FX_H
+
+#include "pci_host.h"
+#include "piix3.h"
+#include "pci_internals.h"
+
+#define TYPE_I440FX_PMC "i440FX-PMC"
+#define I440FX_PMC(obj) OBJECT_CHECK(I440FXPMCState, (obj), TYPE_I440FX_PMC)
+
+typedef struct PAMMemoryRegion {
+    MemoryRegion alias[4];  /* index = PAM value */
+    unsigned current;
+} PAMMemoryRegion;
+
+typedef struct I440FXPMCState {
+    PCIDevice dev;
+    MemoryRegion *system_memory;
+    MemoryRegion *pci_address_space;
+    MemoryRegion *ram_memory;
+    MemoryRegion pci_hole;
+    MemoryRegion pci_hole_64bit;
+    PAMMemoryRegion pam_regions[13];
+    MemoryRegion smram_region;
+    uint8_t smm_enabled;
+
+    ram_addr_t ram_size;
+    MemoryRegion ram;
+    MemoryRegion ram_below_4g;
+    MemoryRegion ram_above_4g;
+} I440FXPMCState;
+
+#define TYPE_I440FX "i440FX"
+#define I440FX(obj) OBJECT_CHECK(I440FXState, (obj), TYPE_I440FX)
+
+typedef struct I440FXState {
+    PCIHostState parent;
+
+    MemoryRegion *address_space_io;
+    MemoryRegion pci_address_space;
+
+    I440FXPMCState pmc;
+    PIIX3State piix3;
+
+    MemoryRegion bios;
+    MemoryRegion isa_bios;
+    MemoryRegion option_roms;
+
+    char *bios_name;
+} I440FXState;
+
+#endif
diff --git a/hw/pc.c b/hw/pc.c
index 4aca498..60919e4 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -882,50 +882,13 @@  void *pc_memory_init(MemoryRegion *system_memory,
                     const char *kernel_cmdline,
                     const char *initrd_filename,
                     ram_addr_t below_4g_mem_size,
-                    ram_addr_t above_4g_mem_size,
-                    MemoryRegion *rom_memory,
-                    MemoryRegion **ram_memory)
+                    ram_addr_t above_4g_mem_size)
 {
     int linux_boot, i;
-    MemoryRegion *ram, *option_rom_mr;
-    MemoryRegion *ram_below_4g, *ram_above_4g;
     void *fw_cfg;
 
     linux_boot = (kernel_filename != NULL);
 
-    /* Allocate RAM.  We allocate it as a single memory region and use
-     * aliases to address portions of it, mostly for backwards compatibility
-     * with older qemus that used qemu_ram_alloc().
-     */
-    ram = g_malloc(sizeof(*ram));
-    memory_region_init_ram(ram, "pc.ram",
-                           below_4g_mem_size + above_4g_mem_size);
-    vmstate_register_ram_global(ram);
-    *ram_memory = ram;
-    ram_below_4g = g_malloc(sizeof(*ram_below_4g));
-    memory_region_init_alias(ram_below_4g, "ram-below-4g", ram,
-                             0, below_4g_mem_size);
-    memory_region_add_subregion(system_memory, 0, ram_below_4g);
-    if (above_4g_mem_size > 0) {
-        ram_above_4g = g_malloc(sizeof(*ram_above_4g));
-        memory_region_init_alias(ram_above_4g, "ram-above-4g", ram,
-                                 below_4g_mem_size, above_4g_mem_size);
-        memory_region_add_subregion(system_memory, 0x100000000ULL,
-                                    ram_above_4g);
-    }
-
-
-    /* Initialize PC system firmware */
-    pc_system_firmware_init(rom_memory);
-
-    option_rom_mr = g_malloc(sizeof(*option_rom_mr));
-    memory_region_init_ram(option_rom_mr, "pc.rom", PC_ROM_SIZE);
-    vmstate_register_ram_global(option_rom_mr);
-    memory_region_add_subregion_overlap(rom_memory,
-                                        PC_ROM_MIN_VGA,
-                                        option_rom_mr,
-                                        1);
-
     fw_cfg = bochs_bios_init();
     rom_set_fw(fw_cfg);
 
diff --git a/hw/pc.h b/hw/pc.h
index e7993ca..fb569d6 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -84,9 +84,7 @@  void *pc_memory_init(MemoryRegion *system_memory,
                     const char *kernel_cmdline,
                     const char *initrd_filename,
                     ram_addr_t below_4g_mem_size,
-                    ram_addr_t above_4g_mem_size,
-                    MemoryRegion *rom_memory,
-                    MemoryRegion **ram_memory);
+                    ram_addr_t above_4g_mem_size);
 qemu_irq *pc_allocate_cpu_irq(void);
 DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
 void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
@@ -121,22 +119,6 @@  void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 /* hpet.c */
 extern int no_hpet;
 
-/* piix_pci.c */
-struct PCII440FXState;
-typedef struct PCII440FXState PCII440FXState;
-
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
-                    ISABus **isa_bus, qemu_irq *pic,
-                    MemoryRegion *address_space_mem,
-                    MemoryRegion *address_space_io,
-                    ram_addr_t ram_size,
-                    hwaddr pci_hole_start,
-                    hwaddr pci_hole_size,
-                    hwaddr pci_hole64_start,
-                    hwaddr pci_hole64_size,
-                    MemoryRegion *pci_memory,
-                    MemoryRegion *ram_memory);
-
 /* piix4.c */
 extern PCIDevice *piix4_dev;
 int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn);
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index cfa839c..0fd25ac 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -43,6 +43,7 @@ 
 #include "xen.h"
 #include "memory.h"
 #include "exec-memory.h"
+#include "i440fx.h"
 #include "cpu.h"
 #ifdef CONFIG_XEN
 #  include <xen/hvm/hvm_info_table.h>
@@ -118,6 +119,40 @@  static void ioapic_init(GSIState *gsi_state)
     }
 }
 
+static PCIBus *i440fx_init(I440FXPMCState **pi440fx_state, int *piix3_devfn,
+                           ISABus **isa_bus, qemu_irq *pic,
+                           MemoryRegion *address_space_mem,
+                           MemoryRegion *address_space_io,
+                           ram_addr_t ram_size,
+                           const char *bios_name)
+{
+    I440FXState *s;
+    PCIHostState *h;
+
+    s = I440FX(object_new(TYPE_I440FX));
+    h = PCI_HOST_BRIDGE(s);
+
+    /* FIXME make a properties */
+    h->address_space = address_space_mem;
+    s->address_space_io = address_space_io;
+    s->piix3.pic = pic;
+    if (bios_name) {
+        g_free(s->bios_name);
+        s->bios_name = g_strdup(bios_name);
+    }
+    s->pmc.ram_size = ram_size;
+
+    qdev_set_parent_bus(DEVICE(s), sysbus_get_default());
+    object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(s), NULL);
+    qdev_init_nofail(DEVICE(s));
+
+    *isa_bus = s->piix3.bus;
+    *pi440fx_state = &s->pmc;
+    *piix3_devfn = s->piix3.dev.devfn;
+
+    return h->bus;
+}
+
 /* PC hardware initialisation */
 static void pc_init1(MemoryRegion *system_memory,
                      MemoryRegion *system_io,
@@ -134,7 +169,7 @@  static void pc_init1(MemoryRegion *system_memory,
     ram_addr_t below_4g_mem_size, above_4g_mem_size;
     PCIBus *pci_bus;
     ISABus *isa_bus;
-    PCII440FXState *i440fx_state;
+    I440FXPMCState *i440fx_state;
     int piix3_devfn = -1;
     qemu_irq *cpu_irq;
     qemu_irq *gsi;
@@ -145,9 +180,7 @@  static void pc_init1(MemoryRegion *system_memory,
     BusState *idebus[MAX_IDE_BUS];
     ISADevice *rtc_state;
     ISADevice *floppy;
-    MemoryRegion *ram_memory;
     MemoryRegion *pci_memory;
-    MemoryRegion *rom_memory;
     void *fw_cfg = NULL;
 
     pc_cpus_init(cpu_model);
@@ -167,18 +200,15 @@  static void pc_init1(MemoryRegion *system_memory,
     if (pci_enabled) {
         pci_memory = g_new(MemoryRegion, 1);
         memory_region_init(pci_memory, "pci", INT64_MAX);
-        rom_memory = pci_memory;
     } else {
         pci_memory = NULL;
-        rom_memory = system_memory;
     }
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
         fw_cfg = pc_memory_init(system_memory,
                        kernel_filename, kernel_cmdline, initrd_filename,
-                       below_4g_mem_size, above_4g_mem_size,
-                       rom_memory, &ram_memory);
+                       below_4g_mem_size, above_4g_mem_size);
     }
 
     gsi_state = g_malloc0(sizeof(*gsi_state));
@@ -193,13 +223,7 @@  static void pc_init1(MemoryRegion *system_memory,
     if (pci_enabled) {
         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
                               system_memory, system_io, ram_size,
-                              below_4g_mem_size,
-                              0x100000000ULL - below_4g_mem_size,
-                              0x100000000ULL + above_4g_mem_size,
-                              (sizeof(hwaddr) == 4
-                               ? 0
-                               : ((uint64_t)1 << 62)),
-                              pci_memory, ram_memory);
+                              bios_name);
     } else {
         pci_bus = NULL;
         i440fx_state = NULL;
diff --git a/hw/piix3.c b/hw/piix3.c
new file mode 100644
index 0000000..7d4145f
--- /dev/null
+++ b/hw/piix3.c
@@ -0,0 +1,258 @@ 
+/*
+ * QEMU PIIX3 PCI-ISA Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "piix3.h"
+#include "range.h"
+#include "kvm.h"
+#include "xen.h"
+#include "pc.h"
+#include "pcspk.h"
+
+void piix3_set_irq(void *opaque, int pirq, int level)
+{
+    PIIX3State *piix3 = opaque;
+    piix3_set_irq_level(piix3, pirq, level);
+}
+
+/* PIIX3 PCI to ISA bridge */
+static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
+{
+    qemu_set_irq(piix3->pic[pic_irq],
+                 !!(piix3->pic_levels &
+                    (((1ULL << PIIX_NUM_PIRQS) - 1) <<
+                     (pic_irq * PIIX_NUM_PIRQS))));
+}
+
+void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
+{
+    int pic_irq;
+    uint64_t mask;
+
+    pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
+    if (pic_irq >= PIIX_NUM_PIC_IRQS) {
+        return;
+    }
+
+    mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
+    piix3->pic_levels &= ~mask;
+    piix3->pic_levels |= mask * !!level;
+
+    piix3_set_irq_pic(piix3, pic_irq);
+}
+
+PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
+{
+    PIIX3State *piix3 = opaque;
+    int irq = piix3->dev.config[PIIX_PIRQC + pin];
+    PCIINTxRoute route;
+
+    if (irq < PIIX_NUM_PIC_IRQS) {
+        route.mode = PCI_INTX_ENABLED;
+        route.irq = irq;
+    } else {
+        route.mode = PCI_INTX_DISABLED;
+        route.irq = -1;
+    }
+    return route;
+}
+
+/* irq routing is changed. so rebuild bitmap */
+static void piix3_update_irq_levels(PIIX3State *piix3)
+{
+    int pirq;
+
+    pci_bus_fire_intx_routing_notifier(piix3->dev.bus);
+    piix3->pic_levels = 0;
+    for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
+        piix3_set_irq_level(piix3, pirq,
+                            pci_bus_get_irq_level(piix3->dev.bus, pirq));
+    }
+}
+
+static void piix3_write_config(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len)
+{
+    pci_default_write_config(dev, address, val, len);
+    if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
+        PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev);
+        int pic_irq;
+        piix3_update_irq_levels(piix3);
+        for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
+            piix3_set_irq_pic(piix3, pic_irq);
+        }
+    }
+}
+
+static void piix3_write_config_xen(PCIDevice *dev,
+                               uint32_t address, uint32_t val, int len)
+{
+    xen_piix_pci_write_config_client(address, val, len);
+    piix3_write_config(dev, address, val, len);
+}
+
+static void piix3_reset(DeviceState *dev)
+{
+    PIIX3State *d = PIIX3(dev);
+    uint8_t *pci_conf = d->dev.config;
+
+    /* master, memory and I/O */
+    pci_conf[0x04] = 0x07;
+    pci_conf[0x05] = 0x00;
+    pci_conf[0x06] = 0x00;
+    /* PCI_status_devsel_medium */
+    pci_conf[0x07] = 0x02;
+    pci_conf[0x4c] = 0x4d;
+    pci_conf[0x4e] = 0x03;
+    pci_conf[0x4f] = 0x00;
+    pci_conf[0x60] = 0x80;
+    pci_conf[0x61] = 0x80;
+    pci_conf[0x62] = 0x80;
+    pci_conf[0x63] = 0x80;
+    pci_conf[0x69] = 0x02;
+    pci_conf[0x70] = 0x80;
+    pci_conf[0x76] = 0x0c;
+    pci_conf[0x77] = 0x0c;
+    pci_conf[0x78] = 0x02;
+    pci_conf[0x79] = 0x00;
+    pci_conf[0x80] = 0x00;
+    pci_conf[0x82] = 0x00;
+    pci_conf[0xa0] = 0x08;
+    pci_conf[0xa2] = 0x00;
+    pci_conf[0xa3] = 0x00;
+    pci_conf[0xa4] = 0x00;
+    pci_conf[0xa5] = 0x00;
+    pci_conf[0xa6] = 0x00;
+    pci_conf[0xa7] = 0x00;
+    pci_conf[0xa8] = 0x0f;
+    pci_conf[0xaa] = 0x00;
+    pci_conf[0xab] = 0x00;
+    pci_conf[0xac] = 0x00;
+    pci_conf[0xae] = 0x00;
+
+    d->pic_levels = 0;
+}
+
+static int piix3_post_load(void *opaque, int version_id)
+{
+    PIIX3State *piix3 = opaque;
+    piix3_update_irq_levels(piix3);
+    return 0;
+}
+
+static void piix3_pre_save(void *opaque)
+{
+    int i;
+    PIIX3State *piix3 = opaque;
+
+    for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
+        piix3->pci_irq_levels_vmstate[i] =
+            pci_bus_get_irq_level(piix3->dev.bus, i);
+    }
+}
+
+static const VMStateDescription vmstate_piix3 = {
+    .name = TYPE_PIIX3,
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .post_load = piix3_post_load,
+    .pre_save = piix3_pre_save,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(dev, PIIX3State),
+        VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
+                              PIIX_NUM_PIRQS, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int piix3_realize(PCIDevice *dev)
+{
+    PIIX3State *s = PIIX3(dev);
+
+    /* Initialize ISA Bus */
+    s->bus = isa_bus_new(DEVICE(dev), pci_address_space_io(dev));
+    isa_bus_irqs(s->bus, s->pic);
+
+    return 0;
+}
+
+static void piix3_initfn(Object *obj)
+{
+    PIIX3State *s = PIIX3(obj);
+
+    qdev_prop_set_int32(DEVICE(s), "addr", PCI_DEVFN(1, 0));
+    qdev_prop_set_bit(DEVICE(s), "multifunction", true);
+
+}
+
+static void piix3_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    dc->desc        = "ISA bridge";
+    dc->vmsd        = &vmstate_piix3;
+    dc->no_user     = 1;
+    dc->reset       = piix3_reset;
+    k->no_hotplug   = 1;
+    k->init         = piix3_realize;
+    k->config_write = piix3_write_config;
+    k->vendor_id    = PCI_VENDOR_ID_INTEL;
+    /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
+    k->device_id    = PCI_DEVICE_ID_INTEL_82371SB_0;
+    k->class_id     = PCI_CLASS_BRIDGE_ISA;
+}
+
+static TypeInfo piix3_info = {
+    .name          = TYPE_PIIX3,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(PIIX3State),
+    .instance_init = piix3_initfn,
+    .class_init    = piix3_class_init,
+};
+
+static void piix3_xen_class_init(ObjectClass *klass, void *data)
+{
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->config_write = piix3_write_config_xen;
+};
+
+static TypeInfo piix3_xen_info = {
+    .name          = "PIIX3-xen",
+    .parent        = TYPE_PIIX3,
+    .instance_size = sizeof(PIIX3State),
+    .class_init    = piix3_xen_class_init,
+};
+
+static void register_devices(void)
+{
+    type_register_static(&piix3_info);
+    type_register_static(&piix3_xen_info);
+}
+type_init(register_devices)
diff --git a/hw/piix3.h b/hw/piix3.h
new file mode 100644
index 0000000..0fb04f2
--- /dev/null
+++ b/hw/piix3.h
@@ -0,0 +1,73 @@ 
+/*
+ * QEMU PIIX3 PCI-ISA Bridge Emulation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_PIIX3_H
+#define QEMU_PIIX3_H
+
+#include "pci.h"
+
+#define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
+#define PIIX_NUM_PIRQS          4ULL    /* PIRQ[A-D] */
+#define XEN_PIIX_NUM_PIRQS      128ULL
+#define PIIX_PIRQC              0x60
+
+#define TYPE_PIIX3 "PIIX3"
+#define PIIX3(obj) OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3)
+
+typedef struct PIIX3State {
+    PCIDevice dev;
+
+    /*
+     * bitmap to track pic levels.
+     * The pic level is the logical OR of all the PCI irqs mapped to it
+     * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
+     *
+     * PIRQ is mapped to PIC pins, we track it by
+     * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
+     * pic_irq * PIIX_NUM_PIRQS + pirq
+     */
+#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
+#error "unable to encode pic state in 64bit in pic_levels."
+#endif
+    uint64_t pic_levels;
+
+    ISABus *bus;
+
+    qemu_irq *pic;
+
+    /* This member isn't used. Just for save/load compatibility */
+    int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
+} PIIX3State;
+
+PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx);
+
+void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level);
+
+void piix3_set_irq(void *opaque, int pirq, int level);
+
+#endif
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
deleted file mode 100644
index 9af5847..0000000
--- a/hw/piix_pci.c
+++ /dev/null
@@ -1,622 +0,0 @@ 
-/*
- * QEMU i440FX/PIIX3 PCI Bridge Emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "hw.h"
-#include "pc.h"
-#include "pci.h"
-#include "pci_host.h"
-#include "isa.h"
-#include "sysbus.h"
-#include "range.h"
-#include "xen.h"
-
-/*
- * I440FX chipset data sheet.
- * http://download.intel.com/design/chipsets/datashts/29054901.pdf
- */
-
-typedef struct I440FXState {
-    PCIHostState parent_obj;
-} I440FXState;
-
-#define PIIX_NUM_PIC_IRQS       16      /* i8259 * 2 */
-#define PIIX_NUM_PIRQS          4ULL    /* PIRQ[A-D] */
-#define XEN_PIIX_NUM_PIRQS      128ULL
-#define PIIX_PIRQC              0x60
-
-typedef struct PIIX3State {
-    PCIDevice dev;
-
-    /*
-     * bitmap to track pic levels.
-     * The pic level is the logical OR of all the PCI irqs mapped to it
-     * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
-     *
-     * PIRQ is mapped to PIC pins, we track it by
-     * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
-     * pic_irq * PIIX_NUM_PIRQS + pirq
-     */
-#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
-#error "unable to encode pic state in 64bit in pic_levels."
-#endif
-    uint64_t pic_levels;
-
-    qemu_irq *pic;
-
-    /* This member isn't used. Just for save/load compatibility */
-    int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
-} PIIX3State;
-
-typedef struct PAMMemoryRegion {
-    MemoryRegion alias[4];  /* index = PAM value */
-    unsigned current;
-} PAMMemoryRegion;
-
-struct PCII440FXState {
-    PCIDevice dev;
-    MemoryRegion *system_memory;
-    MemoryRegion *pci_address_space;
-    MemoryRegion *ram_memory;
-    MemoryRegion pci_hole;
-    MemoryRegion pci_hole_64bit;
-    PAMMemoryRegion pam_regions[13];
-    MemoryRegion smram_region;
-    uint8_t smm_enabled;
-};
-
-
-#define I440FX_PAM      0x59
-#define I440FX_PAM_SIZE 7
-#define I440FX_SMRAM    0x72
-
-static void piix3_set_irq(void *opaque, int pirq, int level);
-static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx);
-static void piix3_write_config_xen(PCIDevice *dev,
-                               uint32_t address, uint32_t val, int len);
-
-/* return the global irq number corresponding to a given device irq
-   pin. We could also use the bus number to have a more precise
-   mapping. */
-static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
-{
-    int slot_addend;
-    slot_addend = (pci_dev->devfn >> 3) - 1;
-    return (pci_intx + slot_addend) & 3;
-}
-
-static void init_pam(PCII440FXState *d, PAMMemoryRegion *mem,
-                     uint32_t start, uint32_t size)
-{
-    int i;
-
-    /* RAM */
-    memory_region_init_alias(&mem->alias[3], "pam-ram", d->ram_memory, start, size);
-    /* ROM (XXX: not quite correct) */
-    memory_region_init_alias(&mem->alias[1], "pam-rom", d->ram_memory, start, size);
-    memory_region_set_readonly(&mem->alias[1], true);
-
-    /* XXX: should distinguish read/write cases */
-    memory_region_init_alias(&mem->alias[0], "pam-pci", d->pci_address_space,
-                             start, size);
-    memory_region_init_alias(&mem->alias[2], "pam-pci", d->pci_address_space,
-                             start, size);
-
-    for (i = 0; i < 4; ++i) {
-        memory_region_set_enabled(&mem->alias[i], false);
-        memory_region_add_subregion_overlap(d->system_memory, start, &mem->alias[i], 1);
-    }
-    mem->current = 0;
-}
-
-static void update_pam(PAMMemoryRegion *pam, unsigned r)
-{
-    memory_region_set_enabled(&pam->alias[pam->current], false);
-    pam->current = r;
-    memory_region_set_enabled(&pam->alias[pam->current], true);
-}
-
-static void i440fx_update_memory_mappings(PCII440FXState *d)
-{
-    int i, r;
-    uint32_t smram;
-    bool smram_enabled;
-
-    memory_region_transaction_begin();
-    update_pam(&d->pam_regions[0], (d->dev.config[I440FX_PAM] >> 4) & 3);
-    for(i = 0; i < 12; i++) {
-        r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3;
-        update_pam(&d->pam_regions[i+1], r);
-    }
-    smram = d->dev.config[I440FX_SMRAM];
-    smram_enabled = (d->smm_enabled && (smram & 0x08)) || (smram & 0x40);
-    memory_region_set_enabled(&d->smram_region, !smram_enabled);
-    memory_region_transaction_commit();
-}
-
-static void i440fx_set_smm(int val, void *arg)
-{
-    PCII440FXState *d = arg;
-
-    val = (val != 0);
-    if (d->smm_enabled != val) {
-        d->smm_enabled = val;
-        i440fx_update_memory_mappings(d);
-    }
-}
-
-
-static void i440fx_write_config(PCIDevice *dev,
-                                uint32_t address, uint32_t val, int len)
-{
-    PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
-
-    /* XXX: implement SMRAM.D_LOCK */
-    pci_default_write_config(dev, address, val, len);
-    if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
-        range_covers_byte(address, len, I440FX_SMRAM)) {
-        i440fx_update_memory_mappings(d);
-    }
-}
-
-static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
-{
-    PCII440FXState *d = opaque;
-    int ret, i;
-
-    ret = pci_device_load(&d->dev, f);
-    if (ret < 0)
-        return ret;
-    i440fx_update_memory_mappings(d);
-    qemu_get_8s(f, &d->smm_enabled);
-
-    if (version_id == 2) {
-        for (i = 0; i < PIIX_NUM_PIRQS; i++) {
-            qemu_get_be32(f); /* dummy load for compatibility */
-        }
-    }
-
-    return 0;
-}
-
-static int i440fx_post_load(void *opaque, int version_id)
-{
-    PCII440FXState *d = opaque;
-
-    i440fx_update_memory_mappings(d);
-    return 0;
-}
-
-static const VMStateDescription vmstate_i440fx = {
-    .name = "I440FX",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 1,
-    .load_state_old = i440fx_load_old,
-    .post_load = i440fx_post_load,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, PCII440FXState),
-        VMSTATE_UINT8(smm_enabled, PCII440FXState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int i440fx_pcihost_initfn(SysBusDevice *dev)
-{
-    PCIHostState *s = PCI_HOST_BRIDGE(dev);
-
-    memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s,
-                          "pci-conf-idx", 4);
-    sysbus_add_io(dev, 0xcf8, &s->conf_mem);
-    sysbus_init_ioports(&s->busdev, 0xcf8, 4);
-
-    memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s,
-                          "pci-conf-data", 4);
-    sysbus_add_io(dev, 0xcfc, &s->data_mem);
-    sysbus_init_ioports(&s->busdev, 0xcfc, 4);
-
-    return 0;
-}
-
-static int i440fx_initfn(PCIDevice *dev)
-{
-    PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
-
-    d->dev.config[I440FX_SMRAM] = 0x02;
-
-    cpu_smm_register(&i440fx_set_smm, d);
-    return 0;
-}
-
-static PCIBus *i440fx_common_init(const char *device_name,
-                                  PCII440FXState **pi440fx_state,
-                                  int *piix3_devfn,
-                                  ISABus **isa_bus, qemu_irq *pic,
-                                  MemoryRegion *address_space_mem,
-                                  MemoryRegion *address_space_io,
-                                  ram_addr_t ram_size,
-                                  hwaddr pci_hole_start,
-                                  hwaddr pci_hole_size,
-                                  hwaddr pci_hole64_start,
-                                  hwaddr pci_hole64_size,
-                                  MemoryRegion *pci_address_space,
-                                  MemoryRegion *ram_memory)
-{
-    DeviceState *dev;
-    PCIBus *b;
-    PCIDevice *d;
-    PCIHostState *s;
-    PIIX3State *piix3;
-    PCII440FXState *f;
-    unsigned i;
-
-    dev = qdev_create(NULL, "i440FX-pcihost");
-    s = PCI_HOST_BRIDGE(dev);
-    s->address_space = address_space_mem;
-    b = pci_bus_new(dev, NULL, pci_address_space,
-                    address_space_io, 0);
-    s->bus = b;
-    object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
-    qdev_init_nofail(dev);
-
-    d = pci_create_simple(b, 0, device_name);
-    *pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
-    f = *pi440fx_state;
-    f->system_memory = address_space_mem;
-    f->pci_address_space = pci_address_space;
-    f->ram_memory = ram_memory;
-    memory_region_init_alias(&f->pci_hole, "pci-hole", f->pci_address_space,
-                             pci_hole_start, pci_hole_size);
-    memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
-    memory_region_init_alias(&f->pci_hole_64bit, "pci-hole64",
-                             f->pci_address_space,
-                             pci_hole64_start, pci_hole64_size);
-    if (pci_hole64_size) {
-        memory_region_add_subregion(f->system_memory, pci_hole64_start,
-                                    &f->pci_hole_64bit);
-    }
-    memory_region_init_alias(&f->smram_region, "smram-region",
-                             f->pci_address_space, 0xa0000, 0x20000);
-    memory_region_add_subregion_overlap(f->system_memory, 0xa0000,
-                                        &f->smram_region, 1);
-    memory_region_set_enabled(&f->smram_region, false);
-    init_pam(f, &f->pam_regions[0], 0xf0000, 0x10000);
-    for (i = 0; i < 12; ++i) {
-        init_pam(f, &f->pam_regions[i+1], 0xc0000 + i * 0x4000, 0x4000);
-    }
-
-    /* Xen supports additional interrupt routes from the PCI devices to
-     * the IOAPIC: the four pins of each PCI device on the bus are also
-     * connected to the IOAPIC directly.
-     * These additional routes can be discovered through ACPI. */
-    if (xen_enabled()) {
-        piix3 = DO_UPCAST(PIIX3State, dev,
-                pci_create_simple_multifunction(b, -1, true, "PIIX3-xen"));
-        pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq,
-                piix3, XEN_PIIX_NUM_PIRQS);
-    } else {
-        piix3 = DO_UPCAST(PIIX3State, dev,
-                pci_create_simple_multifunction(b, -1, true, "PIIX3"));
-        pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
-                PIIX_NUM_PIRQS);
-        pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq);
-    }
-    piix3->pic = pic;
-    *isa_bus = DO_UPCAST(ISABus, qbus,
-                         qdev_get_child_bus(&piix3->dev.qdev, "isa.0"));
-
-    *piix3_devfn = piix3->dev.devfn;
-
-    ram_size = ram_size / 8 / 1024 / 1024;
-    if (ram_size > 255)
-        ram_size = 255;
-    (*pi440fx_state)->dev.config[0x57]=ram_size;
-
-    i440fx_update_memory_mappings(f);
-
-    return b;
-}
-
-PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn,
-                    ISABus **isa_bus, qemu_irq *pic,
-                    MemoryRegion *address_space_mem,
-                    MemoryRegion *address_space_io,
-                    ram_addr_t ram_size,
-                    hwaddr pci_hole_start,
-                    hwaddr pci_hole_size,
-                    hwaddr pci_hole64_start,
-                    hwaddr pci_hole64_size,
-                    MemoryRegion *pci_memory, MemoryRegion *ram_memory)
-
-{
-    PCIBus *b;
-
-    b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, isa_bus, pic,
-                           address_space_mem, address_space_io, ram_size,
-                           pci_hole_start, pci_hole_size,
-                           pci_hole64_start, pci_hole64_size,
-                           pci_memory, ram_memory);
-    return b;
-}
-
-/* PIIX3 PCI to ISA bridge */
-static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
-{
-    qemu_set_irq(piix3->pic[pic_irq],
-                 !!(piix3->pic_levels &
-                    (((1ULL << PIIX_NUM_PIRQS) - 1) <<
-                     (pic_irq * PIIX_NUM_PIRQS))));
-}
-
-static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
-{
-    int pic_irq;
-    uint64_t mask;
-
-    pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
-    if (pic_irq >= PIIX_NUM_PIC_IRQS) {
-        return;
-    }
-
-    mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
-    piix3->pic_levels &= ~mask;
-    piix3->pic_levels |= mask * !!level;
-
-    piix3_set_irq_pic(piix3, pic_irq);
-}
-
-static void piix3_set_irq(void *opaque, int pirq, int level)
-{
-    PIIX3State *piix3 = opaque;
-    piix3_set_irq_level(piix3, pirq, level);
-}
-
-static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
-{
-    PIIX3State *piix3 = opaque;
-    int irq = piix3->dev.config[PIIX_PIRQC + pin];
-    PCIINTxRoute route;
-
-    if (irq < PIIX_NUM_PIC_IRQS) {
-        route.mode = PCI_INTX_ENABLED;
-        route.irq = irq;
-    } else {
-        route.mode = PCI_INTX_DISABLED;
-        route.irq = -1;
-    }
-    return route;
-}
-
-/* irq routing is changed. so rebuild bitmap */
-static void piix3_update_irq_levels(PIIX3State *piix3)
-{
-    int pirq;
-
-    piix3->pic_levels = 0;
-    for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
-        piix3_set_irq_level(piix3, pirq,
-                            pci_bus_get_irq_level(piix3->dev.bus, pirq));
-    }
-}
-
-static void piix3_write_config(PCIDevice *dev,
-                               uint32_t address, uint32_t val, int len)
-{
-    pci_default_write_config(dev, address, val, len);
-    if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
-        PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev);
-        int pic_irq;
-
-        pci_bus_fire_intx_routing_notifier(piix3->dev.bus);
-        piix3_update_irq_levels(piix3);
-        for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
-            piix3_set_irq_pic(piix3, pic_irq);
-        }
-    }
-}
-
-static void piix3_write_config_xen(PCIDevice *dev,
-                               uint32_t address, uint32_t val, int len)
-{
-    xen_piix_pci_write_config_client(address, val, len);
-    piix3_write_config(dev, address, val, len);
-}
-
-static void piix3_reset(void *opaque)
-{
-    PIIX3State *d = opaque;
-    uint8_t *pci_conf = d->dev.config;
-
-    pci_conf[0x04] = 0x07; // master, memory and I/O
-    pci_conf[0x05] = 0x00;
-    pci_conf[0x06] = 0x00;
-    pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
-    pci_conf[0x4c] = 0x4d;
-    pci_conf[0x4e] = 0x03;
-    pci_conf[0x4f] = 0x00;
-    pci_conf[0x60] = 0x80;
-    pci_conf[0x61] = 0x80;
-    pci_conf[0x62] = 0x80;
-    pci_conf[0x63] = 0x80;
-    pci_conf[0x69] = 0x02;
-    pci_conf[0x70] = 0x80;
-    pci_conf[0x76] = 0x0c;
-    pci_conf[0x77] = 0x0c;
-    pci_conf[0x78] = 0x02;
-    pci_conf[0x79] = 0x00;
-    pci_conf[0x80] = 0x00;
-    pci_conf[0x82] = 0x00;
-    pci_conf[0xa0] = 0x08;
-    pci_conf[0xa2] = 0x00;
-    pci_conf[0xa3] = 0x00;
-    pci_conf[0xa4] = 0x00;
-    pci_conf[0xa5] = 0x00;
-    pci_conf[0xa6] = 0x00;
-    pci_conf[0xa7] = 0x00;
-    pci_conf[0xa8] = 0x0f;
-    pci_conf[0xaa] = 0x00;
-    pci_conf[0xab] = 0x00;
-    pci_conf[0xac] = 0x00;
-    pci_conf[0xae] = 0x00;
-
-    d->pic_levels = 0;
-}
-
-static int piix3_post_load(void *opaque, int version_id)
-{
-    PIIX3State *piix3 = opaque;
-    piix3_update_irq_levels(piix3);
-    return 0;
-}
-
-static void piix3_pre_save(void *opaque)
-{
-    int i;
-    PIIX3State *piix3 = opaque;
-
-    for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
-        piix3->pci_irq_levels_vmstate[i] =
-            pci_bus_get_irq_level(piix3->dev.bus, i);
-    }
-}
-
-static const VMStateDescription vmstate_piix3 = {
-    .name = "PIIX3",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .post_load = piix3_post_load,
-    .pre_save = piix3_pre_save,
-    .fields      = (VMStateField []) {
-        VMSTATE_PCI_DEVICE(dev, PIIX3State),
-        VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
-                              PIIX_NUM_PIRQS, 3),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int piix3_initfn(PCIDevice *dev)
-{
-    PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
-
-    isa_bus_new(&d->dev.qdev, pci_address_space_io(dev));
-    qemu_register_reset(piix3_reset, d);
-    return 0;
-}
-
-static void piix3_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    dc->desc        = "ISA bridge";
-    dc->vmsd        = &vmstate_piix3;
-    dc->no_user     = 1,
-    k->no_hotplug   = 1;
-    k->init         = piix3_initfn;
-    k->config_write = piix3_write_config;
-    k->vendor_id    = PCI_VENDOR_ID_INTEL;
-    k->device_id    = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
-    k->class_id     = PCI_CLASS_BRIDGE_ISA;
-}
-
-static const TypeInfo piix3_info = {
-    .name          = "PIIX3",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PIIX3State),
-    .class_init    = piix3_class_init,
-};
-
-static void piix3_xen_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    dc->desc        = "ISA bridge";
-    dc->vmsd        = &vmstate_piix3;
-    dc->no_user     = 1;
-    k->no_hotplug   = 1;
-    k->init         = piix3_initfn;
-    k->config_write = piix3_write_config_xen;
-    k->vendor_id    = PCI_VENDOR_ID_INTEL;
-    k->device_id    = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
-    k->class_id     = PCI_CLASS_BRIDGE_ISA;
-};
-
-static const TypeInfo piix3_xen_info = {
-    .name          = "PIIX3-xen",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PIIX3State),
-    .class_init    = piix3_xen_class_init,
-};
-
-static void i440fx_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->no_hotplug = 1;
-    k->init = i440fx_initfn;
-    k->config_write = i440fx_write_config;
-    k->vendor_id = PCI_VENDOR_ID_INTEL;
-    k->device_id = PCI_DEVICE_ID_INTEL_82441;
-    k->revision = 0x02;
-    k->class_id = PCI_CLASS_BRIDGE_HOST;
-    dc->desc = "Host bridge";
-    dc->no_user = 1;
-    dc->vmsd = &vmstate_i440fx;
-}
-
-static const TypeInfo i440fx_info = {
-    .name          = "i440FX",
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(PCII440FXState),
-    .class_init    = i440fx_class_init,
-};
-
-static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = i440fx_pcihost_initfn;
-    dc->fw_name = "pci";
-    dc->no_user = 1;
-}
-
-static const TypeInfo i440fx_pcihost_info = {
-    .name          = "i440FX-pcihost",
-    .parent        = TYPE_PCI_HOST_BRIDGE,
-    .instance_size = sizeof(I440FXState),
-    .class_init    = i440fx_pcihost_class_init,
-};
-
-static void i440fx_register_types(void)
-{
-    type_register_static(&i440fx_info);
-    type_register_static(&piix3_info);
-    type_register_static(&piix3_xen_info);
-    type_register_static(&i440fx_pcihost_info);
-}
-
-type_init(i440fx_register_types)