]> git.proxmox.com Git - qemu.git/blobdiff - hw/pc.c
isa-bus: Remove bogus IRQ sharing check
[qemu.git] / hw / pc.c
diff --git a/hw/pc.c b/hw/pc.c
index 3b6da4a3e2c768489b6c17f7f382ef5052fe1e25..9f1b7765f77432d209049020730573e9ce177ec6 100644 (file)
--- a/hw/pc.c
+++ b/hw/pc.c
 #include "pc.h"
 #include "apic.h"
 #include "fdc.h"
+#include "ide.h"
 #include "pci.h"
 #include "vmware_vga.h"
-#include "usb-uhci.h"
-#include "usb-ohci.h"
-#include "prep_pci.h"
-#include "apb_pci.h"
-#include "block.h"
-#include "sysemu.h"
-#include "audio/audio.h"
-#include "net.h"
-#include "smbus.h"
-#include "boards.h"
 #include "monitor.h"
 #include "fw_cfg.h"
 #include "hpet_emul.h"
-#include "watchdog.h"
 #include "smbios.h"
-#include "ide.h"
 #include "loader.h"
 #include "elf.h"
 #include "multiboot.h"
-#include "kvm.h"
+#include "mc146818rtc.h"
+#include "msix.h"
+#include "sysbus.h"
+#include "sysemu.h"
+#include "blockdev.h"
+#include "ui/qemu-spice.h"
 
 /* output Bochs bios info messages */
 //#define DEBUG_BIOS
 
+/* debug PC/ISA interrupts */
+//#define DEBUG_IRQ
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, ...)                                       \
+    do { printf("CPUIRQ: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
 #define BIOS_FILENAME "bios.bin"
 
 #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
 #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
 #define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
 #define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
+#define FW_CFG_HPET (FW_CFG_ARCH_LOCAL + 4)
 
-#define MAX_IDE_BUS 2
-
-static RTCState *rtc_state;
+#define MSI_ADDR_BASE 0xfee00000
 
 #define E820_NR_ENTRIES                16
 
@@ -73,24 +76,20 @@ struct e820_entry {
     uint64_t address;
     uint64_t length;
     uint32_t type;
-};
+} __attribute((__packed__, __aligned__(4)));
 
 struct e820_table {
     uint32_t count;
     struct e820_entry entry[E820_NR_ENTRIES];
-};
+} __attribute((__packed__, __aligned__(4)));
 
 static struct e820_table e820_table;
 
-typedef struct isa_irq_state {
-    qemu_irq *i8259;
-    qemu_irq *ioapic;
-} IsaIrqState;
-
-static void isa_irq_handler(void *opaque, int n, int level)
+void isa_irq_handler(void *opaque, int n, int level)
 {
     IsaIrqState *isa = (IsaIrqState *)opaque;
 
+    DPRINTF("isa_irqs: %s irq %d\n", level? "raise" : "lower", n);
     if (n < 16) {
         qemu_set_irq(isa->i8259[n], level);
     }
@@ -104,6 +103,12 @@ static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
 
 /* MSDOS compatibility mode FPU exception support */
 static qemu_irq ferr_irq;
+
+void pc_register_ferr_irq(qemu_irq irq)
+{
+    ferr_irq = irq;
+}
+
 /* XXX: add IGNNE support */
 void cpu_set_ferr(CPUX86State *s)
 {
@@ -146,7 +151,7 @@ int cpu_get_pic_interrupt(CPUState *env)
 {
     int intno;
 
-    intno = apic_get_interrupt(env);
+    intno = apic_get_interrupt(env->apic_state);
     if (intno >= 0) {
         /* set irq request if a PIC irq is still pending */
         /* XXX: improve that */
@@ -154,8 +159,9 @@ int cpu_get_pic_interrupt(CPUState *env)
         return intno;
     }
     /* read the irq from the PIC */
-    if (!apic_accept_pic_intr(env))
+    if (!apic_accept_pic_intr(env->apic_state)) {
         return -1;
+    }
 
     intno = pic_read_irq(isa_pic);
     return intno;
@@ -165,10 +171,12 @@ static void pic_irq_request(void *opaque, int irq, int level)
 {
     CPUState *env = first_cpu;
 
+    DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq);
     if (env->apic_state) {
         while (env) {
-            if (apic_accept_pic_intr(env))
-                apic_deliver_pic_intr(env, level);
+            if (apic_accept_pic_intr(env->apic_state)) {
+                apic_deliver_pic_intr(env->apic_state, level);
+            }
             env = env->next_cpu;
         }
     } else {
@@ -207,9 +215,9 @@ static int cmos_get_fd_drive_type(int fd0)
     return val;
 }
 
-static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
+static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd,
+                         ISADevice *s)
 {
-    RTCState *s = rtc_state;
     int cylinders, heads, sectors;
     bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
     rtc_set_memory(s, type_ofs, 47);
@@ -241,7 +249,7 @@ static int boot_device2nibble(char boot_device)
     return 0;
 }
 
-static int set_boot_dev(RTCState *s, const char *boot_device, int fd_bootchk)
+static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk)
 {
 #define PC_MAX_BOOT_DEVICES 3
     int nbds, bds[3] = { 0, };
@@ -270,16 +278,66 @@ static int pc_boot_set(void *opaque, const char *boot_device)
     return set_boot_dev(opaque, boot_device, 0);
 }
 
-/* hd_table must contain 4 block drivers */
-static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
-                      const char *boot_device, DriveInfo **hd_table,
-                      FDCtrl *floppy_controller)
+typedef struct pc_cmos_init_late_arg {
+    ISADevice *rtc_state;
+    BusState *idebus0, *idebus1;
+} pc_cmos_init_late_arg;
+
+static void pc_cmos_init_late(void *opaque)
 {
-    RTCState *s = rtc_state;
+    pc_cmos_init_late_arg *arg = opaque;
+    ISADevice *s = arg->rtc_state;
     int val;
-    int fd0, fd1, nb;
+    BlockDriverState *hd_table[4];
     int i;
 
+    ide_get_bs(hd_table, arg->idebus0);
+    ide_get_bs(hd_table + 2, arg->idebus1);
+
+    rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
+    if (hd_table[0])
+        cmos_init_hd(0x19, 0x1b, hd_table[0], s);
+    if (hd_table[1])
+        cmos_init_hd(0x1a, 0x24, hd_table[1], s);
+
+    val = 0;
+    for (i = 0; i < 4; i++) {
+        if (hd_table[i]) {
+            int cylinders, heads, sectors, translation;
+            /* NOTE: bdrv_get_geometry_hint() returns the physical
+                geometry.  It is always such that: 1 <= sects <= 63, 1
+                <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
+                geometry can be different if a translation is done. */
+            translation = bdrv_get_translation_hint(hd_table[i]);
+            if (translation == BIOS_ATA_TRANSLATION_AUTO) {
+                bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, &sectors);
+                if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
+                    /* No translation. */
+                    translation = 0;
+                } else {
+                    /* LBA translation. */
+                    translation = 1;
+                }
+            } else {
+                translation--;
+            }
+            val |= translation << (i * 2);
+        }
+    }
+    rtc_set_memory(s, 0x39, val);
+
+    qemu_unregister_reset(pc_cmos_init_late, opaque);
+}
+
+void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+                  const char *boot_device,
+                  BusState *idebus0, BusState *idebus1,
+                  FDCtrl *floppy_controller, ISADevice *s)
+{
+    int val;
+    int fd0, fd1, nb;
+    static pc_cmos_init_late_arg arg;
+
     /* various important CMOS locations needed by PC/Bochs bios */
 
     /* memory size */
@@ -347,60 +405,99 @@ static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
     rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
 
     /* hard drives */
+    arg.rtc_state = s;
+    arg.idebus0 = idebus0;
+    arg.idebus1 = idebus1;
+    qemu_register_reset(pc_cmos_init_late, &arg);
+}
 
-    rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
-    if (hd_table[0])
-        cmos_init_hd(0x19, 0x1b, hd_table[0]->bdrv);
-    if (hd_table[1])
-        cmos_init_hd(0x1a, 0x24, hd_table[1]->bdrv);
+/* port 92 stuff: could be split off */
+typedef struct Port92State {
+    ISADevice dev;
+    uint8_t outport;
+    qemu_irq *a20_out;
+} Port92State;
 
-    val = 0;
-    for (i = 0; i < 4; i++) {
-        if (hd_table[i]) {
-            int cylinders, heads, sectors, translation;
-            /* NOTE: bdrv_get_geometry_hint() returns the physical
-                geometry.  It is always such that: 1 <= sects <= 63, 1
-                <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
-                geometry can be different if a translation is done. */
-            translation = bdrv_get_translation_hint(hd_table[i]->bdrv);
-            if (translation == BIOS_ATA_TRANSLATION_AUTO) {
-                bdrv_get_geometry_hint(hd_table[i]->bdrv, &cylinders, &heads, &sectors);
-                if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
-                    /* No translation. */
-                    translation = 0;
-                } else {
-                    /* LBA translation. */
-                    translation = 1;
-                }
-            } else {
-                translation--;
-            }
-            val |= translation << (i * 2);
-        }
+static void port92_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    Port92State *s = opaque;
+
+    DPRINTF("port92: write 0x%02x\n", val);
+    s->outport = val;
+    qemu_set_irq(*s->a20_out, (val >> 1) & 1);
+    if (val & 1) {
+        qemu_system_reset_request();
     }
-    rtc_set_memory(s, 0x39, val);
 }
 
-void ioport_set_a20(int enable)
+static uint32_t port92_read(void *opaque, uint32_t addr)
 {
-    /* XXX: send to all CPUs ? */
-    cpu_x86_set_a20(first_cpu, enable);
+    Port92State *s = opaque;
+    uint32_t ret;
+
+    ret = s->outport;
+    DPRINTF("port92: read 0x%02x\n", ret);
+    return ret;
+}
+
+static void port92_init(ISADevice *dev, qemu_irq *a20_out)
+{
+    Port92State *s = DO_UPCAST(Port92State, dev, dev);
+
+    s->a20_out = a20_out;
+}
+
+static const VMStateDescription vmstate_port92_isa = {
+    .name = "port92",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_UINT8(outport, Port92State),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void port92_reset(DeviceState *d)
+{
+    Port92State *s = container_of(d, Port92State, dev.qdev);
+
+    s->outport &= ~1;
 }
 
-int ioport_get_a20(void)
+static int port92_initfn(ISADevice *dev)
 {
-    return ((first_cpu->a20_mask >> 20) & 1);
+    Port92State *s = DO_UPCAST(Port92State, dev, dev);
+
+    register_ioport_read(0x92, 1, 1, port92_read, s);
+    register_ioport_write(0x92, 1, 1, port92_write, s);
+    isa_init_ioport(dev, 0x92);
+    s->outport = 0;
+    return 0;
 }
 
-static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
+static ISADeviceInfo port92_info = {
+    .qdev.name     = "port92",
+    .qdev.size     = sizeof(Port92State),
+    .qdev.vmsd     = &vmstate_port92_isa,
+    .qdev.no_user  = 1,
+    .qdev.reset    = port92_reset,
+    .init          = port92_initfn,
+};
+
+static void port92_register(void)
 {
-    ioport_set_a20((val >> 1) & 1);
-    /* XXX: bit 0 is fast reset */
+    isa_qdev_register(&port92_info);
 }
+device_init(port92_register)
 
-static uint32_t ioport92_read(void *opaque, uint32_t addr)
+static void handle_a20_line_change(void *opaque, int irq, int level)
 {
-    return ioport_get_a20() << 1;
+    CPUState *cpu = opaque;
+
+    /* XXX: send to all CPUs ? */
+    /* XXX: add logic to handle multiple A20 line sources */
+    cpu_x86_set_a20(cpu, level);
 }
 
 /***********************************************************/
@@ -415,8 +512,8 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
         /* Bochs BIOS messages */
     case 0x400:
     case 0x401:
-        fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
-        exit(1);
+        /* used to be panic, now unused */
+        break;
     case 0x402:
     case 0x403:
 #ifdef DEBUG_BIOS
@@ -452,19 +549,19 @@ static void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
 
 int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
 {
-    int index = e820_table.count;
+    int index = le32_to_cpu(e820_table.count);
     struct e820_entry *entry;
 
     if (index >= E820_NR_ENTRIES)
         return -EBUSY;
-    entry = &e820_table.entry[index];
+    entry = &e820_table.entry[index++];
 
-    entry->address = address;
-    entry->length = length;
-    entry->type = type;
+    entry->address = cpu_to_le64(address);
+    entry->length = cpu_to_le64(length);
+    entry->type = cpu_to_le32(type);
 
-    e820_table.count++;
-    return e820_table.count;
+    e820_table.count = cpu_to_le32(index);
+    return index;
 }
 
 static void *bochs_bios_init(void)
@@ -501,6 +598,8 @@ static void *bochs_bios_init(void)
     fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, (uint8_t *)&e820_table,
                      sizeof(struct e820_table));
 
+    fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, (uint8_t *)&hpet_cfg,
+                     sizeof(struct hpet_fw_config));
     /* allocate memory for the NUMA channel: one (64bit) word for the number
      * of nodes, one word for each VCPU->node and one word for each node to
      * hold the amount of memory.
@@ -716,14 +815,11 @@ static void load_linux(void *fw_cfg,
     fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
     fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
 
-    option_rom[nb_option_roms] = "linuxboot.bin";
+    option_rom[nb_option_roms].name = "linuxboot.bin";
+    option_rom[nb_option_roms].bootindex = 0;
     nb_option_roms++;
 }
 
-static const int ide_iobase[2] = { 0x1f0, 0x170 };
-static const int ide_iobase2[2] = { 0x3f6, 0x376 };
-static const int ide_irq[2] = { 14, 15 };
-
 #define NE2000_NB_MAX 6
 
 static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
@@ -733,26 +829,7 @@ static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
 static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
 static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
 
-#ifdef HAS_AUDIO
-static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
-{
-    struct soundhw *c;
-
-    for (c = soundhw; c->name; ++c) {
-        if (c->enabled) {
-            if (c->isa) {
-                c->init.init_isa(pic);
-            } else {
-                if (pci_bus) {
-                    c->init.init_pci(pci_bus);
-                }
-            }
-        }
-    }
-}
-#endif
-
-static void pc_init_ne2k_isa(NICInfo *nd)
+void pc_init_ne2k_isa(NICInfo *nd)
 {
     static int nb_ne2k = 0;
 
@@ -769,18 +846,53 @@ int cpu_is_bsp(CPUState *env)
     return env->cpu_index == 0;
 }
 
+DeviceState *cpu_get_current_apic(void)
+{
+    if (cpu_single_env) {
+        return cpu_single_env->apic_state;
+    } else {
+        return NULL;
+    }
+}
+
+static DeviceState *apic_init(void *env, uint8_t apic_id)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+    static int apic_mapped;
+
+    dev = qdev_create(NULL, "apic");
+    qdev_prop_set_uint8(dev, "id", apic_id);
+    qdev_prop_set_ptr(dev, "cpu_env", env);
+    qdev_init_nofail(dev);
+    d = sysbus_from_qdev(dev);
+
+    /* XXX: mapping more APICs at the same memory location */
+    if (apic_mapped == 0) {
+        /* NOTE: the APIC is directly connected to the CPU - it is not
+           on the global memory bus. */
+        /* XXX: what if the base changes? */
+        sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
+        apic_mapped = 1;
+    }
+
+    msix_supported = 1;
+
+    return dev;
+}
+
 /* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
    BIOS will read it and start S3 resume at POST Entry */
-static void cmos_set_s3_resume(void *opaque, int irq, int level)
+void pc_cmos_set_s3_resume(void *opaque, int irq, int level)
 {
-    RTCState *s = opaque;
+    ISADevice *s = opaque;
 
     if (level) {
         rtc_set_memory(s, 0xF, 0xFE);
     }
 }
 
-static void acpi_smi_interrupt(void *opaque, int irq, int level)
+void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
 {
     CPUState *s = opaque;
 
@@ -789,6 +901,14 @@ static void acpi_smi_interrupt(void *opaque, int irq, int level)
     }
 }
 
+static void pc_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    env->halted = !cpu_is_bsp(env);
+}
+
 static CPUState *pc_new_cpu(const char *cpu_model)
 {
     CPUState *env;
@@ -800,42 +920,44 @@ static CPUState *pc_new_cpu(const char *cpu_model)
     }
     if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
         env->cpuid_apic_id = env->cpu_index;
-        /* APIC reset callback resets cpu */
-        apic_init(env);
-    } else {
-        qemu_register_reset((QEMUResetHandler*)cpu_reset, env);
+        env->apic_state = apic_init(env, env->cpuid_apic_id);
     }
+    qemu_register_reset(pc_cpu_reset, env);
+    pc_cpu_reset(env);
     return env;
 }
 
-/* PC hardware initialisation */
-static void pc_init1(ram_addr_t ram_size,
-                     const char *boot_device,
-                     const char *kernel_filename,
-                     const char *kernel_cmdline,
-                     const char *initrd_filename,
-                     const char *cpu_model,
-                     int pci_enabled)
+void pc_cpus_init(const char *cpu_model)
+{
+    int i;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+        cpu_model = "qemu64";
+#else
+        cpu_model = "qemu32";
+#endif
+    }
+
+    for(i = 0; i < smp_cpus; i++) {
+        pc_new_cpu(cpu_model);
+    }
+}
+
+void pc_memory_init(ram_addr_t ram_size,
+                    const char *kernel_filename,
+                    const char *kernel_cmdline,
+                    const char *initrd_filename,
+                    ram_addr_t *below_4g_mem_size_p,
+                    ram_addr_t *above_4g_mem_size_p)
 {
     char *filename;
     int ret, linux_boot, i;
     ram_addr_t ram_addr, bios_offset, option_rom_offset;
     ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
     int bios_size, isa_bios_size;
-    PCIBus *pci_bus;
-    PCII440FXState *i440fx_state;
-    int piix3_devfn = -1;
-    qemu_irq *cpu_irq;
-    qemu_irq *isa_irq;
-    qemu_irq *i8259;
-    qemu_irq *cmos_s3;
-    qemu_irq *smi_irq;
-    IsaIrqState *isa_irq_state;
-    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
-    DriveInfo *fd[MAX_FD];
     void *fw_cfg;
-    FDCtrl *floppy_controller;
-    PITState *pit;
 
     if (ram_size >= 0xe0000000 ) {
         above_4g_mem_size = ram_size - 0xe0000000;
@@ -843,43 +965,29 @@ static void pc_init1(ram_addr_t ram_size,
     } else {
         below_4g_mem_size = ram_size;
     }
+    *above_4g_mem_size_p = above_4g_mem_size;
+    *below_4g_mem_size_p = below_4g_mem_size;
 
-    linux_boot = (kernel_filename != NULL);
-
-    /* init CPUs */
-    if (cpu_model == NULL) {
-#ifdef TARGET_X86_64
-        cpu_model = "qemu64";
-#else
-        cpu_model = "qemu32";
-#endif
-    }
-
-    for (i = 0; i < smp_cpus; i++) {
-        pc_new_cpu(cpu_model);
+#if TARGET_PHYS_ADDR_BITS == 32
+    if (above_4g_mem_size > 0) {
+        hw_error("To much RAM for 32-bit physical address");
     }
-
-    vmport_init();
+#endif
+    linux_boot = (kernel_filename != NULL);
 
     /* allocate RAM */
-    ram_addr = qemu_ram_alloc(below_4g_mem_size);
+    ram_addr = qemu_ram_alloc(NULL, "pc.ram",
+                              below_4g_mem_size + above_4g_mem_size);
     cpu_register_physical_memory(0, 0xa0000, ram_addr);
     cpu_register_physical_memory(0x100000,
                  below_4g_mem_size - 0x100000,
                  ram_addr + 0x100000);
-
-    /* above 4giga memory allocation */
+#if TARGET_PHYS_ADDR_BITS > 32
     if (above_4g_mem_size > 0) {
-#if TARGET_PHYS_ADDR_BITS == 32
-        hw_error("To much RAM for 32-bit physical address");
-#else
-        ram_addr = qemu_ram_alloc(above_4g_mem_size);
-        cpu_register_physical_memory(0x100000000ULL,
-                                     above_4g_mem_size,
-                                     ram_addr);
-#endif
+        cpu_register_physical_memory(0x100000000ULL, above_4g_mem_size,
+                                     ram_addr + below_4g_mem_size);
     }
-
+#endif
 
     /* BIOS load */
     if (bios_name == NULL)
@@ -894,8 +1002,8 @@ static void pc_init1(ram_addr_t ram_size,
         (bios_size % 65536) != 0) {
         goto bios_error;
     }
-    bios_offset = qemu_ram_alloc(bios_size);
-    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size));
+    bios_offset = qemu_ram_alloc(NULL, "pc.bios", bios_size);
+    ret = rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1);
     if (ret != 0) {
     bios_error:
         fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name);
@@ -912,7 +1020,7 @@ static void pc_init1(ram_addr_t ram_size,
                                  isa_bios_size,
                                  (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
 
-    option_rom_offset = qemu_ram_alloc(PC_ROM_SIZE);
+    option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
     cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
 
     /* map all the bios at the top of memory */
@@ -927,64 +1035,83 @@ static void pc_init1(ram_addr_t ram_size,
     }
 
     for (i = 0; i < nb_option_roms; i++) {
-        rom_add_option(option_rom[i]);
-    }
-
-    cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
-    i8259 = i8259_init(cpu_irq[0]);
-    isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
-    isa_irq_state->i8259 = i8259;
-    if (pci_enabled) {
-        isa_irq_state->ioapic = ioapic_init();
+        rom_add_option(option_rom[i].name, option_rom[i].bootindex);
     }
-    isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
-
-    if (pci_enabled) {
-        pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
-    } else {
-        pci_bus = NULL;
-        isa_bus_new(NULL);
-    }
-    isa_bus_irqs(isa_irq);
-
-    ferr_irq = isa_reserve_irq(13);
-
-    /* init basic PC hardware */
-    register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
+}
 
-    register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
+qemu_irq *pc_allocate_cpu_irq(void)
+{
+    return qemu_allocate_irqs(pic_irq_request, NULL, 1);
+}
 
+void pc_vga_init(PCIBus *pci_bus)
+{
     if (cirrus_vga_enabled) {
-        if (pci_enabled) {
+        if (pci_bus) {
             pci_cirrus_vga_init(pci_bus);
         } else {
             isa_cirrus_vga_init();
         }
     } else if (vmsvga_enabled) {
-        if (pci_enabled)
+        if (pci_bus)
             pci_vmsvga_init(pci_bus);
         else
             fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
+#ifdef CONFIG_SPICE
+    } else if (qxl_enabled) {
+        if (pci_bus)
+            pci_create_simple(pci_bus, -1, "qxl-vga");
+        else
+            fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__);
+#endif
     } else if (std_vga_enabled) {
-        if (pci_enabled) {
-            pci_vga_init(pci_bus, 0, 0);
+        if (pci_bus) {
+            pci_vga_init(pci_bus);
         } else {
             isa_vga_init();
         }
     }
+}
+
+static void cpu_request_exit(void *opaque, int irq, int level)
+{
+    CPUState *env = cpu_single_env;
+
+    if (env && level) {
+        cpu_exit(env);
+    }
+}
 
-    rtc_state = rtc_init(2000);
+void pc_basic_device_init(qemu_irq *isa_irq,
+                          FDCtrl **floppy_controller,
+                          ISADevice **rtc_state)
+{
+    int i;
+    DriveInfo *fd[MAX_FD];
+    PITState *pit;
+    qemu_irq rtc_irq = NULL;
+    qemu_irq *a20_line;
+    ISADevice *i8042, *port92;
+    qemu_irq *cpu_exit_irq;
 
-    qemu_register_boot_set(pc_boot_set, rtc_state);
+    register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
 
-    register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
-    register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
+    register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
 
-    pit = pit_init(0x40, isa_reserve_irq(0));
-    pcspk_init(pit);
     if (!no_hpet) {
-        hpet_init(isa_irq);
+        DeviceState *hpet = sysbus_create_simple("hpet", HPET_BASE, NULL);
+
+        for (i = 0; i < 24; i++) {
+            sysbus_connect_irq(sysbus_from_qdev(hpet), i, isa_irq[i]);
+        }
+        rtc_irq = qdev_get_gpio_in(hpet, 0);
     }
+    *rtc_state = rtc_init(2000, rtc_irq);
+
+    qemu_register_boot_set(pc_boot_set, *rtc_state);
+
+    pit = pit_init(0x40, isa_get_irq(0));
+    pcspk_init(pit);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
@@ -998,236 +1125,29 @@ static void pc_init1(ram_addr_t ram_size,
         }
     }
 
-    for(i = 0; i < nb_nics; i++) {
-        NICInfo *nd = &nd_table[i];
-
-        if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
-            pc_init_ne2k_isa(nd);
-        else
-            pci_nic_init_nofail(nd, "e1000", NULL);
-    }
-
-    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
-        fprintf(stderr, "qemu: too many IDE bus\n");
-        exit(1);
-    }
-
-    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
-        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
-    }
-
-    if (pci_enabled) {
-        pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
-    } else {
-        for(i = 0; i < MAX_IDE_BUS; i++) {
-            isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
-                        hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
-        }
-    }
+    a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
+    i8042 = isa_create_simple("i8042");
+    i8042_setup_a20_line(i8042, &a20_line[0]);
+    vmmouse_init(i8042);
+    port92 = isa_create_simple("port92");
+    port92_init(port92, &a20_line[1]);
 
-    isa_create_simple("i8042");
-    DMA_init(0);
-#ifdef HAS_AUDIO
-    audio_init(pci_enabled ? pci_bus : NULL, isa_irq);
-#endif
+    cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+    DMA_init(0, cpu_exit_irq);
 
     for(i = 0; i < MAX_FD; i++) {
         fd[i] = drive_get(IF_FLOPPY, 0, i);
     }
-    floppy_controller = fdctrl_init_isa(fd);
-
-    cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd,
-              floppy_controller);
-
-    if (pci_enabled && usb_enabled) {
-        usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
-    }
-
-    if (pci_enabled && acpi_enabled) {
-        uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
-        i2c_bus *smbus;
-
-        cmos_s3 = qemu_allocate_irqs(cmos_set_s3_resume, rtc_state, 1);
-        smi_irq = qemu_allocate_irqs(acpi_smi_interrupt, first_cpu, 1);
-        /* TODO: Populate SPD eeprom data.  */
-        smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
-                              isa_reserve_irq(9), *cmos_s3, *smi_irq,
-                              kvm_enabled());
-        for (i = 0; i < 8; i++) {
-            DeviceState *eeprom;
-            eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
-            qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
-            qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
-            qdev_init_nofail(eeprom);
-        }
-        piix4_acpi_system_hot_add_init(pci_bus);
-    }
-
-    if (i440fx_state) {
-        i440fx_init_memory_mappings(i440fx_state);
-    }
-
-    if (pci_enabled) {
-       int max_bus;
-        int bus;
-
-        max_bus = drive_get_max_bus(IF_SCSI);
-       for (bus = 0; bus <= max_bus; bus++) {
-            pci_create_simple(pci_bus, -1, "lsi53c895a");
-        }
-    }
+    *floppy_controller = fdctrl_init_isa(fd);
 }
 
-static void pc_init_pci(ram_addr_t ram_size,
-                        const char *boot_device,
-                        const char *kernel_filename,
-                        const char *kernel_cmdline,
-                        const char *initrd_filename,
-                        const char *cpu_model)
+void pc_pci_device_init(PCIBus *pci_bus)
 {
-    pc_init1(ram_size, boot_device,
-             kernel_filename, kernel_cmdline,
-             initrd_filename, cpu_model, 1);
-}
+    int max_bus;
+    int bus;
 
-static void pc_init_isa(ram_addr_t ram_size,
-                        const char *boot_device,
-                        const char *kernel_filename,
-                        const char *kernel_cmdline,
-                        const char *initrd_filename,
-                        const char *cpu_model)
-{
-    if (cpu_model == NULL)
-        cpu_model = "486";
-    pc_init1(ram_size, boot_device,
-             kernel_filename, kernel_cmdline,
-             initrd_filename, cpu_model, 0);
-}
-
-static QEMUMachine pc_machine = {
-    .name = "pc-0.13",
-    .alias = "pc",
-    .desc = "Standard PC",
-    .init = pc_init_pci,
-    .max_cpus = 255,
-    .is_default = 1,
-};
-
-static QEMUMachine pc_machine_v0_12 = {
-    .name = "pc-0.12",
-    .desc = "Standard PC",
-    .init = pc_init_pci,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        {
-            .driver   = "virtio-serial-pci",
-            .property = "max_nr_ports",
-            .value    = stringify(1),
-        },{
-            .driver   = "virtio-serial-pci",
-            .property = "vectors",
-            .value    = stringify(0),
-        },
-        { /* end of list */ }
+    max_bus = drive_get_max_bus(IF_SCSI);
+    for (bus = 0; bus <= max_bus; bus++) {
+        pci_create_simple(pci_bus, -1, "lsi53c895a");
     }
-};
-
-static QEMUMachine pc_machine_v0_11 = {
-    .name = "pc-0.11",
-    .desc = "Standard PC, qemu 0.11",
-    .init = pc_init_pci,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        {
-            .driver   = "virtio-blk-pci",
-            .property = "vectors",
-            .value    = stringify(0),
-        },{
-            .driver   = "virtio-serial-pci",
-            .property = "max_nr_ports",
-            .value    = stringify(1),
-        },{
-            .driver   = "virtio-serial-pci",
-            .property = "vectors",
-            .value    = stringify(0),
-        },{
-            .driver   = "ide-drive",
-            .property = "ver",
-            .value    = "0.11",
-        },{
-            .driver   = "scsi-disk",
-            .property = "ver",
-            .value    = "0.11",
-        },{
-            .driver   = "PCI",
-            .property = "rombar",
-            .value    = stringify(0),
-        },
-        { /* end of list */ }
-    }
-};
-
-static QEMUMachine pc_machine_v0_10 = {
-    .name = "pc-0.10",
-    .desc = "Standard PC, qemu 0.10",
-    .init = pc_init_pci,
-    .max_cpus = 255,
-    .compat_props = (GlobalProperty[]) {
-        {
-            .driver   = "virtio-blk-pci",
-            .property = "class",
-            .value    = stringify(PCI_CLASS_STORAGE_OTHER),
-        },{
-            .driver   = "virtio-serial-pci",
-            .property = "class",
-            .value    = stringify(PCI_CLASS_DISPLAY_OTHER),
-        },{
-            .driver   = "virtio-serial-pci",
-            .property = "max_nr_ports",
-            .value    = stringify(1),
-        },{
-            .driver   = "virtio-serial-pci",
-            .property = "vectors",
-            .value    = stringify(0),
-        },{
-            .driver   = "virtio-net-pci",
-            .property = "vectors",
-            .value    = stringify(0),
-        },{
-            .driver   = "virtio-blk-pci",
-            .property = "vectors",
-            .value    = stringify(0),
-        },{
-            .driver   = "ide-drive",
-            .property = "ver",
-            .value    = "0.10",
-        },{
-            .driver   = "scsi-disk",
-            .property = "ver",
-            .value    = "0.10",
-        },{
-            .driver   = "PCI",
-            .property = "rombar",
-            .value    = stringify(0),
-        },
-        { /* end of list */ }
-    },
-};
-
-static QEMUMachine isapc_machine = {
-    .name = "isapc",
-    .desc = "ISA-only PC",
-    .init = pc_init_isa,
-    .max_cpus = 1,
-};
-
-static void pc_machine_init(void)
-{
-    qemu_register_machine(&pc_machine);
-    qemu_register_machine(&pc_machine_v0_12);
-    qemu_register_machine(&pc_machine_v0_11);
-    qemu_register_machine(&pc_machine_v0_10);
-    qemu_register_machine(&isapc_machine);
 }
-
-machine_init(pc_machine_init);