summary refs log tree commit diff stats
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/a15mpcore.c1
-rw-r--r--hw/a9mpcore.c2
-rw-r--r--hw/acpi.c5
-rw-r--r--hw/acpi.h2
-rw-r--r--hw/acpi_piix4.c30
-rw-r--r--hw/arm-misc.h4
-rw-r--r--hw/arm/Makefile.objs2
-rw-r--r--hw/arm11mpcore.c2
-rw-r--r--hw/arm_boot.c10
-rw-r--r--hw/arm_gic.c366
-rw-r--r--hw/arm_gic_common.c184
-rw-r--r--hw/arm_gic_internal.h136
-rw-r--r--hw/arm_l2x0.c2
-rw-r--r--hw/armv7m_nvic.c138
-rw-r--r--hw/boards.h1
-rw-r--r--hw/bt-sdp.c6
-rw-r--r--hw/cadence_gem.c2
-rw-r--r--hw/cadence_ttc.c2
-rw-r--r--hw/exynos4210.c32
-rw-r--r--hw/exynos4210.h2
-rw-r--r--hw/exynos4210_gic.c78
-rw-r--r--hw/fdc.c54
-rw-r--r--hw/fdc.h24
-rw-r--r--hw/i2c.c30
-rw-r--r--hw/i386/Makefile.objs2
-rw-r--r--hw/ide/ahci.c25
-rw-r--r--hw/ide/ahci.h2
-rw-r--r--hw/ide/core.c23
-rw-r--r--hw/ide/ich.c19
-rw-r--r--hw/ide/internal.h3
-rw-r--r--hw/ide/piix.c3
-rw-r--r--hw/ide/qdev.c31
-rw-r--r--hw/intel-hda.c49
-rw-r--r--hw/intel-hda.h3
-rw-r--r--hw/ioh3420.c3
-rw-r--r--hw/isa-bus.c23
-rw-r--r--hw/isa.h5
-rw-r--r--hw/ivshmem.c1
-rw-r--r--hw/kvm/Makefile.objs1
-rw-r--r--hw/lsi53c895a.c5
-rw-r--r--hw/m48t59.c40
-rw-r--r--hw/mips_malta.c2
-rw-r--r--hw/msi.c11
-rw-r--r--hw/msix.c15
-rw-r--r--hw/nseries.c3
-rw-r--r--hw/omap.h95
-rw-r--r--hw/pc.c3
-rw-r--r--hw/pc.h4
-rw-r--r--hw/pc_piix.c23
-rw-r--r--hw/pc_sysfw.c1
-rw-r--r--hw/pci-hotplug.c6
-rw-r--r--hw/pci.c59
-rw-r--r--hw/pci_bridge.c12
-rw-r--r--hw/pci_bridge_dev.c8
-rw-r--r--hw/pci_internals.h3
-rw-r--r--hw/qdev-monitor.c101
-rw-r--r--hw/qdev-properties.c67
-rw-r--r--hw/qdev.c301
-rw-r--r--hw/qdev.h65
-rw-r--r--hw/rtl8139.c2
-rw-r--r--hw/s390-virtio-bus.c37
-rw-r--r--hw/s390-virtio-bus.h4
-rw-r--r--hw/scsi-bus.c60
-rw-r--r--hw/scsi-disk.c5
-rw-r--r--hw/scsi.h3
-rw-r--r--hw/shpc.c1
-rw-r--r--hw/spapr_pci.c7
-rw-r--r--hw/spapr_vio.c47
-rw-r--r--hw/spapr_vio.h3
-rw-r--r--hw/spapr_vty.c6
-rw-r--r--hw/ssi.c29
-rw-r--r--hw/sysbus.c45
-rw-r--r--hw/sysbus.h3
-rw-r--r--hw/usb.h3
-rw-r--r--hw/usb/bus.c45
-rw-r--r--hw/usb/desc.c5
-rw-r--r--hw/usb/dev-bluetooth.c2
-rw-r--r--hw/usb/dev-hid.c2
-rw-r--r--hw/usb/dev-hub.c2
-rw-r--r--hw/usb/dev-serial.c2
-rw-r--r--hw/usb/dev-smartcard-reader.c29
-rw-r--r--hw/usb/dev-storage.c2
-rw-r--r--hw/usb/dev-wacom.c2
-rw-r--r--hw/usb/redirect.c8
-rw-r--r--hw/virtio-balloon.c5
-rw-r--r--hw/virtio-pci.c3
-rw-r--r--hw/virtio-scsi.c6
-rw-r--r--hw/virtio-serial-bus.c36
-rw-r--r--hw/vt82c686.c2
-rw-r--r--hw/xen_devconfig.c13
-rw-r--r--hw/xen_disk.c3
-rw-r--r--hw/xilinx_timer.c3
-rw-r--r--hw/xio3130_downstream.c3
-rw-r--r--hw/xio3130_upstream.c3
-rw-r--r--hw/xtensa_lx60.c1
95 files changed, 1480 insertions, 1084 deletions
diff --git a/hw/a15mpcore.c b/hw/a15mpcore.c
index 5a7b365548..fc0a02ae86 100644
--- a/hw/a15mpcore.c
+++ b/hw/a15mpcore.c
@@ -44,6 +44,7 @@ static int a15mp_priv_init(SysBusDevice *dev)
     s->gic = qdev_create(NULL, "arm_gic");
     qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
     qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+    qdev_prop_set_uint32(s->gic, "revision", 2);
     qdev_init_nofail(s->gic);
     busdev = sysbus_from_qdev(s->gic);
 
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index c2ff74d4b6..ebd5b29173 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -75,7 +75,7 @@ static void a9_scu_write(void *opaque, target_phys_addr_t offset,
         break;
     default:
         fprintf(stderr, "Invalid size %u in write to a9 scu register %x\n",
-                size, offset);
+                size, (unsigned)offset);
         return;
     }
 
diff --git a/hw/acpi.c b/hw/acpi.c
index 5d521e5133..effc7ec23e 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -370,7 +370,7 @@ void acpi_pm1_cnt_init(ACPIREGS *ar)
     qemu_register_wakeup_notifier(&ar->wakeup);
 }
 
-void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
+void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4)
 {
     ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
 
@@ -385,6 +385,9 @@ void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
             qemu_system_suspend_request();
             break;
         default:
+            if (sus_typ == s4) { /* S4 request */
+                qemu_system_shutdown_request();
+            }
             break;
         }
     }
diff --git a/hw/acpi.h b/hw/acpi.h
index fe8cdb48e0..7337f41857 100644
--- a/hw/acpi.h
+++ b/hw/acpi.h
@@ -139,7 +139,7 @@ void acpi_pm1_evt_reset(ACPIREGS *ar);
 
 /* PM1a_CNT: piix and ich9 don't implement PM1b CNT. */
 void acpi_pm1_cnt_init(ACPIREGS *ar);
-void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val);
+void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val, char s4);
 void acpi_pm1_cnt_update(ACPIREGS *ar,
                          bool sci_enable, bool sci_disable);
 void acpi_pm1_cnt_reset(ACPIREGS *ar);
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 0345490ee0..0aace60f24 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -27,6 +27,7 @@
 #include "sysemu.h"
 #include "range.h"
 #include "ioport.h"
+#include "fw_cfg.h"
 
 //#define DEBUG
 
@@ -71,6 +72,10 @@ typedef struct PIIX4PMState {
     struct pci_status pci0_status;
     uint32_t pci0_hotplug_enable;
     uint32_t pci0_slot_device_present;
+
+    uint8_t disable_s3;
+    uint8_t disable_s4;
+    uint8_t s4_val;
 } PIIX4PMState;
 
 static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
@@ -123,7 +128,7 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width,
         pm_update_sci(s);
         break;
     case 0x04:
-        acpi_pm1_cnt_write(&s->ar, val);
+        acpi_pm1_cnt_write(&s->ar, val, s->s4_val);
         break;
     default:
         break;
@@ -284,7 +289,7 @@ static const VMStateDescription vmstate_acpi = {
 
 static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
 {
-    DeviceState *qdev, *next;
+    BusChild *kid, *next;
     BusState *bus = qdev_get_parent_bus(&s->dev.qdev);
     int slot = ffs(slots) - 1;
     bool slot_free = true;
@@ -292,7 +297,8 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
     /* Mark request as complete */
     s->pci0_status.down &= ~(1U << slot);
 
-    QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+    QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
+        DeviceState *qdev = kid->child;
         PCIDevice *dev = PCI_DEVICE(qdev);
         PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
         if (PCI_SLOT(dev->devfn) == slot) {
@@ -313,7 +319,7 @@ static void piix4_update_hotplug(PIIX4PMState *s)
 {
     PCIDevice *dev = &s->dev;
     BusState *bus = qdev_get_parent_bus(&dev->qdev);
-    DeviceState *qdev, *next;
+    BusChild *kid, *next;
 
     /* Execute any pending removes during reset */
     while (s->pci0_status.down) {
@@ -323,7 +329,8 @@ static void piix4_update_hotplug(PIIX4PMState *s)
     s->pci0_hotplug_enable = ~0;
     s->pci0_slot_device_present = 0;
 
-    QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+    QTAILQ_FOREACH_SAFE(kid, &bus->children, sibling, next) {
+        DeviceState *qdev = kid->child;
         PCIDevice *pdev = PCI_DEVICE(qdev);
         PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
         int slot = PCI_SLOT(pdev->devfn);
@@ -422,7 +429,7 @@ static int piix4_pm_initfn(PCIDevice *dev)
 
 i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
                        qemu_irq sci_irq, qemu_irq smi_irq,
-                       int kvm_enabled)
+                       int kvm_enabled, void *fw_cfg)
 {
     PCIDevice *dev;
     PIIX4PMState *s;
@@ -438,11 +445,22 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
 
     qdev_init_nofail(&dev->qdev);
 
+    if (fw_cfg) {
+        uint8_t suspend[6] = {128, 0, 0, 129, 128, 128};
+        suspend[3] = 1 | ((!s->disable_s3) << 7);
+        suspend[4] = s->s4_val | ((!s->disable_s4) << 7);
+
+        fw_cfg_add_file(fw_cfg, "etc/system-states", g_memdup(suspend, 6), 6);
+    }
+
     return s->smb.smbus;
 }
 
 static Property piix4_pm_properties[] = {
     DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
+    DEFINE_PROP_UINT8("disable_s3", PIIX4PMState, disable_s3, 0),
+    DEFINE_PROP_UINT8("disable_s4", PIIX4PMState, disable_s4, 0),
+    DEFINE_PROP_UINT8("s4_val", PIIX4PMState, s4_val, 2),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 1d51570c88..1f96229d3c 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -45,9 +45,9 @@ struct arm_boot_info {
     /* multicore boards that use the default secondary core boot functions
      * can ignore these two function calls. If the default functions won't
      * work, then write_secondary_boot() should write a suitable blob of
-     * code mimicing the secondary CPU startup process used by the board's
+     * code mimicking the secondary CPU startup process used by the board's
      * boot loader/boot ROM code, and secondary_cpu_reset_hook() should
-     * perform any necessary CPU reset handling and set the PC for thei
+     * perform any necessary CPU reset handling and set the PC for the
      * secondary CPUs to point at this boot blob.
      */
     void (*write_secondary_boot)(ARMCPU *cpu,
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index a0ff6a62d6..88ff47d95e 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -6,7 +6,7 @@ obj-y += cadence_uart.o
 obj-y += cadence_ttc.o
 obj-y += cadence_gem.o
 obj-y += xilinx_zynq.o zynq_slcr.o
-obj-y += arm_gic.o
+obj-y += arm_gic.o arm_gic_common.o
 obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
 obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
 obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index c528d7aa01..1bff3d3282 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -123,6 +123,8 @@ static int mpcore_priv_init(SysBusDevice *dev)
     s->gic = qdev_create(NULL, "arm_gic");
     qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
     qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
+    /* Request the legacy 11MPCore GIC behaviour: */
+    qdev_prop_set_uint32(s->gic, "revision", 0);
     qdev_init_nofail(s->gic);
 
     /* Pass through outbound IRQ lines from the GIC */
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index d0e643ba11..a1e6ddbc1c 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -242,10 +242,12 @@ static int load_dtb(target_phys_addr_t addr, const struct arm_boot_info *binfo)
         fprintf(stderr, "couldn't set /memory/reg\n");
     }
 
-    rc = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
-                                      binfo->kernel_cmdline);
-    if (rc < 0) {
-        fprintf(stderr, "couldn't set /chosen/bootargs\n");
+    if (binfo->kernel_cmdline && *binfo->kernel_cmdline) {
+        rc = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
+                                          binfo->kernel_cmdline);
+        if (rc < 0) {
+            fprintf(stderr, "couldn't set /chosen/bootargs\n");
+        }
     }
 
     if (binfo->initrd_size) {
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 72298b4b41..ec22322930 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -19,17 +19,7 @@
  */
 
 #include "sysbus.h"
-
-/* Maximum number of possible interrupts, determined by the GIC architecture */
-#define GIC_MAXIRQ 1020
-/* First 32 are private to each CPU (SGIs and PPIs). */
-#define GIC_INTERNAL 32
-/* Maximum number of possible CPU interfaces, determined by GIC architecture */
-#ifdef NVIC
-#define NCPU 1
-#else
-#define NCPU 8
-#endif
+#include "arm_gic_internal.h"
 
 //#define DEBUG_GIC
 
@@ -40,114 +30,23 @@ do { printf("arm_gic: " fmt , ## __VA_ARGS__); } while (0)
 #define DPRINTF(fmt, ...) do {} while(0)
 #endif
 
-#ifdef NVIC
-static const uint8_t gic_id[] =
-{ 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 };
-/* The NVIC has 16 internal vectors.  However these are not exposed
-   through the normal GIC interface.  */
-#define GIC_BASE_IRQ    32
-#else
-static const uint8_t gic_id[] =
-{ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-#define GIC_BASE_IRQ    0
-#endif
-
-#define FROM_SYSBUSGIC(type, dev) \
-    DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev))
+static const uint8_t gic_id[] = {
+    0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
+};
 
-typedef struct gic_irq_state
-{
-    /* The enable bits are only banked for per-cpu interrupts.  */
-    unsigned enabled:NCPU;
-    unsigned pending:NCPU;
-    unsigned active:NCPU;
-    unsigned level:NCPU;
-    unsigned model:1; /* 0 = N:N, 1 = 1:N */
-    unsigned trigger:1; /* nonzero = edge triggered.  */
-} gic_irq_state;
-
-#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1)))
-#if NCPU > 1
 #define NUM_CPU(s) ((s)->num_cpu)
-#else
-#define NUM_CPU(s) 1
-#endif
-
-#define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm)
-#define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm)
-#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0)
-#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
-#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
-#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
-#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
-#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
-#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
-#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
-#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
-#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
-#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
-#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
-#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
-#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
-#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
-#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
-#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ?            \
-                                    s->priority1[irq][cpu] :            \
-                                    s->priority2[(irq) - GIC_INTERNAL])
-#ifdef NVIC
-#define GIC_TARGET(irq) 1
-#else
-#define GIC_TARGET(irq) s->irq_target[irq]
-#endif
-
-typedef struct gic_state
-{
-    SysBusDevice busdev;
-    qemu_irq parent_irq[NCPU];
-    int enabled;
-    int cpu_enabled[NCPU];
-
-    gic_irq_state irq_state[GIC_MAXIRQ];
-#ifndef NVIC
-    int irq_target[GIC_MAXIRQ];
-#endif
-    int priority1[GIC_INTERNAL][NCPU];
-    int priority2[GIC_MAXIRQ - GIC_INTERNAL];
-    int last_active[GIC_MAXIRQ][NCPU];
-
-    int priority_mask[NCPU];
-    int running_irq[NCPU];
-    int running_priority[NCPU];
-    int current_pending[NCPU];
-
-#if NCPU > 1
-    uint32_t num_cpu;
-#endif
-
-    MemoryRegion iomem; /* Distributor */
-#ifndef NVIC
-    /* This is just so we can have an opaque pointer which identifies
-     * both this GIC and which CPU interface we should be accessing.
-     */
-    struct gic_state *backref[NCPU];
-    MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
-#endif
-    uint32_t num_irq;
-} gic_state;
 
 static inline int gic_get_current_cpu(gic_state *s)
 {
-#if NCPU > 1
     if (s->num_cpu > 1) {
         return cpu_single_env->cpu_index;
     }
-#endif
     return 0;
 }
 
 /* TODO: Many places that call this routine could be optimized.  */
 /* Update interrupt status after enabled or pending bits have been changed.  */
-static void gic_update(gic_state *s)
+void gic_update(gic_state *s)
 {
     int best_irq;
     int best_prio;
@@ -185,8 +84,7 @@ static void gic_update(gic_state *s)
     }
 }
 
-#ifdef NVIC
-static void gic_set_pending_private(gic_state *s, int cpu, int irq)
+void gic_set_pending_private(gic_state *s, int cpu, int irq)
 {
     int cm = 1 << cpu;
 
@@ -197,7 +95,6 @@ static void gic_set_pending_private(gic_state *s, int cpu, int irq)
     GIC_SET_PENDING(irq, cm);
     gic_update(s);
 }
-#endif
 
 /* Process a change in an external IRQ input.  */
 static void gic_set_irq(void *opaque, int irq, int level)
@@ -251,7 +148,7 @@ static void gic_set_running_irq(gic_state *s, int cpu, int irq)
     gic_update(s);
 }
 
-static uint32_t gic_acknowledge_irq(gic_state *s, int cpu)
+uint32_t gic_acknowledge_irq(gic_state *s, int cpu)
 {
     int new_irq;
     int cm = 1 << cpu;
@@ -270,7 +167,7 @@ static uint32_t gic_acknowledge_irq(gic_state *s, int cpu)
     return new_irq;
 }
 
-static void gic_complete_irq(gic_state * s, int cpu, int irq)
+void gic_complete_irq(gic_state *s, int cpu, int irq)
 {
     int update = 0;
     int cm = 1 << cpu;
@@ -328,7 +225,6 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
     cpu = gic_get_current_cpu(s);
     cm = 1 << cpu;
     if (offset < 0x100) {
-#ifndef NVIC
         if (offset == 0)
             return s->enabled;
         if (offset == 4)
@@ -339,7 +235,6 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
             /* Interrupt Security , RAZ/WI */
             return 0;
         }
-#endif
         goto bad_reg;
     } else if (offset < 0x200) {
         /* Interrupt Set/Clear Enable.  */
@@ -390,16 +285,21 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
         if (irq >= s->num_irq)
             goto bad_reg;
         res = GIC_GET_PRIORITY(irq, cpu);
-#ifndef NVIC
     } else if (offset < 0xc00) {
         /* Interrupt CPU Target.  */
-        irq = (offset - 0x800) + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq >= 29 && irq <= 31) {
-            res = cm;
+        if (s->num_cpu == 1 && s->revision != REV_11MPCORE) {
+            /* For uniprocessor GICs these RAZ/WI */
+            res = 0;
         } else {
-            res = GIC_TARGET(irq);
+            irq = (offset - 0x800) + GIC_BASE_IRQ;
+            if (irq >= s->num_irq) {
+                goto bad_reg;
+            }
+            if (irq >= 29 && irq <= 31) {
+                res = cm;
+            } else {
+                res = GIC_TARGET(irq);
+            }
         }
     } else if (offset < 0xf00) {
         /* Interrupt Configuration.  */
@@ -413,7 +313,6 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
             if (GIC_TEST_TRIGGER(irq + i))
                 res |= (2 << (i * 2));
         }
-#endif
     } else if (offset < 0xfe0) {
         goto bad_reg;
     } else /* offset >= 0xfe0 */ {
@@ -440,13 +339,6 @@ static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
 static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
 {
     uint32_t val;
-#ifdef NVIC
-    gic_state *s = (gic_state *)opaque;
-    uint32_t addr;
-    addr = offset;
-    if (addr < 0x100 || addr > 0xd00)
-        return nvic_readl(s, addr);
-#endif
     val = gic_dist_readw(opaque, offset);
     val |= gic_dist_readw(opaque, offset + 2) << 16;
     return val;
@@ -462,9 +354,6 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
 
     cpu = gic_get_current_cpu(s);
     if (offset < 0x100) {
-#ifdef NVIC
-        goto bad_reg;
-#else
         if (offset == 0) {
             s->enabled = (value & 1);
             DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
@@ -475,7 +364,6 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
         } else {
             goto bad_reg;
         }
-#endif
     } else if (offset < 0x180) {
         /* Interrupt Set Enable.  */
         irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
@@ -557,17 +445,22 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
         } else {
             s->priority2[irq - GIC_INTERNAL] = value;
         }
-#ifndef NVIC
     } else if (offset < 0xc00) {
-        /* Interrupt CPU Target.  */
-        irq = (offset - 0x800) + GIC_BASE_IRQ;
-        if (irq >= s->num_irq)
-            goto bad_reg;
-        if (irq < 29)
-            value = 0;
-        else if (irq < GIC_INTERNAL)
-            value = ALL_CPU_MASK;
-        s->irq_target[irq] = value & ALL_CPU_MASK;
+        /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the
+         * annoying exception of the 11MPCore's GIC.
+         */
+        if (s->num_cpu != 1 || s->revision == REV_11MPCORE) {
+            irq = (offset - 0x800) + GIC_BASE_IRQ;
+            if (irq >= s->num_irq) {
+                goto bad_reg;
+            }
+            if (irq < 29) {
+                value = 0;
+            } else if (irq < GIC_INTERNAL) {
+                value = ALL_CPU_MASK;
+            }
+            s->irq_target[irq] = value & ALL_CPU_MASK;
+        }
     } else if (offset < 0xf00) {
         /* Interrupt Configuration.  */
         irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
@@ -587,7 +480,6 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
                 GIC_CLEAR_TRIGGER(irq + i);
             }
         }
-#endif
     } else {
         /* 0xf00 is only handled for 32-bit writes.  */
         goto bad_reg;
@@ -609,14 +501,6 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
                             uint32_t value)
 {
     gic_state *s = (gic_state *)opaque;
-#ifdef NVIC
-    uint32_t addr;
-    addr = offset;
-    if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
-        nvic_writel(s, addr, value);
-        return;
-    }
-#endif
     if (offset == 0xf00) {
         int cpu;
         int irq;
@@ -655,7 +539,6 @@ static const MemoryRegionOps gic_dist_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-#ifndef NVIC
 static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset)
 {
     switch (offset) {
@@ -747,141 +630,12 @@ static const MemoryRegionOps gic_cpu_ops = {
     .write = gic_do_cpu_write,
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
-#endif
-
-static void gic_reset(DeviceState *dev)
-{
-    gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev));
-    int i;
-    memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
-    for (i = 0 ; i < NUM_CPU(s); i++) {
-        s->priority_mask[i] = 0xf0;
-        s->current_pending[i] = 1023;
-        s->running_irq[i] = 1023;
-        s->running_priority[i] = 0x100;
-#ifdef NVIC
-        /* The NVIC doesn't have per-cpu interfaces, so enable by default.  */
-        s->cpu_enabled[i] = 1;
-#else
-        s->cpu_enabled[i] = 0;
-#endif
-    }
-    for (i = 0; i < 16; i++) {
-        GIC_SET_ENABLED(i, ALL_CPU_MASK);
-        GIC_SET_TRIGGER(i);
-    }
-#ifdef NVIC
-    /* The NVIC is always enabled.  */
-    s->enabled = 1;
-#else
-    s->enabled = 0;
-#endif
-}
 
-static void gic_save(QEMUFile *f, void *opaque)
-{
-    gic_state *s = (gic_state *)opaque;
-    int i;
-    int j;
-
-    qemu_put_be32(f, s->enabled);
-    for (i = 0; i < NUM_CPU(s); i++) {
-        qemu_put_be32(f, s->cpu_enabled[i]);
-        for (j = 0; j < GIC_INTERNAL; j++)
-            qemu_put_be32(f, s->priority1[j][i]);
-        for (j = 0; j < s->num_irq; j++)
-            qemu_put_be32(f, s->last_active[j][i]);
-        qemu_put_be32(f, s->priority_mask[i]);
-        qemu_put_be32(f, s->running_irq[i]);
-        qemu_put_be32(f, s->running_priority[i]);
-        qemu_put_be32(f, s->current_pending[i]);
-    }
-    for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
-        qemu_put_be32(f, s->priority2[i]);
-    }
-    for (i = 0; i < s->num_irq; i++) {
-#ifndef NVIC
-        qemu_put_be32(f, s->irq_target[i]);
-#endif
-        qemu_put_byte(f, s->irq_state[i].enabled);
-        qemu_put_byte(f, s->irq_state[i].pending);
-        qemu_put_byte(f, s->irq_state[i].active);
-        qemu_put_byte(f, s->irq_state[i].level);
-        qemu_put_byte(f, s->irq_state[i].model);
-        qemu_put_byte(f, s->irq_state[i].trigger);
-    }
-}
-
-static int gic_load(QEMUFile *f, void *opaque, int version_id)
-{
-    gic_state *s = (gic_state *)opaque;
-    int i;
-    int j;
-
-    if (version_id != 2)
-        return -EINVAL;
-
-    s->enabled = qemu_get_be32(f);
-    for (i = 0; i < NUM_CPU(s); i++) {
-        s->cpu_enabled[i] = qemu_get_be32(f);
-        for (j = 0; j < GIC_INTERNAL; j++)
-            s->priority1[j][i] = qemu_get_be32(f);
-        for (j = 0; j < s->num_irq; j++)
-            s->last_active[j][i] = qemu_get_be32(f);
-        s->priority_mask[i] = qemu_get_be32(f);
-        s->running_irq[i] = qemu_get_be32(f);
-        s->running_priority[i] = qemu_get_be32(f);
-        s->current_pending[i] = qemu_get_be32(f);
-    }
-    for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
-        s->priority2[i] = qemu_get_be32(f);
-    }
-    for (i = 0; i < s->num_irq; i++) {
-#ifndef NVIC
-        s->irq_target[i] = qemu_get_be32(f);
-#endif
-        s->irq_state[i].enabled = qemu_get_byte(f);
-        s->irq_state[i].pending = qemu_get_byte(f);
-        s->irq_state[i].active = qemu_get_byte(f);
-        s->irq_state[i].level = qemu_get_byte(f);
-        s->irq_state[i].model = qemu_get_byte(f);
-        s->irq_state[i].trigger = qemu_get_byte(f);
-    }
-
-    return 0;
-}
-
-#if NCPU > 1
-static void gic_init(gic_state *s, int num_cpu, int num_irq)
-#else
-static void gic_init(gic_state *s, int num_irq)
-#endif
+void gic_init_irqs_and_distributor(gic_state *s, int num_irq)
 {
     int i;
 
-#if NCPU > 1
-    s->num_cpu = num_cpu;
-    if (s->num_cpu > NCPU) {
-        hw_error("requested %u CPUs exceeds GIC maximum %d\n",
-                 num_cpu, NCPU);
-    }
-#endif
-    s->num_irq = num_irq + GIC_BASE_IRQ;
-    if (s->num_irq > GIC_MAXIRQ) {
-        hw_error("requested %u interrupt lines exceeds GIC maximum %d\n",
-                 num_irq, GIC_MAXIRQ);
-    }
-    /* ITLinesNumber is represented as (N / 32) - 1 (see
-     * gic_dist_readb) so this is an implementation imposed
-     * restriction, not an architectural one:
-     */
-    if (s->num_irq < 32 || (s->num_irq % 32)) {
-        hw_error("%d interrupt lines unsupported: not divisible by 32\n",
-                 num_irq);
-    }
-
     i = s->num_irq - GIC_INTERNAL;
-#ifndef NVIC
     /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
      * GPIO array layout is thus:
      *  [0..N-1] SPIs
@@ -889,14 +643,27 @@ static void gic_init(gic_state *s, int num_irq)
      *  [N+32..N+63] PPIs for CPU 1
      *   ...
      */
-    i += (GIC_INTERNAL * num_cpu);
-#endif
+    if (s->revision != REV_NVIC) {
+        i += (GIC_INTERNAL * s->num_cpu);
+    }
     qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i);
     for (i = 0; i < NUM_CPU(s); i++) {
         sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
     }
     memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
-#ifndef NVIC
+}
+
+static int arm_gic_init(SysBusDevice *dev)
+{
+    /* Device instance init function for the GIC sysbus device */
+    int i;
+    gic_state *s = FROM_SYSBUS(gic_state, dev);
+    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
+
+    agc->parent_init(dev);
+
+    gic_init_irqs_and_distributor(s, s->num_irq);
+
     /* Memory regions for the CPU interfaces (NVIC doesn't have these):
      * a region for "CPU interface for this core", then a region for
      * "CPU interface for core 0", "for core 1", ...
@@ -912,19 +679,6 @@ static void gic_init(gic_state *s, int num_irq)
         memory_region_init_io(&s->cpuiomem[i+1], &gic_cpu_ops, &s->backref[i],
                               "gic_cpu", 0x100);
     }
-#endif
-
-    register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
-}
-
-#ifndef NVIC
-
-static int arm_gic_init(SysBusDevice *dev)
-{
-    /* Device instance init function for the GIC sysbus device */
-    int i;
-    gic_state *s = FROM_SYSBUS(gic_state, dev);
-    gic_init(s, s->num_cpu, s->num_irq);
     /* Distributor */
     sysbus_init_mmio(dev, &s->iomem);
     /* cpu interfaces (one for "current cpu" plus one per cpu) */
@@ -934,25 +688,19 @@ static int arm_gic_init(SysBusDevice *dev)
     return 0;
 }
 
-static Property arm_gic_properties[] = {
-    DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1),
-    DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
 static void arm_gic_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+    ARMGICClass *agc = ARM_GIC_CLASS(klass);
+    agc->parent_init = sbc->init;
     sbc->init = arm_gic_init;
-    dc->props = arm_gic_properties;
-    dc->reset = gic_reset;
     dc->no_user = 1;
 }
 
 static TypeInfo arm_gic_info = {
-    .name = "arm_gic",
-    .parent = TYPE_SYS_BUS_DEVICE,
+    .name = TYPE_ARM_GIC,
+    .parent = TYPE_ARM_GIC_COMMON,
     .instance_size = sizeof(gic_state),
     .class_init = arm_gic_class_init,
 };
@@ -963,5 +711,3 @@ static void arm_gic_register_types(void)
 }
 
 type_init(arm_gic_register_types)
-
-#endif
diff --git a/hw/arm_gic_common.c b/hw/arm_gic_common.c
new file mode 100644
index 0000000000..360e7823f7
--- /dev/null
+++ b/hw/arm_gic_common.c
@@ -0,0 +1,184 @@
+/*
+ * ARM GIC support - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2012 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "arm_gic_internal.h"
+
+static void gic_save(QEMUFile *f, void *opaque)
+{
+    gic_state *s = (gic_state *)opaque;
+    int i;
+    int j;
+
+    qemu_put_be32(f, s->enabled);
+    for (i = 0; i < s->num_cpu; i++) {
+        qemu_put_be32(f, s->cpu_enabled[i]);
+        for (j = 0; j < GIC_INTERNAL; j++) {
+            qemu_put_be32(f, s->priority1[j][i]);
+        }
+        for (j = 0; j < s->num_irq; j++) {
+            qemu_put_be32(f, s->last_active[j][i]);
+        }
+        qemu_put_be32(f, s->priority_mask[i]);
+        qemu_put_be32(f, s->running_irq[i]);
+        qemu_put_be32(f, s->running_priority[i]);
+        qemu_put_be32(f, s->current_pending[i]);
+    }
+    for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
+        qemu_put_be32(f, s->priority2[i]);
+    }
+    for (i = 0; i < s->num_irq; i++) {
+        qemu_put_be32(f, s->irq_target[i]);
+        qemu_put_byte(f, s->irq_state[i].enabled);
+        qemu_put_byte(f, s->irq_state[i].pending);
+        qemu_put_byte(f, s->irq_state[i].active);
+        qemu_put_byte(f, s->irq_state[i].level);
+        qemu_put_byte(f, s->irq_state[i].model);
+        qemu_put_byte(f, s->irq_state[i].trigger);
+    }
+}
+
+static int gic_load(QEMUFile *f, void *opaque, int version_id)
+{
+    gic_state *s = (gic_state *)opaque;
+    int i;
+    int j;
+
+    if (version_id != 3) {
+        return -EINVAL;
+    }
+
+    s->enabled = qemu_get_be32(f);
+    for (i = 0; i < s->num_cpu; i++) {
+        s->cpu_enabled[i] = qemu_get_be32(f);
+        for (j = 0; j < GIC_INTERNAL; j++) {
+            s->priority1[j][i] = qemu_get_be32(f);
+        }
+        for (j = 0; j < s->num_irq; j++) {
+            s->last_active[j][i] = qemu_get_be32(f);
+        }
+        s->priority_mask[i] = qemu_get_be32(f);
+        s->running_irq[i] = qemu_get_be32(f);
+        s->running_priority[i] = qemu_get_be32(f);
+        s->current_pending[i] = qemu_get_be32(f);
+    }
+    for (i = 0; i < s->num_irq - GIC_INTERNAL; i++) {
+        s->priority2[i] = qemu_get_be32(f);
+    }
+    for (i = 0; i < s->num_irq; i++) {
+        s->irq_target[i] = qemu_get_be32(f);
+        s->irq_state[i].enabled = qemu_get_byte(f);
+        s->irq_state[i].pending = qemu_get_byte(f);
+        s->irq_state[i].active = qemu_get_byte(f);
+        s->irq_state[i].level = qemu_get_byte(f);
+        s->irq_state[i].model = qemu_get_byte(f);
+        s->irq_state[i].trigger = qemu_get_byte(f);
+    }
+
+    return 0;
+}
+
+static int arm_gic_common_init(SysBusDevice *dev)
+{
+    gic_state *s = FROM_SYSBUS(gic_state, dev);
+    int num_irq = s->num_irq;
+
+    if (s->num_cpu > NCPU) {
+        hw_error("requested %u CPUs exceeds GIC maximum %d\n",
+                 s->num_cpu, NCPU);
+    }
+    s->num_irq += GIC_BASE_IRQ;
+    if (s->num_irq > GIC_MAXIRQ) {
+        hw_error("requested %u interrupt lines exceeds GIC maximum %d\n",
+                 num_irq, GIC_MAXIRQ);
+    }
+    /* ITLinesNumber is represented as (N / 32) - 1 (see
+     * gic_dist_readb) so this is an implementation imposed
+     * restriction, not an architectural one:
+     */
+    if (s->num_irq < 32 || (s->num_irq % 32)) {
+        hw_error("%d interrupt lines unsupported: not divisible by 32\n",
+                 num_irq);
+    }
+
+    register_savevm(NULL, "arm_gic", -1, 3, gic_save, gic_load, s);
+    return 0;
+}
+
+static void arm_gic_common_reset(DeviceState *dev)
+{
+    gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev));
+    int i;
+    memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
+    for (i = 0 ; i < s->num_cpu; i++) {
+        s->priority_mask[i] = 0xf0;
+        s->current_pending[i] = 1023;
+        s->running_irq[i] = 1023;
+        s->running_priority[i] = 0x100;
+        s->cpu_enabled[i] = 0;
+    }
+    for (i = 0; i < 16; i++) {
+        GIC_SET_ENABLED(i, ALL_CPU_MASK);
+        GIC_SET_TRIGGER(i);
+    }
+    if (s->num_cpu == 1) {
+        /* For uniprocessor GICs all interrupts always target the sole CPU */
+        for (i = 0; i < GIC_MAXIRQ; i++) {
+            s->irq_target[i] = 1;
+        }
+    }
+    s->enabled = 0;
+}
+
+static Property arm_gic_common_properties[] = {
+    DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1),
+    DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32),
+    /* Revision can be 1 or 2 for GIC architecture specification
+     * versions 1 or 2, or 0 to indicate the legacy 11MPCore GIC.
+     * (Internally, 0xffffffff also indicates "not a GIC but an NVIC".)
+     */
+    DEFINE_PROP_UINT32("revision", gic_state, revision, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arm_gic_common_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->reset = arm_gic_common_reset;
+    dc->props = arm_gic_common_properties;
+    dc->no_user = 1;
+    sc->init = arm_gic_common_init;
+}
+
+static TypeInfo arm_gic_common_type = {
+    .name = TYPE_ARM_GIC_COMMON,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(gic_state),
+    .class_size = sizeof(ARMGICCommonClass),
+    .class_init = arm_gic_common_class_init,
+    .abstract = true,
+};
+
+static void register_types(void)
+{
+    type_register_static(&arm_gic_common_type);
+}
+
+type_init(register_types)
diff --git a/hw/arm_gic_internal.h b/hw/arm_gic_internal.h
new file mode 100644
index 0000000000..db4fad564f
--- /dev/null
+++ b/hw/arm_gic_internal.h
@@ -0,0 +1,136 @@
+/*
+ * ARM GIC support - internal interfaces
+ *
+ * Copyright (c) 2012 Linaro Limited
+ * Written by Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_ARM_GIC_INTERNAL_H
+#define QEMU_ARM_GIC_INTERNAL_H
+
+#include "sysbus.h"
+
+/* Maximum number of possible interrupts, determined by the GIC architecture */
+#define GIC_MAXIRQ 1020
+/* First 32 are private to each CPU (SGIs and PPIs). */
+#define GIC_INTERNAL 32
+/* Maximum number of possible CPU interfaces, determined by GIC architecture */
+#define NCPU 8
+
+#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1)))
+
+/* The NVIC has 16 internal vectors.  However these are not exposed
+   through the normal GIC interface.  */
+#define GIC_BASE_IRQ ((s->revision == REV_NVIC) ? 32 : 0)
+
+#define GIC_SET_ENABLED(irq, cm) s->irq_state[irq].enabled |= (cm)
+#define GIC_CLEAR_ENABLED(irq, cm) s->irq_state[irq].enabled &= ~(cm)
+#define GIC_TEST_ENABLED(irq, cm) ((s->irq_state[irq].enabled & (cm)) != 0)
+#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
+#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
+#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
+#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
+#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
+#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
+#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
+#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
+#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
+#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
+#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
+#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
+#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
+#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
+#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
+#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GIC_INTERNAL) ?            \
+                                    s->priority1[irq][cpu] :            \
+                                    s->priority2[(irq) - GIC_INTERNAL])
+#define GIC_TARGET(irq) s->irq_target[irq]
+
+typedef struct gic_irq_state {
+    /* The enable bits are only banked for per-cpu interrupts.  */
+    unsigned enabled:NCPU;
+    unsigned pending:NCPU;
+    unsigned active:NCPU;
+    unsigned level:NCPU;
+    unsigned model:1; /* 0 = N:N, 1 = 1:N */
+    unsigned trigger:1; /* nonzero = edge triggered.  */
+} gic_irq_state;
+
+typedef struct gic_state {
+    SysBusDevice busdev;
+    qemu_irq parent_irq[NCPU];
+    int enabled;
+    int cpu_enabled[NCPU];
+
+    gic_irq_state irq_state[GIC_MAXIRQ];
+    int irq_target[GIC_MAXIRQ];
+    int priority1[GIC_INTERNAL][NCPU];
+    int priority2[GIC_MAXIRQ - GIC_INTERNAL];
+    int last_active[GIC_MAXIRQ][NCPU];
+
+    int priority_mask[NCPU];
+    int running_irq[NCPU];
+    int running_priority[NCPU];
+    int current_pending[NCPU];
+
+    uint32_t num_cpu;
+
+    MemoryRegion iomem; /* Distributor */
+    /* This is just so we can have an opaque pointer which identifies
+     * both this GIC and which CPU interface we should be accessing.
+     */
+    struct gic_state *backref[NCPU];
+    MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
+    uint32_t num_irq;
+    uint32_t revision;
+} gic_state;
+
+/* The special cases for the revision property: */
+#define REV_11MPCORE 0
+#define REV_NVIC 0xffffffff
+
+void gic_set_pending_private(gic_state *s, int cpu, int irq);
+uint32_t gic_acknowledge_irq(gic_state *s, int cpu);
+void gic_complete_irq(gic_state *s, int cpu, int irq);
+void gic_update(gic_state *s);
+void gic_init_irqs_and_distributor(gic_state *s, int num_irq);
+
+#define TYPE_ARM_GIC_COMMON "arm_gic_common"
+#define ARM_GIC_COMMON(obj) \
+     OBJECT_CHECK(gic_state, (obj), TYPE_ARM_GIC_COMMON)
+#define ARM_GIC_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(ARMGICCommonClass, (klass), TYPE_ARM_GIC_COMMON)
+#define ARM_GIC_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(ARMGICCommonClass, (obj), TYPE_ARM_GIC_COMMON)
+
+typedef struct ARMGICCommonClass {
+    SysBusDeviceClass parent_class;
+} ARMGICCommonClass;
+
+#define TYPE_ARM_GIC "arm_gic"
+#define ARM_GIC(obj) \
+     OBJECT_CHECK(gic_state, (obj), TYPE_ARM_GIC)
+#define ARM_GIC_CLASS(klass) \
+     OBJECT_CLASS_CHECK(ARMGICClass, (klass), TYPE_ARM_GIC)
+#define ARM_GIC_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(ARMGICClass, (obj), TYPE_ARM_GIC)
+
+typedef struct ARMGICClass {
+    ARMGICCommonClass parent_class;
+    int (*parent_init)(SysBusDevice *dev);
+} ARMGICClass;
+
+#endif /* !QEMU_ARM_GIC_INTERNAL_H */
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
index 09f290c85f..de6a0863d8 100644
--- a/hw/arm_l2x0.c
+++ b/hw/arm_l2x0.c
@@ -161,7 +161,7 @@ static int l2x0_priv_init(SysBusDevice *dev)
 }
 
 static Property l2x0_properties[] = {
-    DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
+    DEFINE_PROP_UINT32("cache-type", l2x0_state, cache_type, 0x1c100100),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index 986a6bbd0c..4867c1d5fa 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -14,13 +14,7 @@
 #include "qemu-timer.h"
 #include "arm-misc.h"
 #include "exec-memory.h"
-
-#define NVIC 1
-
-static uint32_t nvic_readl(void *opaque, uint32_t offset);
-static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
-
-#include "arm_gic.c"
+#include "arm_gic_internal.h"
 
 typedef struct {
     gic_state gic;
@@ -30,9 +24,38 @@ typedef struct {
         int64_t tick;
         QEMUTimer *timer;
     } systick;
+    MemoryRegion sysregmem;
+    MemoryRegion gic_iomem_alias;
+    MemoryRegion container;
     uint32_t num_irq;
 } nvic_state;
 
+#define TYPE_NVIC "armv7m_nvic"
+/**
+ * NVICClass:
+ * @parent_reset: the parent class' reset handler.
+ *
+ * A model of the v7M NVIC and System Controller
+ */
+typedef struct NVICClass {
+    /*< private >*/
+    ARMGICClass parent_class;
+    /*< public >*/
+    int (*parent_init)(SysBusDevice *dev);
+    void (*parent_reset)(DeviceState *dev);
+} NVICClass;
+
+#define NVIC_CLASS(klass) \
+    OBJECT_CLASS_CHECK(NVICClass, (klass), TYPE_NVIC)
+#define NVIC_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(NVICClass, (obj), TYPE_NVIC)
+#define NVIC(obj) \
+    OBJECT_CHECK(nvic_state, (obj), TYPE_NVIC)
+
+static const uint8_t nvic_id[] = {
+    0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
+};
+
 /* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
 #define SYSTICK_SCALE 1000ULL
 
@@ -358,12 +381,54 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
     case 0xd38: /* Bus Fault Address.  */
     case 0xd3c: /* Aux Fault Status.  */
         goto bad_reg;
+    case 0xf00: /* Software Triggered Interrupt Register */
+        if ((value & 0x1ff) < s->num_irq) {
+            gic_set_pending_private(&s->gic, 0, value & 0x1ff);
+        }
+        break;
     default:
     bad_reg:
         hw_error("NVIC: Bad write offset 0x%x\n", offset);
     }
 }
 
+static uint64_t nvic_sysreg_read(void *opaque, target_phys_addr_t addr,
+                                 unsigned size)
+{
+    /* At the moment we only support the ID registers for byte/word access.
+     * This is not strictly correct as a few of the other registers also
+     * allow byte access.
+     */
+    uint32_t offset = addr;
+    if (offset >= 0xfe0) {
+        if (offset & 3) {
+            return 0;
+        }
+        return nvic_id[(offset - 0xfe0) >> 2];
+    }
+    if (size == 4) {
+        return nvic_readl(opaque, offset);
+    }
+    hw_error("NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
+}
+
+static void nvic_sysreg_write(void *opaque, target_phys_addr_t addr,
+                              uint64_t value, unsigned size)
+{
+    uint32_t offset = addr;
+    if (size == 4) {
+        nvic_writel(opaque, offset, value);
+        return;
+    }
+    hw_error("NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
+}
+
+static const MemoryRegionOps nvic_sysreg_ops = {
+    .read = nvic_sysreg_read,
+    .write = nvic_sysreg_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
 static const VMStateDescription vmstate_nvic = {
     .name = "armv7m_nvic",
     .version_id = 1,
@@ -380,20 +445,55 @@ static const VMStateDescription vmstate_nvic = {
 
 static void armv7m_nvic_reset(DeviceState *dev)
 {
-    nvic_state *s = FROM_SYSBUSGIC(nvic_state, sysbus_from_qdev(dev));
-    gic_reset(&s->gic.busdev.qdev);
+    nvic_state *s = NVIC(dev);
+    NVICClass *nc = NVIC_GET_CLASS(s);
+    nc->parent_reset(dev);
+    /* Common GIC reset resets to disabled; the NVIC doesn't have
+     * per-CPU interfaces so mark our non-existent CPU interface
+     * as enabled by default.
+     */
+    s->gic.cpu_enabled[0] = 1;
+    /* The NVIC as a whole is always enabled. */
+    s->gic.enabled = 1;
     systick_reset(s);
 }
 
 static int armv7m_nvic_init(SysBusDevice *dev)
 {
-    nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
+    nvic_state *s = NVIC(dev);
+    NVICClass *nc = NVIC_GET_CLASS(s);
 
-   /* note that for the M profile gic_init() takes the number of external
-    * interrupt lines only.
-    */
-    gic_init(&s->gic, s->num_irq);
-    memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
+    /* The NVIC always has only one CPU */
+    s->gic.num_cpu = 1;
+    /* Tell the common code we're an NVIC */
+    s->gic.revision = 0xffffffff;
+    s->gic.num_irq = s->num_irq;
+    nc->parent_init(dev);
+    gic_init_irqs_and_distributor(&s->gic, s->num_irq);
+    /* The NVIC and system controller register area looks like this:
+     *  0..0xff : system control registers, including systick
+     *  0x100..0xcff : GIC-like registers
+     *  0xd00..0xfff : system control registers
+     * We use overlaying to put the GIC like registers
+     * over the top of the system control register region.
+     */
+    memory_region_init(&s->container, "nvic", 0x1000);
+    /* The system register region goes at the bottom of the priority
+     * stack as it covers the whole page.
+     */
+    memory_region_init_io(&s->sysregmem, &nvic_sysreg_ops, s,
+                          "nvic_sysregs", 0x1000);
+    memory_region_add_subregion(&s->container, 0, &s->sysregmem);
+    /* Alias the GIC region so we can get only the section of it
+     * we need, and layer it on top of the system register region.
+     */
+    memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem,
+                             0x100, 0xc00);
+    memory_region_add_subregion_overlap(&s->container, 0x100, &s->gic.iomem, 1);
+    /* Map the whole thing into system memory at the location required
+     * by the v7M architecture.
+     */
+    memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
     s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
     return 0;
 }
@@ -409,9 +509,12 @@ static Property armv7m_nvic_properties[] = {
 
 static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
 {
+    NVICClass *nc = NVIC_CLASS(klass);
     DeviceClass *dc = DEVICE_CLASS(klass);
     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
 
+    nc->parent_reset = dc->reset;
+    nc->parent_init = sdc->init;
     sdc->init = armv7m_nvic_init;
     dc->vmsd  = &vmstate_nvic;
     dc->reset = armv7m_nvic_reset;
@@ -419,10 +522,11 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
 }
 
 static TypeInfo armv7m_nvic_info = {
-    .name          = "armv7m_nvic",
-    .parent        = TYPE_SYS_BUS_DEVICE,
+    .name          = TYPE_NVIC,
+    .parent        = TYPE_ARM_GIC_COMMON,
     .instance_size = sizeof(nvic_state),
     .class_init    = armv7m_nvic_class_init,
+    .class_size    = sizeof(NVICClass),
 };
 
 static void armv7m_nvic_register_types(void)
diff --git a/hw/boards.h b/hw/boards.h
index 667177d76d..59c01d0367 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -29,6 +29,7 @@ typedef struct QEMUMachine {
     const char *default_machine_opts;
     GlobalProperty *compat_props;
     struct QEMUMachine *next;
+    const char *hw_version;
 } QEMUMachine;
 
 int qemu_register_machine(QEMUMachine *m);
diff --git a/hw/bt-sdp.c b/hw/bt-sdp.c
index 3e390ab5b9..c0431d1a40 100644
--- a/hw/bt-sdp.c
+++ b/hw/bt-sdp.c
@@ -834,7 +834,7 @@ SERVICE(hid,
     ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
     ATTRIBUTE(SVCNAME_PRIMARY, STRING("QEMU Bluetooth HID"))
     ATTRIBUTE(SVCDESC_PRIMARY, STRING("QEMU Keyboard/Mouse"))
-    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
 
     /* Profile specific */
     ATTRIBUTE(DEVICE_RELEASE_NUMBER,	UINT16(0x0091)) /* Deprecated, remove */
@@ -908,7 +908,7 @@ SERVICE(sdp,
         LIST(UUID128(SDP_SERVER_PROFILE_ID) UINT16(0x0100))
     ))
     ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
-    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
 
     /* Profile specific */
     ATTRIBUTE(VERSION_NUM_LIST, LIST(UINT16(0x0100)))
@@ -931,7 +931,7 @@ SERVICE(pnp,
         LIST(UUID128(PNP_INFO_PROFILE_ID) UINT16(0x0100))
     ))
     ATTRIBUTE(DOC_URL,         URL("http://bellard.org/qemu/user-doc.html"))
-    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU " QEMU_VERSION))
+    ATTRIBUTE(SVCPROV_PRIMARY, STRING("QEMU"))
 
     /* Profile specific */
     ATTRIBUTE(SPECIFICATION_ID, UINT16(0x0100))
diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c
index e2140aea2b..dbde3920d0 100644
--- a/hw/cadence_gem.c
+++ b/hw/cadence_gem.c
@@ -664,7 +664,7 @@ static ssize_t gem_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
          */
 
         memcpy(rxbuf, buf, size);
-        memset(rxbuf + size, 0, sizeof(rxbuf - size));
+        memset(rxbuf + size, 0, sizeof(rxbuf) - size);
         rxbuf_ptr = rxbuf;
         crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));
         if (size < 60) {
diff --git a/hw/cadence_ttc.c b/hw/cadence_ttc.c
index 2b5477b688..dd02f86eb9 100644
--- a/hw/cadence_ttc.c
+++ b/hw/cadence_ttc.c
@@ -405,7 +405,7 @@ static int cadence_ttc_init(SysBusDevice *dev)
     int i;
 
     for (i = 0; i < 3; ++i) {
-        cadence_timer_init(2500000, &s->timer[i]);
+        cadence_timer_init(133000000, &s->timer[i]);
         sysbus_init_irq(dev, &s->timer[i].irq);
     }
 
diff --git a/hw/exynos4210.c b/hw/exynos4210.c
index dd14d01b01..9c20b3f22d 100644
--- a/hw/exynos4210.c
+++ b/hw/exynos4210.c
@@ -97,11 +97,11 @@ void exynos4210_write_secondary(ARMCPU *cpu,
 Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
         unsigned long ram_size)
 {
-    qemu_irq cpu_irq[4];
-    int n;
+    qemu_irq cpu_irq[EXYNOS4210_NCPUS];
+    int i, n;
     Exynos4210State *s = g_new(Exynos4210State, 1);
     qemu_irq *irqp;
-    qemu_irq gate_irq[EXYNOS4210_IRQ_GATE_NINPUTS];
+    qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
     unsigned long mem_size;
     DeviceState *dev;
     SysBusDevice *busdev;
@@ -128,16 +128,18 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
     s->irq_table = exynos4210_init_irq(&s->irqs);
 
     /* IRQ Gate */
-    dev = qdev_create(NULL, "exynos4210.irq_gate");
-    qdev_init_nofail(dev);
-    /* Get IRQ Gate input in gate_irq */
-    for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
-        gate_irq[n] = qdev_get_gpio_in(dev, n);
-    }
-    busdev = sysbus_from_qdev(dev);
-    /* Connect IRQ Gate output to cpu_irq */
-    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
-        sysbus_connect_irq(busdev, n, cpu_irq[n]);
+    for (i = 0; i < EXYNOS4210_NCPUS; i++) {
+        dev = qdev_create(NULL, "exynos4210.irq_gate");
+        qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
+        qdev_init_nofail(dev);
+        /* Get IRQ Gate input in gate_irq */
+        for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
+            gate_irq[i][n] = qdev_get_gpio_in(dev, n);
+        }
+        busdev = sysbus_from_qdev(dev);
+
+        /* Connect IRQ Gate output to cpu_irq */
+        sysbus_connect_irq(busdev, 0, cpu_irq[i]);
     }
 
     /* Private memory region and Internal GIC */
@@ -147,7 +149,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
     busdev = sysbus_from_qdev(dev);
     sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
     for (n = 0; n < EXYNOS4210_NCPUS; n++) {
-        sysbus_connect_irq(busdev, n, gate_irq[n * 2]);
+        sysbus_connect_irq(busdev, n, gate_irq[n][0]);
     }
     for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
         s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
@@ -166,7 +168,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
     /* Map Distributer interface */
     sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
     for (n = 0; n < EXYNOS4210_NCPUS; n++) {
-        sysbus_connect_irq(busdev, n, gate_irq[n * 2 + 1]);
+        sysbus_connect_irq(busdev, n, gate_irq[n][1]);
     }
     for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
         s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
diff --git a/hw/exynos4210.h b/hw/exynos4210.h
index b1b4609054..9b1ae4c8b1 100644
--- a/hw/exynos4210.h
+++ b/hw/exynos4210.h
@@ -56,7 +56,7 @@
 /*
  * exynos4210 IRQ subsystem stub definitions.
  */
-#define EXYNOS4210_IRQ_GATE_NINPUTS 8
+#define EXYNOS4210_IRQ_GATE_NINPUTS 2 /* Internal and External GIC */
 
 #define EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ  64
 #define EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ  16
diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c
index e1b215eff0..7d03dd9ae3 100644
--- a/hw/exynos4210_gic.c
+++ b/hw/exynos4210_gic.c
@@ -362,61 +362,64 @@ static void exynos4210_gic_register_types(void)
 
 type_init(exynos4210_gic_register_types)
 
-/*
- * IRQGate struct.
- * IRQ Gate represents OR gate between GICs to pass IRQ to PIC.
+/* IRQ OR Gate struct.
+ *
+ * This device models an OR gate. There are n_in input qdev gpio lines and one
+ * output sysbus IRQ line. The output IRQ level is formed as OR between all
+ * gpio inputs.
  */
 typedef struct {
     SysBusDevice busdev;
 
-    qemu_irq pic_irq[EXYNOS4210_NCPUS]; /* output IRQs to PICs */
-    uint32_t gpio_level[EXYNOS4210_IRQ_GATE_NINPUTS]; /* Input levels */
+    uint32_t n_in;      /* inputs amount */
+    uint32_t *level;    /* input levels */
+    qemu_irq out;       /* output IRQ */
 } Exynos4210IRQGateState;
 
+static Property exynos4210_irq_gate_properties[] = {
+    DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static const VMStateDescription vmstate_exynos4210_irq_gate = {
     .name = "exynos4210.irq_gate",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(gpio_level, Exynos4210IRQGateState,
-                EXYNOS4210_IRQ_GATE_NINPUTS),
+        VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in),
         VMSTATE_END_OF_LIST()
     }
 };
 
-/* Process a change in an external IRQ input.  */
+/* Process a change in IRQ input. */
 static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
 {
-    Exynos4210IRQGateState *s =
-            (Exynos4210IRQGateState *)opaque;
-    uint32_t odd, even;
-
-    if (irq & 1) {
-        odd = irq;
-        even = irq & ~1;
-    } else {
-        even = irq;
-        odd = irq | 1;
-    }
+    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
+    uint32_t i;
 
-    assert(irq < EXYNOS4210_IRQ_GATE_NINPUTS);
-    s->gpio_level[irq] = level;
+    assert(irq < s->n_in);
 
-    if (s->gpio_level[odd] >= 1 || s->gpio_level[even] >= 1) {
-        qemu_irq_raise(s->pic_irq[even >> 1]);
-    } else {
-        qemu_irq_lower(s->pic_irq[even >> 1]);
+    s->level[irq] = level;
+
+    for (i = 0; i < s->n_in; i++) {
+        if (s->level[i] >= 1) {
+            qemu_irq_raise(s->out);
+            return;
+        }
     }
 
+    qemu_irq_lower(s->out);
+
     return;
 }
 
 static void exynos4210_irq_gate_reset(DeviceState *d)
 {
-    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)d;
+    Exynos4210IRQGateState *s =
+            DO_UPCAST(Exynos4210IRQGateState, busdev.qdev, d);
 
-    memset(&s->gpio_level, 0, sizeof(s->gpio_level));
+    memset(s->level, 0, s->n_in * sizeof(*s->level));
 }
 
 /*
@@ -424,19 +427,15 @@ static void exynos4210_irq_gate_reset(DeviceState *d)
  */
 static int exynos4210_irq_gate_init(SysBusDevice *dev)
 {
-    unsigned int i;
-    Exynos4210IRQGateState *s =
-            FROM_SYSBUS(Exynos4210IRQGateState, dev);
+    Exynos4210IRQGateState *s = FROM_SYSBUS(Exynos4210IRQGateState, dev);
 
     /* Allocate general purpose input signals and connect a handler to each of
      * them */
-    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler,
-            EXYNOS4210_IRQ_GATE_NINPUTS);
+    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler, s->n_in);
 
-    /* Connect SysBusDev irqs to device specific irqs */
-    for (i = 0; i < EXYNOS4210_NCPUS; i++) {
-        sysbus_init_irq(dev, &s->pic_irq[i]);
-    }
+    s->level = g_malloc0(s->n_in * sizeof(*s->level));
+
+    sysbus_init_irq(dev, &s->out);
 
     return 0;
 }
@@ -449,6 +448,7 @@ static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
     k->init = exynos4210_irq_gate_init;
     dc->reset = exynos4210_irq_gate_reset;
     dc->vmsd = &vmstate_exynos4210_irq_gate;
+    dc->props = exynos4210_irq_gate_properties;
 }
 
 static TypeInfo exynos4210_irq_gate_info = {
diff --git a/hw/fdc.c b/hw/fdc.c
index 30d34e3f1d..5b3224b39b 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -36,6 +36,7 @@
 #include "qdev-addr.h"
 #include "blockdev.h"
 #include "sysemu.h"
+#include "qemu-log.h"
 
 /********************************************************/
 /* debug Floppy devices */
@@ -48,9 +49,6 @@
 #define FLOPPY_DPRINTF(fmt, ...)
 #endif
 
-#define FLOPPY_ERROR(fmt, ...)                                          \
-    do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
-
 /********************************************************/
 /* Floppy drive emulation                               */
 
@@ -147,8 +145,10 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
     if (sector != fd_sector(drv)) {
 #if 0
         if (!enable_seek) {
-            FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
-                         head, track, sect, 1, drv->max_track, drv->last_sect);
+            FLOPPY_DPRINTF("error: no implicit seek %d %02x %02x"
+                           " (max=%d %02x %02x)\n",
+                           head, track, sect, 1, drv->max_track,
+                           drv->last_sect);
             return 4;
         }
 #endif
@@ -159,6 +159,10 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
         drv->sect = sect;
     }
 
+    if (drv->bs == NULL || !bdrv_is_inserted(drv->bs)) {
+        ret = 2;
+    }
+
     return ret;
 }
 
@@ -987,7 +991,8 @@ static void fdctrl_set_fifo(FDCtrl *fdctrl, int fifo_len, int do_irq)
 /* Set an error: unimplemented/unknown command */
 static void fdctrl_unimplemented(FDCtrl *fdctrl, int direction)
 {
-    FLOPPY_ERROR("unimplemented command 0x%02x\n", fdctrl->fifo[0]);
+    qemu_log_mask(LOG_UNIMP, "fdc: unimplemented command 0x%02x\n",
+                  fdctrl->fifo[0]);
     fdctrl->fifo[0] = FD_SR0_INVCMD;
     fdctrl_set_fifo(fdctrl, 1, 0);
 }
@@ -1155,7 +1160,8 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
             DMA_schedule(fdctrl->dma_chann);
             return;
         } else {
-            FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
+            FLOPPY_DPRINTF("bad dma_mode=%d direction=%d\n", dma_mode,
+                           direction);
         }
     }
     FLOPPY_DPRINTF("start non-DMA transfer\n");
@@ -1171,7 +1177,7 @@ static void fdctrl_start_transfer(FDCtrl *fdctrl, int direction)
 /* Prepare a transfer of deleted data */
 static void fdctrl_start_transfer_del(FDCtrl *fdctrl, int direction)
 {
-    FLOPPY_ERROR("fdctrl_start_transfer_del() unimplemented\n");
+    qemu_log_mask(LOG_UNIMP, "fdctrl_start_transfer_del() unimplemented\n");
 
     /* We don't handle deleted data,
      * so we don't return *ANYTHING*
@@ -1250,7 +1256,8 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
                              fdctrl->data_pos, len);
             if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
                            fdctrl->fifo, 1) < 0) {
-                FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
+                FLOPPY_DPRINTF("error writing sector %d\n",
+                               fd_sector(cur_drv));
                 fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
                 goto transfer_error;
             }
@@ -1309,7 +1316,7 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
     cur_drv = get_cur_drv(fdctrl);
     fdctrl->dsr &= ~FD_DSR_PWRDOWN;
     if (!(fdctrl->msr & FD_MSR_RQM) || !(fdctrl->msr & FD_MSR_DIO)) {
-        FLOPPY_ERROR("controller not ready for reading\n");
+        FLOPPY_DPRINTF("error: controller not ready for reading\n");
         return 0;
     }
     pos = fdctrl->data_pos;
@@ -1393,7 +1400,7 @@ static void fdctrl_format_sector(FDCtrl *fdctrl)
     memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
     if (cur_drv->bs == NULL ||
         bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
-        FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv));
+        FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv));
         fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
     } else {
         if (cur_drv->sect == cur_drv->last_sect) {
@@ -1768,7 +1775,7 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
         return;
     }
     if (!(fdctrl->msr & FD_MSR_RQM) || (fdctrl->msr & FD_MSR_DIO)) {
-        FLOPPY_ERROR("controller not ready for writing\n");
+        FLOPPY_DPRINTF("error: controller not ready for writing\n");
         return;
     }
     fdctrl->dsr &= ~FD_DSR_PWRDOWN;
@@ -1782,7 +1789,8 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
             fdctrl->data_pos == fdctrl->data_len) {
             cur_drv = get_cur_drv(fdctrl);
             if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
-                FLOPPY_ERROR("writing sector %d\n", fd_sector(cur_drv));
+                FLOPPY_DPRINTF("error writing sector %d\n",
+                               fd_sector(cur_drv));
                 return;
             }
             if (!fdctrl_seek_to_next_sect(fdctrl, cur_drv)) {
@@ -1888,6 +1896,26 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
     return 0;
 }
 
+ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
+{
+    ISADevice *dev;
+
+    dev = isa_try_create(bus, "isa-fdc");
+    if (!dev) {
+        return NULL;
+    }
+
+    if (fds[0]) {
+        qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
+    }
+    if (fds[1]) {
+        qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
+    }
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
 void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
                         target_phys_addr_t mmio_base, DriveInfo **fds)
 {
diff --git a/hw/fdc.h b/hw/fdc.h
index 55a8d732c1..1b32b17bef 100644
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -1,32 +1,12 @@
 #ifndef HW_FDC_H
 #define HW_FDC_H
 
-#include "isa.h"
-#include "blockdev.h"
+#include "qemu-common.h"
 
 /* fdc.c */
 #define MAX_FD 2
 
-static inline ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
-{
-    ISADevice *dev;
-
-    dev = isa_try_create(bus, "isa-fdc");
-    if (!dev) {
-        return NULL;
-    }
-
-    if (fds[0]) {
-        qdev_prop_set_drive_nofail(&dev->qdev, "driveA", fds[0]->bdrv);
-    }
-    if (fds[1]) {
-        qdev_prop_set_drive_nofail(&dev->qdev, "driveB", fds[1]->bdrv);
-    }
-    qdev_init_nofail(&dev->qdev);
-
-    return dev;
-}
-
+ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds);
 void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
                         target_phys_addr_t mmio_base, DriveInfo **fds);
 void sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
diff --git a/hw/i2c.c b/hw/i2c.c
index 23dfccba14..296bece119 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -17,13 +17,18 @@ struct i2c_bus
     uint8_t saved_address;
 };
 
-static struct BusInfo i2c_bus_info = {
-    .name = "I2C",
-    .size = sizeof(i2c_bus),
-    .props = (Property[]) {
-        DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property i2c_props[] = {
+    DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+#define TYPE_I2C_BUS "i2c-bus"
+#define I2C_BUS(obj) OBJECT_CHECK(i2c_bus, (obj), TYPE_I2C_BUS)
+
+static const TypeInfo i2c_bus_info = {
+    .name = TYPE_I2C_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(i2c_bus),
 };
 
 static void i2c_bus_pre_save(void *opaque)
@@ -61,7 +66,7 @@ i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
 {
     i2c_bus *bus;
 
-    bus = FROM_QBUS(i2c_bus, qbus_create(&i2c_bus_info, parent, name));
+    bus = FROM_QBUS(i2c_bus, qbus_create(TYPE_I2C_BUS, parent, name));
     vmstate_register(NULL, -1, &vmstate_i2c_bus, bus);
     return bus;
 }
@@ -81,11 +86,12 @@ int i2c_bus_busy(i2c_bus *bus)
 /* TODO: Make this handle multiple masters.  */
 int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
 {
-    DeviceState *qdev;
+    BusChild *kid;
     I2CSlave *slave = NULL;
     I2CSlaveClass *sc;
 
-    QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
+    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
         I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
         if (candidate->address == address) {
             slave = candidate;
@@ -218,7 +224,8 @@ static void i2c_slave_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
     k->init = i2c_slave_qdev_init;
-    k->bus_info = &i2c_bus_info;
+    k->bus_type = TYPE_I2C_BUS;
+    k->props = i2c_props;
 }
 
 static TypeInfo i2c_slave_type_info = {
@@ -232,6 +239,7 @@ static TypeInfo i2c_slave_type_info = {
 
 static void i2c_slave_register_types(void)
 {
+    type_register_static(&i2c_bus_info);
     type_register_static(&i2c_slave_type_info);
 }
 
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs
index d43f1df5f0..eb171b7c47 100644
--- a/hw/i386/Makefile.objs
+++ b/hw/i386/Makefile.objs
@@ -7,7 +7,7 @@ obj-y += debugcon.o multiboot.o
 obj-y += pc_piix.o
 obj-y += pc_sysfw.o
 obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o
-obj-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o kvm/i8254.o
+obj-y += kvm/
 obj-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 obj-y := $(addprefix ../,$(obj-y))
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 2d7d03d772..e275e68934 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -339,7 +339,7 @@ static void ahci_mem_write(void *opaque, target_phys_addr_t addr,
             case HOST_CTL: /* R/W */
                 if (val & HOST_CTL_RESET) {
                     DPRINTF(-1, "HBA Reset\n");
-                    ahci_reset(container_of(s, AHCIPCIState, ahci));
+                    ahci_reset(s);
                 } else {
                     s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
                     ahci_check_irq(s);
@@ -1149,21 +1149,20 @@ void ahci_uninit(AHCIState *s)
     g_free(s->dev);
 }
 
-void ahci_reset(void *opaque)
+void ahci_reset(AHCIState *s)
 {
-    struct AHCIPCIState *d = opaque;
     AHCIPortRegs *pr;
     int i;
 
-    d->ahci.control_regs.irqstatus = 0;
-    d->ahci.control_regs.ghc = 0;
+    s->control_regs.irqstatus = 0;
+    s->control_regs.ghc = 0;
 
-    for (i = 0; i < d->ahci.ports; i++) {
-        pr = &d->ahci.dev[i].port_regs;
+    for (i = 0; i < s->ports; i++) {
+        pr = &s->dev[i].port_regs;
         pr->irq_stat = 0;
         pr->irq_mask = 0;
         pr->scr_ctl = 0;
-        ahci_reset_port(&d->ahci, i);
+        ahci_reset_port(s, i);
     }
 }
 
@@ -1178,6 +1177,13 @@ static const VMStateDescription vmstate_sysbus_ahci = {
     .unmigratable = 1,
 };
 
+static void sysbus_ahci_reset(DeviceState *dev)
+{
+    SysbusAHCIState *s = DO_UPCAST(SysbusAHCIState, busdev.qdev, dev);
+
+    ahci_reset(&s->ahci);
+}
+
 static int sysbus_ahci_init(SysBusDevice *dev)
 {
     SysbusAHCIState *s = FROM_SYSBUS(SysbusAHCIState, dev);
@@ -1185,8 +1191,6 @@ static int sysbus_ahci_init(SysBusDevice *dev)
 
     sysbus_init_mmio(dev, &s->ahci.mem);
     sysbus_init_irq(dev, &s->ahci.irq);
-
-    qemu_register_reset(ahci_reset, &s->ahci);
     return 0;
 }
 
@@ -1203,6 +1207,7 @@ static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
     sbc->init = sysbus_ahci_init;
     dc->vmsd = &vmstate_sysbus_ahci;
     dc->props = sysbus_ahci_properties;
+    dc->reset = sysbus_ahci_reset;
 }
 
 static TypeInfo sysbus_ahci_info = {
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index b223d2c055..ec1b6a5f66 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -332,6 +332,6 @@ typedef struct NCQFrame {
 void ahci_init(AHCIState *s, DeviceState *qdev, int ports);
 void ahci_uninit(AHCIState *s);
 
-void ahci_reset(void *opaque);
+void ahci_reset(AHCIState *s);
 
 #endif /* HW_IDE_AHCI_H */
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9785d5f713..71d4d7732a 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1047,6 +1047,7 @@ static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
 
 void ide_exec_cmd(IDEBus *bus, uint32_t val)
 {
+    uint16_t *identify_data;
     IDEState *s;
     int n;
     int lba48 = 0;
@@ -1231,10 +1232,21 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
             goto abort_cmd;
         /* XXX: valid for CDROM ? */
         switch(s->feature) {
-        case 0xcc: /* reverting to power-on defaults enable */
-        case 0x66: /* reverting to power-on defaults disable */
         case 0x02: /* write cache enable */
+            bdrv_set_enable_write_cache(s->bs, true);
+            identify_data = (uint16_t *)s->identify_data;
+            put_le16(identify_data + 85, (1 << 14) | (1 << 5) | 1);
+            s->status = READY_STAT | SEEK_STAT;
+            ide_set_irq(s->bus);
+            break;
         case 0x82: /* write cache disable */
+            bdrv_set_enable_write_cache(s->bs, false);
+            identify_data = (uint16_t *)s->identify_data;
+            put_le16(identify_data + 85, (1 << 14) | 1);
+            ide_flush_cache(s);
+            break;
+        case 0xcc: /* reverting to power-on defaults enable */
+        case 0x66: /* reverting to power-on defaults disable */
         case 0xaa: /* read look-ahead enable */
         case 0x55: /* read look-ahead disable */
         case 0x05: /* set advanced power management mode */
@@ -1250,7 +1262,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
             break;
         case 0x03: { /* set transfer mode */
 		uint8_t val = s->nsector & 0x07;
-            uint16_t *identify_data = (uint16_t *)s->identify_data;
+		identify_data = (uint16_t *)s->identify_data;
 
 		switch (s->nsector >> 3) {
 		case 0x00: /* pio default */
@@ -1983,7 +1995,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind,
     if (version) {
         pstrcpy(s->version, sizeof(s->version), version);
     } else {
-        pstrcpy(s->version, sizeof(s->version), QEMU_VERSION);
+        pstrcpy(s->version, sizeof(s->version), qemu_get_version());
     }
 
     ide_reset(s);
@@ -2146,6 +2158,9 @@ static int ide_drive_post_load(void *opaque, int version_id)
             s->cdrom_changed = 1;
         }
     }
+    if (s->identify_set) {
+        bdrv_set_enable_write_cache(s->bs, !!(s->identify_data[85] & (1 << 5)));
+    }
     return 0;
 }
 
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 560ae37618..e3eaaea882 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -84,6 +84,13 @@ static const VMStateDescription vmstate_ahci = {
     .unmigratable = 1,
 };
 
+static void pci_ich9_reset(DeviceState *dev)
+{
+    struct AHCIPCIState *d = DO_UPCAST(struct AHCIPCIState, card.qdev, dev);
+
+    ahci_reset(&d->ahci);
+}
+
 static int pci_ich9_ahci_init(PCIDevice *dev)
 {
     struct AHCIPCIState *d;
@@ -102,8 +109,6 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
     /* XXX Software should program this register */
     d->card.config[0x90]   = 1 << 6; /* Address Map Register - AHCI mode */
 
-    qemu_register_reset(ahci_reset, d);
-
     msi_init(dev, 0x50, 1, true, false);
     d->ahci.irq = d->card.irq[0];
 
@@ -133,19 +138,11 @@ static int pci_ich9_uninit(PCIDevice *dev)
     d = DO_UPCAST(struct AHCIPCIState, card, dev);
 
     msi_uninit(dev);
-    qemu_unregister_reset(ahci_reset, d);
     ahci_uninit(&d->ahci);
 
     return 0;
 }
 
-static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr,
-                                  uint32_t val, int len)
-{
-    pci_default_write_config(pci, addr, val, len);
-    msi_write_config(pci, addr, val, len);
-}
-
 static void ich_ahci_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -153,12 +150,12 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data)
 
     k->init = pci_ich9_ahci_init;
     k->exit = pci_ich9_uninit;
-    k->config_write = pci_ich9_write_config;
     k->vendor_id = PCI_VENDOR_ID_INTEL;
     k->device_id = PCI_DEVICE_ID_INTEL_82801IR;
     k->revision = 0x02;
     k->class_id = PCI_CLASS_STORAGE_SATA;
     dc->vmsd = &vmstate_ahci;
+    dc->reset = pci_ich9_reset;
 }
 
 static TypeInfo ich_ahci_info = {
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index f8a027d0e4..1a02f57bf5 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -25,6 +25,9 @@ typedef struct IDEState IDEState;
 typedef struct IDEDMA IDEDMA;
 typedef struct IDEDMAOps IDEDMAOps;
 
+#define TYPE_IDE_BUS "IDE"
+#define IDE_BUS(obj) OBJECT_CHECK(IDEBus, (obj), TYPE_IDE_BUS)
+
 /* Bits of HD_STATUS */
 #define ERR_STAT		0x01
 #define INDEX_STAT		0x02
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index bcaa400e2d..f5a74c293a 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -22,11 +22,12 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+
 #include <hw/hw.h>
 #include <hw/pc.h>
 #include <hw/pci.h>
 #include <hw/isa.h>
-#include "block.h"
+#include "blockdev.h"
 #include "sysemu.h"
 #include "dma.h"
 
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index a46578d685..c122395401 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -27,19 +27,28 @@
 
 static char *idebus_get_fw_dev_path(DeviceState *dev);
 
-static struct BusInfo ide_bus_info = {
-    .name  = "IDE",
-    .size  = sizeof(IDEBus),
-    .get_fw_dev_path = idebus_get_fw_dev_path,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property ide_props[] = {
+    DEFINE_PROP_UINT32("unit", IDEDevice, unit, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ide_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->get_fw_dev_path = idebus_get_fw_dev_path;
+}
+
+static const TypeInfo ide_bus_info = {
+    .name = TYPE_IDE_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(IDEBus),
+    .class_init = ide_bus_class_init,
 };
 
 void ide_bus_new(IDEBus *idebus, DeviceState *dev, int bus_id)
 {
-    qbus_create_inplace(&idebus->qbus, &ide_bus_info, dev, NULL);
+    qbus_create_inplace(&idebus->qbus, TYPE_IDE_BUS, dev, NULL);
     idebus->bus_id = bus_id;
 }
 
@@ -248,7 +257,8 @@ static void ide_device_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
     k->init = ide_qdev_init;
-    k->bus_info = &ide_bus_info;
+    k->bus_type = TYPE_IDE_BUS;
+    k->props = ide_props;
 }
 
 static TypeInfo ide_device_type_info = {
@@ -262,6 +272,7 @@ static TypeInfo ide_device_type_info = {
 
 static void ide_register_types(void)
 {
+    type_register_static(&ide_bus_info);
     type_register_static(&ide_hd_info);
     type_register_static(&ide_cd_info);
     type_register_static(&ide_drive_info);
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index bb11af286a..31fe1c54f6 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -29,20 +29,22 @@
 /* --------------------------------------------------------------------- */
 /* hda bus                                                               */
 
-static struct BusInfo hda_codec_bus_info = {
-    .name      = "HDA",
-    .size      = sizeof(HDACodecBus),
-    .props     = (Property[]) {
-        DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property hda_props[] = {
+    DEFINE_PROP_UINT32("cad", HDACodecDevice, cad, -1),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static const TypeInfo hda_codec_bus_info = {
+    .name = TYPE_HDA_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(HDACodecBus),
 };
 
 void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
                         hda_codec_response_func response,
                         hda_codec_xfer_func xfer)
 {
-    qbus_create_inplace(&bus->qbus, &hda_codec_bus_info, dev, NULL);
+    qbus_create_inplace(&bus->qbus, TYPE_HDA_BUS, dev, NULL);
     bus->response = response;
     bus->xfer = xfer;
 }
@@ -76,10 +78,11 @@ static int hda_codec_dev_exit(DeviceState *qdev)
 
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
 {
-    DeviceState *qdev;
+    BusChild *kid;
     HDACodecDevice *cdev;
 
-    QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
+    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         if (cdev->cad == cad) {
             return cdev;
@@ -481,10 +484,11 @@ static void intel_hda_parse_bdl(IntelHDAState *d, IntelHDAStream *st)
 
 static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool running, bool output)
 {
-    DeviceState *qdev;
+    BusChild *kid;
     HDACodecDevice *cdev;
 
-    QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+    QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
         HDACodecDeviceClass *cdc;
 
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
@@ -1103,15 +1107,16 @@ static const MemoryRegionOps intel_hda_mmio_ops = {
 
 static void intel_hda_reset(DeviceState *dev)
 {
+    BusChild *kid;
     IntelHDAState *d = DO_UPCAST(IntelHDAState, pci.qdev, dev);
-    DeviceState *qdev;
     HDACodecDevice *cdev;
 
     intel_hda_regs_reset(d);
     d->wall_base_ns = qemu_get_clock_ns(vm_clock);
 
     /* reset codecs */
-    QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+    QTAILQ_FOREACH(kid, &d->codecs.qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
         cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
         device_reset(DEVICE(cdev));
         d->state_sts |= (1 << cdev->cad);
@@ -1153,17 +1158,6 @@ static int intel_hda_exit(PCIDevice *pci)
     return 0;
 }
 
-static void intel_hda_write_config(PCIDevice *pci, uint32_t addr,
-                                   uint32_t val, int len)
-{
-    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
-
-    pci_default_write_config(pci, addr, val, len);
-    if (d->msi) {
-        msi_write_config(pci, addr, val, len);
-    }
-}
-
 static int intel_hda_post_load(void *opaque, int version)
 {
     IntelHDAState* d = opaque;
@@ -1252,7 +1246,6 @@ static void intel_hda_class_init(ObjectClass *klass, void *data)
 
     k->init = intel_hda_init;
     k->exit = intel_hda_exit;
-    k->config_write = intel_hda_write_config;
     k->vendor_id = PCI_VENDOR_ID_INTEL;
     k->device_id = 0x2668;
     k->revision = 1;
@@ -1275,7 +1268,8 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data)
     DeviceClass *k = DEVICE_CLASS(klass);
     k->init = hda_codec_dev_init;
     k->exit = hda_codec_dev_exit;
-    k->bus_info = &hda_codec_bus_info;
+    k->bus_type = TYPE_HDA_BUS;
+    k->props = hda_props;
 }
 
 static TypeInfo hda_codec_device_type_info = {
@@ -1289,6 +1283,7 @@ static TypeInfo hda_codec_device_type_info = {
 
 static void intel_hda_register_types(void)
 {
+    type_register_static(&hda_codec_bus_info);
     type_register_static(&intel_hda_info);
     type_register_static(&hda_codec_device_type_info);
 }
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index a1cca5b1bb..22e0968d50 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -14,6 +14,9 @@
 #define HDA_CODEC_DEVICE_GET_CLASS(obj) \
      OBJECT_GET_CLASS(HDACodecDeviceClass, (obj), TYPE_HDA_CODEC_DEVICE)
 
+#define TYPE_HDA_BUS "HDA"
+#define HDA_BUS(obj) OBJECT_CHECK(HDACodecBus, (obj), TYPE_HDA_BUS)
+
 typedef struct HDACodecBus HDACodecBus;
 typedef struct HDACodecDevice HDACodecDevice;
 
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index 1632d31c19..0a2601cac4 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -71,7 +71,6 @@ static void ioh3420_write_config(PCIDevice *d,
         pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
 
     pci_bridge_write_config(d, address, val, len);
-    msi_write_config(d, address, val, len);
     ioh3420_aer_vector_update(d);
     pcie_cap_slot_write_config(d, address, val, len);
     pcie_aer_write_config(d, address, val, len);
@@ -81,7 +80,7 @@ static void ioh3420_write_config(PCIDevice *d,
 static void ioh3420_reset(DeviceState *qdev)
 {
     PCIDevice *d = PCI_DEVICE(qdev);
-    msi_reset(d);
+
     ioh3420_aer_vector_update(d);
     pcie_cap_root_reset(d);
     pcie_cap_deverr_reset(d);
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 5a43f03a7c..f9b237387a 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -28,11 +28,19 @@ target_phys_addr_t isa_mem_base = 0;
 static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent);
 static char *isabus_get_fw_dev_path(DeviceState *dev);
 
-static struct BusInfo isa_bus_info = {
-    .name      = "ISA",
-    .size      = sizeof(ISABus),
-    .print_dev = isabus_dev_print,
-    .get_fw_dev_path = isabus_get_fw_dev_path,
+static void isa_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->print_dev = isabus_dev_print;
+    k->get_fw_dev_path = isabus_get_fw_dev_path;
+}
+
+static const TypeInfo isa_bus_info = {
+    .name = TYPE_ISA_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(ISABus),
+    .class_init = isa_bus_class_init,
 };
 
 ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io)
@@ -46,7 +54,7 @@ ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io)
         qdev_init_nofail(dev);
     }
 
-    isabus = FROM_QBUS(ISABus, qbus_create(&isa_bus_info, dev, NULL));
+    isabus = FROM_QBUS(ISABus, qbus_create(TYPE_ISA_BUS, dev, NULL));
     isabus->address_space_io = address_space_io;
     return isabus;
 }
@@ -198,7 +206,7 @@ static void isa_device_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
     k->init = isa_qdev_init;
-    k->bus_info = &isa_bus_info;
+    k->bus_type = TYPE_ISA_BUS;
 }
 
 static TypeInfo isa_device_type_info = {
@@ -212,6 +220,7 @@ static TypeInfo isa_device_type_info = {
 
 static void isabus_register_types(void)
 {
+    type_register_static(&isa_bus_info);
     type_register_static(&isabus_bridge_info);
     type_register_static(&isa_device_type_info);
 }
diff --git a/hw/isa.h b/hw/isa.h
index f7bc4b5a95..dc970527ae 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -9,8 +9,6 @@
 
 #define ISA_NUM_IRQS 16
 
-typedef struct ISADevice ISADevice;
-
 #define TYPE_ISA_DEVICE "isa-device"
 #define ISA_DEVICE(obj) \
      OBJECT_CHECK(ISADevice, (obj), TYPE_ISA_DEVICE)
@@ -19,6 +17,9 @@ typedef struct ISADevice ISADevice;
 #define ISA_DEVICE_GET_CLASS(obj) \
      OBJECT_GET_CLASS(ISADeviceClass, (obj), TYPE_ISA_DEVICE)
 
+#define TYPE_ISA_BUS "ISA"
+#define ISA_BUS(obj) OBJECT_CHECK(ISABus, (obj), TYPE_ISA_BUS)
+
 typedef struct ISADeviceClass {
     DeviceClass parent_class;
     int (*init)(ISADevice *dev);
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index d48e5f9906..05559b639c 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -530,7 +530,6 @@ static void ivshmem_reset(DeviceState *d)
     IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
 
     s->intrstatus = 0;
-    msix_reset(&s->dev);
     ivshmem_use_msix(s);
     return;
 }
diff --git a/hw/kvm/Makefile.objs b/hw/kvm/Makefile.objs
new file mode 100644
index 0000000000..226497a58f
--- /dev/null
+++ b/hw/kvm/Makefile.objs
@@ -0,0 +1 @@
+obj-$(CONFIG_KVM) += clock.o apic.o i8259.o ioapic.o i8254.o
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index f022a02447..2fe141d24e 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -1677,9 +1677,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
         }
         if (val & LSI_SCNTL1_RST) {
             if (!(s->sstat0 & LSI_SSTAT0_RST)) {
-                DeviceState *dev;
+                BusChild *kid;
 
-                QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) {
+                QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+                    DeviceState *dev = kid->child;
                     device_reset(dev);
                 }
                 s->sstat0 |= LSI_SSTAT0_RST;
diff --git a/hw/m48t59.c b/hw/m48t59.c
index 0c50f450ad..dd6cb37ba6 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -65,7 +65,7 @@ struct M48t59State {
     /* NVRAM storage */
     uint8_t *buffer;
     /* Model parameters */
-    uint32_t type; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
+    uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
     /* NVRAM storage */
     uint16_t addr;
     uint8_t  lock;
@@ -197,10 +197,11 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
 	NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
 
     /* check for NVRAM access */
-    if ((NVRAM->type == 2 && addr < 0x7f8) ||
-        (NVRAM->type == 8 && addr < 0x1ff8) ||
-        (NVRAM->type == 59 && addr < 0x1ff0))
+    if ((NVRAM->model == 2 && addr < 0x7f8) ||
+        (NVRAM->model == 8 && addr < 0x1ff8) ||
+        (NVRAM->model == 59 && addr < 0x1ff0)) {
         goto do_write;
+    }
 
     /* TOD access */
     switch (addr) {
@@ -334,10 +335,11 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
 	tmp = from_bcd(val);
 	if (tmp >= 0 && tmp <= 99) {
 	    get_time(NVRAM, &tm);
-            if (NVRAM->type == 8)
+            if (NVRAM->model == 8) {
                 tm.tm_year = from_bcd(val) + 68; // Base year is 1968
-            else
+            } else {
                 tm.tm_year = from_bcd(val);
+            }
 	    set_time(NVRAM, &tm);
 	}
         break;
@@ -362,10 +364,11 @@ uint32_t m48t59_read (void *opaque, uint32_t addr)
     uint32_t retval = 0xFF;
 
     /* check for NVRAM access */
-    if ((NVRAM->type == 2 && addr < 0x078f) ||
-        (NVRAM->type == 8 && addr < 0x1ff8) ||
-        (NVRAM->type == 59 && addr < 0x1ff0))
+    if ((NVRAM->model == 2 && addr < 0x078f) ||
+        (NVRAM->model == 8 && addr < 0x1ff8) ||
+        (NVRAM->model == 59 && addr < 0x1ff0)) {
         goto do_read;
+    }
 
     /* TOD access */
     switch (addr) {
@@ -439,10 +442,11 @@ uint32_t m48t59_read (void *opaque, uint32_t addr)
     case 0x07FF:
         /* year */
         get_time(NVRAM, &tm);
-        if (NVRAM->type == 8)
+        if (NVRAM->model == 8) {
             retval = to_bcd(tm.tm_year - 68); // Base year is 1968
-        else
+        } else {
             retval = to_bcd(tm.tm_year);
+        }
         break;
     default:
         /* Check lock registers state */
@@ -633,7 +637,7 @@ static const MemoryRegionOps m48t59_io_ops = {
 
 /* Initialisation routine */
 M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base,
-                         uint32_t io_base, uint16_t size, int type)
+                         uint32_t io_base, uint16_t size, int model)
 {
     DeviceState *dev;
     SysBusDevice *s;
@@ -641,7 +645,7 @@ M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base,
     M48t59State *state;
 
     dev = qdev_create(NULL, "m48t59");
-    qdev_prop_set_uint32(dev, "type", type);
+    qdev_prop_set_uint32(dev, "model", model);
     qdev_prop_set_uint32(dev, "size", size);
     qdev_prop_set_uint32(dev, "io_base", io_base);
     qdev_init_nofail(dev);
@@ -661,14 +665,14 @@ M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base,
 }
 
 M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
-                             int type)
+                             int model)
 {
     M48t59ISAState *d;
     ISADevice *dev;
     M48t59State *s;
 
     dev = isa_create(bus, "m48t59_isa");
-    qdev_prop_set_uint32(&dev->qdev, "type", type);
+    qdev_prop_set_uint32(&dev->qdev, "model", model);
     qdev_prop_set_uint32(&dev->qdev, "size", size);
     qdev_prop_set_uint32(&dev->qdev, "io_base", io_base);
     qdev_init_nofail(&dev->qdev);
@@ -686,7 +690,7 @@ M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
 static void m48t59_init_common(M48t59State *s)
 {
     s->buffer = g_malloc0(s->size);
-    if (s->type == 59) {
+    if (s->model == 59) {
         s->alrm_timer = qemu_new_timer_ns(rtc_clock, &alarm_cb, s);
         s->wd_timer = qemu_new_timer_ns(vm_clock, &watchdog_cb, s);
     }
@@ -722,7 +726,7 @@ static int m48t59_init1(SysBusDevice *dev)
 
 static Property m48t59_isa_properties[] = {
     DEFINE_PROP_UINT32("size",    M48t59ISAState, state.size,    -1),
-    DEFINE_PROP_UINT32("type",    M48t59ISAState, state.type,    -1),
+    DEFINE_PROP_UINT32("model",   M48t59ISAState, state.model,   -1),
     DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base,  0),
     DEFINE_PROP_END_OF_LIST(),
 };
@@ -746,7 +750,7 @@ static TypeInfo m48t59_isa_info = {
 
 static Property m48t59_properties[] = {
     DEFINE_PROP_UINT32("size",    M48t59SysBusState, state.size,    -1),
-    DEFINE_PROP_UINT32("type",    M48t59SysBusState, state.type,    -1),
+    DEFINE_PROP_UINT32("model",   M48t59SysBusState, state.model,   -1),
     DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base,  0),
     DEFINE_PROP_END_OF_LIST(),
 };
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index dfd7b6b113..351c88ebca 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -959,7 +959,7 @@ void mips_malta_init (ram_addr_t ram_size,
     pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
     pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
     smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
-                          isa_get_irq(NULL, 9), NULL, 0);
+                          isa_get_irq(NULL, 9), NULL, 0, NULL);
     /* TODO: Populate SPD eeprom data.  */
     smbus_eeprom_init(smbus, 8, NULL, 0);
     pit = pit_init(isa_bus, 0x40, 0, NULL);
diff --git a/hw/msi.c b/hw/msi.c
index 5d6ceb6df0..52332041e7 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -175,7 +175,7 @@ void msi_uninit(struct PCIDevice *dev)
     uint16_t flags;
     uint8_t cap_size;
 
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSI)) {
+    if (!msi_present(dev)) {
         return;
     }
     flags = pci_get_word(dev->config + msi_flags_off(dev));
@@ -191,6 +191,10 @@ void msi_reset(PCIDevice *dev)
     uint16_t flags;
     bool msi64bit;
 
+    if (!msi_present(dev)) {
+        return;
+    }
+
     flags = pci_get_word(dev->config + msi_flags_off(dev));
     flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
     msi64bit = flags & PCI_MSI_FLAGS_64BIT;
@@ -260,7 +264,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
     stl_le_phys(address, data);
 }
 
-/* call this function after updating configs by pci_default_write_config(). */
+/* Normally called by pci_default_write_config(). */
 void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
 {
     uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
@@ -272,7 +276,8 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
     unsigned int vector;
     uint32_t pending;
 
-    if (!ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
+    if (!msi_present(dev) ||
+        !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
         return;
     }
 
diff --git a/hw/msix.c b/hw/msix.c
index 59c7a8388f..ded3c55b92 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -187,7 +187,7 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
     int vector;
     bool was_masked;
 
-    if (!range_covers_byte(addr, len, enable_pos)) {
+    if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) {
         return;
     }
 
@@ -319,8 +319,9 @@ static void msix_free_irq_entries(PCIDevice *dev)
 /* Clean up resources for the device. */
 int msix_uninit(PCIDevice *dev, MemoryRegion *bar)
 {
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
+    if (!msix_present(dev)) {
         return 0;
+    }
     pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH);
     dev->msix_cap = 0;
     msix_free_irq_entries(dev);
@@ -339,7 +340,7 @@ void msix_save(PCIDevice *dev, QEMUFile *f)
 {
     unsigned n = dev->msix_entries_nr;
 
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
+    if (!msix_present(dev)) {
         return;
     }
 
@@ -353,7 +354,7 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
     unsigned n = dev->msix_entries_nr;
     unsigned int vector;
 
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
+    if (!msix_present(dev)) {
         return;
     }
 
@@ -407,8 +408,9 @@ void msix_notify(PCIDevice *dev, unsigned vector)
 
 void msix_reset(PCIDevice *dev)
 {
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
+    if (!msix_present(dev)) {
         return;
+    }
     msix_free_irq_entries(dev);
     dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
 	    ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
@@ -447,8 +449,9 @@ void msix_vector_unuse(PCIDevice *dev, unsigned vector)
 
 void msix_unuse_all_vectors(PCIDevice *dev)
 {
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
+    if (!msix_present(dev)) {
         return;
+    }
     msix_free_irq_entries(dev);
 }
 
diff --git a/hw/nseries.c b/hw/nseries.c
index fcc85466e7..4df2670327 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -1247,7 +1247,8 @@ static int n8x0_atag_setup(void *p, int model)
     stw_raw(w ++, 24);				/* u16 len */
     strcpy((void *) w, "hw-build");		/* char component[12] */
     w += 6;
-    strcpy((void *) w, "QEMU " QEMU_VERSION);	/* char version[12] */
+    strcpy((void *) w, "QEMU ");
+    pstrcat((void *) w, 12, qemu_get_version()); /* char version[12] */
     w += 6;
 
     tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu";
diff --git a/hw/omap.h b/hw/omap.h
index 2819e5df9a..3d98941b72 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -998,7 +998,6 @@ enum {
 #define OMAP_GPIOSW_OUTPUT	0x0002
 
 # define TCMI_VERBOSE			1
-//# define MEM_VERBOSE			1
 
 # ifdef TCMI_VERBOSE
 #  define OMAP_8B_REG(paddr)		\
@@ -1018,98 +1017,4 @@ enum {
 
 # define OMAP_MPUI_REG_MASK		0x000007ff
 
-# ifdef MEM_VERBOSE
-struct io_fn {
-    CPUReadMemoryFunc * const *mem_read;
-    CPUWriteMemoryFunc * const *mem_write;
-    void *opaque;
-    int in;
-};
-
-static uint32_t io_readb(void *opaque, target_phys_addr_t addr)
-{
-    struct io_fn *s = opaque;
-    uint32_t ret;
-
-    s->in ++;
-    ret = s->mem_read[0](s->opaque, addr);
-    s->in --;
-    if (!s->in)
-        fprintf(stderr, "%08x ---> %02x\n", (uint32_t) addr, ret);
-    return ret;
-}
-static uint32_t io_readh(void *opaque, target_phys_addr_t addr)
-{
-    struct io_fn *s = opaque;
-    uint32_t ret;
-
-    s->in ++;
-    ret = s->mem_read[1](s->opaque, addr);
-    s->in --;
-    if (!s->in)
-        fprintf(stderr, "%08x ---> %04x\n", (uint32_t) addr, ret);
-    return ret;
-}
-static uint32_t io_readw(void *opaque, target_phys_addr_t addr)
-{
-    struct io_fn *s = opaque;
-    uint32_t ret;
-
-    s->in ++;
-    ret = s->mem_read[2](s->opaque, addr);
-    s->in --;
-    if (!s->in)
-        fprintf(stderr, "%08x ---> %08x\n", (uint32_t) addr, ret);
-    return ret;
-}
-static void io_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-    struct io_fn *s = opaque;
-
-    if (!s->in)
-        fprintf(stderr, "%08x <--- %02x\n", (uint32_t) addr, value);
-    s->in ++;
-    s->mem_write[0](s->opaque, addr, value);
-    s->in --;
-}
-static void io_writeh(void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-    struct io_fn *s = opaque;
-
-    if (!s->in)
-        fprintf(stderr, "%08x <--- %04x\n", (uint32_t) addr, value);
-    s->in ++;
-    s->mem_write[1](s->opaque, addr, value);
-    s->in --;
-}
-static void io_writew(void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-    struct io_fn *s = opaque;
-
-    if (!s->in)
-        fprintf(stderr, "%08x <--- %08x\n", (uint32_t) addr, value);
-    s->in ++;
-    s->mem_write[2](s->opaque, addr, value);
-    s->in --;
-}
-
-static CPUReadMemoryFunc * const io_readfn[] = { io_readb, io_readh, io_readw, };
-static CPUWriteMemoryFunc * const io_writefn[] = { io_writeb, io_writeh, io_writew, };
-
-inline static int debug_register_io_memory(CPUReadMemoryFunc * const *mem_read,
-                                           CPUWriteMemoryFunc * const *mem_write,
-                                           void *opaque)
-{
-    struct io_fn *s = g_malloc(sizeof(struct io_fn));
-
-    s->mem_read = mem_read;
-    s->mem_write = mem_write;
-    s->opaque = opaque;
-    s->in = 0;
-    return cpu_register_io_memory(io_readfn, io_writefn, s,
-                                  DEVICE_NATIVE_ENDIAN);
-}
-#  define cpu_register_io_memory	debug_register_io_memory
-# endif
-
 #endif /* hw_omap_h */
diff --git a/hw/pc.c b/hw/pc.c
index 8368701efb..c7e9ab3ee1 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -970,7 +970,7 @@ void pc_cpus_init(const char *cpu_model)
     }
 }
 
-void pc_memory_init(MemoryRegion *system_memory,
+void *pc_memory_init(MemoryRegion *system_memory,
                     const char *kernel_filename,
                     const char *kernel_cmdline,
                     const char *initrd_filename,
@@ -1029,6 +1029,7 @@ void pc_memory_init(MemoryRegion *system_memory,
     for (i = 0; i < nb_option_roms; i++) {
         rom_add_option(option_rom[i].name, option_rom[i].bootindex);
     }
+    return fw_cfg;
 }
 
 qemu_irq *pc_allocate_cpu_irq(void)
diff --git a/hw/pc.h b/hw/pc.h
index 74d3369a12..31ccb6f495 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -106,7 +106,7 @@ void pc_register_ferr_irq(qemu_irq irq);
 void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
 
 void pc_cpus_init(const char *cpu_model);
-void pc_memory_init(MemoryRegion *system_memory,
+void *pc_memory_init(MemoryRegion *system_memory,
                     const char *kernel_filename,
                     const char *kernel_cmdline,
                     const char *initrd_filename,
@@ -142,7 +142,7 @@ int acpi_table_add(const char *table_desc);
 
 i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
                        qemu_irq sci_irq, qemu_irq smi_irq,
-                       int kvm_enabled);
+                       int kvm_enabled, void *fw_cfg);
 void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 
 /* hpet.c */
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index f49b0aaf89..eae258cefd 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -29,6 +29,7 @@
 #include "apic.h"
 #include "pci.h"
 #include "pci_ids.h"
+#include "usb.h"
 #include "net.h"
 #include "boards.h"
 #include "ide.h"
@@ -146,6 +147,7 @@ static void pc_init1(MemoryRegion *system_memory,
     MemoryRegion *ram_memory;
     MemoryRegion *pci_memory;
     MemoryRegion *rom_memory;
+    void *fw_cfg = NULL;
 
     pc_cpus_init(cpu_model);
 
@@ -172,7 +174,7 @@ static void pc_init1(MemoryRegion *system_memory,
 
     /* allocate ram and load rom/bios */
     if (!xen_enabled()) {
-        pc_memory_init(system_memory,
+        fw_cfg = pc_memory_init(system_memory,
                        kernel_filename, kernel_cmdline, initrd_filename,
                        below_4g_mem_size, above_4g_mem_size,
                        pci_enabled ? rom_memory : system_memory, &ram_memory);
@@ -276,7 +278,7 @@ static void pc_init1(MemoryRegion *system_memory,
         /* TODO: Populate SPD eeprom data.  */
         smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
                               gsi[9], *smi_irq,
-                              kvm_enabled());
+                              kvm_enabled(), fw_cfg);
         smbus_eeprom_init(smbus, 8, NULL, 0);
     }
 
@@ -374,7 +376,7 @@ static QEMUMachine pc_machine_v1_1 = {
             .property = "vapic",\
             .value    = "off",\
         },{\
-            .driver   = "USB",\
+            .driver   = TYPE_USB_DEVICE,\
             .property = "full-path",\
             .value    = "no",\
         }
@@ -388,6 +390,7 @@ static QEMUMachine pc_machine_v1_0 = {
         PC_COMPAT_1_0,
         { /* end of list */ }
     },
+    .hw_version = "1.0",
 };
 
 #define PC_COMPAT_0_15 \
@@ -402,6 +405,7 @@ static QEMUMachine pc_machine_v0_15 = {
         PC_COMPAT_0_15,
         { /* end of list */ }
     },
+    .hw_version = "0.15",
 };
 
 #define PC_COMPAT_0_14 \
@@ -442,12 +446,13 @@ static QEMUMachine pc_machine_v0_14 = {
         },
         { /* end of list */ }
     },
+    .hw_version = "0.14",
 };
 
 #define PC_COMPAT_0_13 \
         PC_COMPAT_0_14,\
         {\
-            .driver   = "PCI",\
+            .driver   = TYPE_PCI_DEVICE,\
             .property = "command_serr_enable",\
             .value    = "off",\
         },{\
@@ -478,6 +483,7 @@ static QEMUMachine pc_machine_v0_13 = {
         },
         { /* end of list */ }
     },
+    .hw_version = "0.13",
 };
 
 #define PC_COMPAT_0_12 \
@@ -509,7 +515,8 @@ static QEMUMachine pc_machine_v0_12 = {
             .value    = stringify(0),
         },
         { /* end of list */ }
-    }
+    },
+    .hw_version = "0.12",
 };
 
 #define PC_COMPAT_0_11 \
@@ -519,7 +526,7 @@ static QEMUMachine pc_machine_v0_12 = {
             .property = "vectors",\
             .value    = stringify(0),\
         },{\
-            .driver   = "PCI",\
+            .driver   = TYPE_PCI_DEVICE,\
             .property = "rombar",\
             .value    = stringify(0),\
         }
@@ -541,7 +548,8 @@ static QEMUMachine pc_machine_v0_11 = {
             .value    = "0.11",
         },
         { /* end of list */ }
-    }
+    },
+    .hw_version = "0.11",
 };
 
 static QEMUMachine pc_machine_v0_10 = {
@@ -574,6 +582,7 @@ static QEMUMachine pc_machine_v0_10 = {
         },
         { /* end of list */ }
     },
+    .hw_version = "0.10",
 };
 
 static QEMUMachine isapc_machine = {
diff --git a/hw/pc_sysfw.c b/hw/pc_sysfw.c
index f0d7c21b5c..b45f0acc7d 100644
--- a/hw/pc_sysfw.c
+++ b/hw/pc_sysfw.c
@@ -23,6 +23,7 @@
  * THE SOFTWARE.
  */
 
+#include "blockdev.h"
 #include "sysbus.h"
 #include "hw.h"
 #include "pc.h"
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 61257f457b..e7fb780a08 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -80,11 +80,7 @@ static int scsi_hot_add(Monitor *mon, DeviceState *adapter,
     SCSIBus *scsibus;
     SCSIDevice *scsidev;
 
-    scsibus = DO_UPCAST(SCSIBus, qbus, QLIST_FIRST(&adapter->child_bus));
-    if (!scsibus || strcmp(scsibus->qbus.info->name, "SCSI") != 0) {
-        error_report("Device is not a SCSI adapter");
-        return -1;
-    }
+    scsibus = SCSI_BUS(QLIST_FIRST(&adapter->child_bus));
 
     /*
      * drive_init() tries to find a default for dinfo->unit.  Doesn't
diff --git a/hw/pci.c b/hw/pci.c
index 127b7aca73..bdfb3d6540 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -31,6 +31,8 @@
 #include "loader.h"
 #include "range.h"
 #include "qmp-commands.h"
+#include "msi.h"
+#include "msix.h"
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
@@ -44,23 +46,32 @@ static char *pcibus_get_dev_path(DeviceState *dev);
 static char *pcibus_get_fw_dev_path(DeviceState *dev);
 static int pcibus_reset(BusState *qbus);
 
-struct BusInfo pci_bus_info = {
-    .name       = "PCI",
-    .size       = sizeof(PCIBus),
-    .print_dev  = pcibus_dev_print,
-    .get_dev_path = pcibus_get_dev_path,
-    .get_fw_dev_path = pcibus_get_fw_dev_path,
-    .reset      = pcibus_reset,
-    .props      = (Property[]) {
-        DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
-        DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
-        DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
-        DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
-                        QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
-        DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
-                        QEMU_PCI_CAP_SERR_BITNR, true),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property pci_props[] = {
+    DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
+    DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
+    DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
+    DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
+                    QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
+    DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
+                    QEMU_PCI_CAP_SERR_BITNR, true),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static void pci_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->print_dev = pcibus_dev_print;
+    k->get_dev_path = pcibus_get_dev_path;
+    k->get_fw_dev_path = pcibus_get_fw_dev_path;
+    k->reset = pcibus_reset;
+}
+
+static const TypeInfo pci_bus_info = {
+    .name = TYPE_PCI_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(PCIBus),
+    .class_init = pci_bus_class_init,
 };
 
 static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
@@ -188,6 +199,9 @@ void pci_device_reset(PCIDevice *dev)
         }
     }
     pci_update_mappings(dev);
+
+    msi_reset(dev);
+    msix_reset(dev);
 }
 
 /*
@@ -265,7 +279,7 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
                          MemoryRegion *address_space_io,
                          uint8_t devfn_min)
 {
-    qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);
+    qbus_create_inplace(&bus->qbus, TYPE_PCI_BUS, parent, name);
     assert(PCI_FUNC(devfn_min) == 0);
     bus->devfn_min = devfn_min;
     bus->address_space_mem = address_space_mem;
@@ -286,7 +300,7 @@ PCIBus *pci_bus_new(DeviceState *parent, const char *name,
     PCIBus *bus;
 
     bus = g_malloc0(sizeof(*bus));
-    bus->qbus.qdev_allocated = 1;
+    bus->qbus.glib_allocated = true;
     pci_bus_new_inplace(bus, parent, name, address_space_mem,
                         address_space_io, devfn_min);
     return bus;
@@ -1037,6 +1051,9 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 
     if (range_covers_byte(addr, l, PCI_COMMAND))
         pci_update_irq_disabled(d, was_irq_disabled);
+
+    msi_write_config(d, addr, val, l);
+    msix_write_config(d, addr, val, l);
 }
 
 /***********************************************************/
@@ -2000,7 +2017,8 @@ static void pci_device_class_init(ObjectClass *klass, void *data)
     k->init = pci_qdev_init;
     k->unplug = pci_unplug_device;
     k->exit = pci_unregister_device;
-    k->bus_info = &pci_bus_info;
+    k->bus_type = TYPE_PCI_BUS;
+    k->props = pci_props;
 }
 
 static TypeInfo pci_device_type_info = {
@@ -2014,6 +2032,7 @@ static TypeInfo pci_device_type_info = {
 
 static void pci_register_types(void)
 {
+    type_register_static(&pci_bus_info);
     type_register_static(&pci_device_type_info);
 }
 
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 866f0b6c52..0916276c4d 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -254,8 +254,9 @@ void pci_bridge_disable_base_limit(PCIDevice *dev)
 }
 
 /* reset bridge specific configuration registers */
-void pci_bridge_reset_reg(PCIDevice *dev)
+void pci_bridge_reset(DeviceState *qdev)
 {
+    PCIDevice *dev = PCI_DEVICE(qdev);
     uint8_t *conf = dev->config;
 
     conf[PCI_PRIMARY_BUS] = 0;
@@ -291,13 +292,6 @@ void pci_bridge_reset_reg(PCIDevice *dev)
     pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
 }
 
-/* default reset function for PCI-to-PCI bridge */
-void pci_bridge_reset(DeviceState *qdev)
-{
-    PCIDevice *dev = PCI_DEVICE(qdev);
-    pci_bridge_reset_reg(dev);
-}
-
 /* default qdev initialization function for PCI-to-PCI bridge */
 int pci_bridge_initfn(PCIDevice *dev)
 {
@@ -324,7 +318,7 @@ int pci_bridge_initfn(PCIDevice *dev)
 	    br->bus_name = dev->qdev.id;
     }
 
-    qbus_create_inplace(&sec_bus->qbus, &pci_bus_info, &dev->qdev,
+    qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev,
                         br->bus_name);
     sec_bus->parent_dev = dev;
     sec_bus->map_irq = br->map_irq;
diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c
index eccaa5831e..1cc1d2049c 100644
--- a/hw/pci_bridge_dev.c
+++ b/hw/pci_bridge_dev.c
@@ -52,7 +52,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
 {
     PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
     PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
-    int err;
+    int err, ret;
     pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn);
     err = pci_bridge_initfn(dev);
     if (err) {
@@ -86,6 +86,8 @@ slotid_error:
     shpc_cleanup(dev, &bridge_dev->bar);
 shpc_error:
     memory_region_destroy(&bridge_dev->bar);
+    ret = pci_bridge_exitfn(dev);
+    assert(!ret);
 bridge_error:
     return err;
 }
@@ -119,10 +121,8 @@ static void pci_bridge_dev_write_config(PCIDevice *d,
 static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
 {
     PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+
     pci_bridge_reset(qdev);
-    if (msi_present(dev)) {
-        msi_reset(dev);
-    }
     shpc_reset(dev);
 }
 
diff --git a/hw/pci_internals.h b/hw/pci_internals.h
index 96690b72d3..399c6d475c 100644
--- a/hw/pci_internals.h
+++ b/hw/pci_internals.h
@@ -12,7 +12,8 @@
  * Use accessor function in pci.h, pci_bridge.h
  */
 
-extern struct BusInfo pci_bus_info;
+#define TYPE_PCI_BUS "PCI"
+#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
 
 struct PCIBus {
     BusState qbus;
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index f83b3ad2a0..7915b4500d 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -83,8 +83,8 @@ static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
     }
 
     error_printf("name \"%s\"", object_class_get_name(klass));
-    if (dc->bus_info) {
-        error_printf(", bus %s", dc->bus_info->name);
+    if (dc->bus_type) {
+        error_printf(", bus %s", dc->bus_type);
     }
     if (qdev_class_has_alias(dc)) {
         error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
@@ -136,7 +136,6 @@ int qdev_device_help(QemuOpts *opts)
     const char *driver;
     Property *prop;
     ObjectClass *klass;
-    DeviceClass *info;
 
     driver = qemu_opt_get(opts, "driver");
     if (driver && !strcmp(driver, "?")) {
@@ -162,30 +161,22 @@ int qdev_device_help(QemuOpts *opts)
     if (!klass) {
         return 0;
     }
-    info = DEVICE_CLASS(klass);
-
-    for (prop = info->props; prop && prop->name; prop++) {
-        /*
-         * TODO Properties without a parser are just for dirty hacks.
-         * qdev_prop_ptr is the only such PropertyInfo.  It's marked
-         * for removal.  This conditional should be removed along with
-         * it.
-         */
-        if (!prop->info->set) {
-            continue;           /* no way to set it, don't show */
-        }
-        error_printf("%s.%s=%s\n", driver, prop->name,
-                     prop->info->legacy_name ?: prop->info->name);
-    }
-    if (info->bus_info) {
-        for (prop = info->bus_info->props; prop && prop->name; prop++) {
+    do {
+        for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
+            /*
+             * TODO Properties without a parser are just for dirty hacks.
+             * qdev_prop_ptr is the only such PropertyInfo.  It's marked
+             * for removal.  This conditional should be removed along with
+             * it.
+             */
             if (!prop->info->set) {
                 continue;           /* no way to set it, don't show */
             }
             error_printf("%s.%s=%s\n", driver, prop->name,
                          prop->info->legacy_name ?: prop->info->name);
         }
-    }
+        klass = object_class_get_parent(klass);
+    } while (klass != object_class_by_name(TYPE_DEVICE));
     return 1;
 }
 
@@ -227,11 +218,12 @@ static void qbus_list_bus(DeviceState *dev)
 
 static void qbus_list_dev(BusState *bus)
 {
-    DeviceState *dev;
+    BusChild *kid;
     const char *sep = " ";
 
     error_printf("devices at \"%s\":", bus->name);
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
         error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
         if (dev->id)
             error_printf("/\"%s\"", dev->id);
@@ -254,7 +246,7 @@ static BusState *qbus_find_bus(DeviceState *dev, char *elem)
 
 static DeviceState *qbus_find_dev(BusState *bus, char *elem)
 {
-    DeviceState *dev;
+    BusChild *kid;
 
     /*
      * try to match in order:
@@ -262,17 +254,20 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
      *   (2) driver name
      *   (3) driver alias, if present
      */
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
         if (dev->id  &&  strcmp(dev->id, elem) == 0) {
             return dev;
         }
     }
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
         if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
             return dev;
         }
     }
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
         DeviceClass *dc = DEVICE_GET_CLASS(dev);
 
         if (qdev_class_has_alias(dc) &&
@@ -284,25 +279,27 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
 }
 
 static BusState *qbus_find_recursive(BusState *bus, const char *name,
-                                     const BusInfo *info)
+                                     const char *bus_typename)
 {
-    DeviceState *dev;
+    BusChild *kid;
     BusState *child, *ret;
     int match = 1;
 
     if (name && (strcmp(bus->name, name) != 0)) {
         match = 0;
     }
-    if (info && (bus->info != info)) {
+    if (bus_typename &&
+        (strcmp(object_get_typename(OBJECT(bus)), bus_typename) != 0)) {
         match = 0;
     }
     if (match) {
         return bus;
     }
 
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
         QLIST_FOREACH(child, &dev->child_bus, sibling) {
-            ret = qbus_find_recursive(child, name, info);
+            ret = qbus_find_recursive(child, name, bus_typename);
             if (ret) {
                 return ret;
             }
@@ -437,16 +434,16 @@ DeviceState *qdev_device_add(QemuOpts *opts)
         if (!bus) {
             return NULL;
         }
-        if (bus->info != k->bus_info) {
+        if (strcmp(object_get_typename(OBJECT(bus)), k->bus_type) != 0) {
             qerror_report(QERR_BAD_BUS_FOR_DEVICE,
-                           driver, bus->info->name);
+                          driver, object_get_typename(OBJECT(bus)));
             return NULL;
         }
     } else {
-        bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_info);
+        bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_type);
         if (!bus) {
             qerror_report(QERR_NO_BUS_FOR_DEVICE,
-                          driver, k->bus_info->name);
+                          driver, k->bus_type);
             return NULL;
         }
     }
@@ -462,7 +459,6 @@ DeviceState *qdev_device_add(QemuOpts *opts)
     /* create device, set properties */
     qdev = DEVICE(object_new(driver));
     qdev_set_parent_bus(qdev, bus);
-    qdev_prop_set_globals(qdev);
 
     id = qemu_opts_id(opts);
     if (id) {
@@ -495,7 +491,7 @@ DeviceState *qdev_device_add(QemuOpts *opts)
 static void qbus_print(Monitor *mon, BusState *bus, int indent);
 
 static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
-                             const char *prefix, int indent)
+                             int indent)
 {
     if (!props)
         return;
@@ -514,14 +510,24 @@ static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
             error_free(err);
             continue;
         }
-        qdev_printf("%s-prop: %s = %s\n", prefix, props->name,
+        qdev_printf("%s = %s\n", props->name,
                     value && *value ? value : "<null>");
         g_free(value);
     }
 }
 
+static void bus_print_dev(BusState *bus, Monitor *mon, DeviceState *dev, int indent)
+{
+    BusClass *bc = BUS_GET_CLASS(bus);
+
+    if (bc->print_dev) {
+        bc->print_dev(mon, dev, indent);
+    }
+}
+
 static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
 {
+    ObjectClass *class;
     BusState *child;
     qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
                 dev->id ? dev->id : "");
@@ -532,10 +538,12 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
     if (dev->num_gpio_out) {
         qdev_printf("gpio-out %d\n", dev->num_gpio_out);
     }
-    qdev_print_props(mon, dev, qdev_get_props(dev), "dev", indent);
-    qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
-    if (dev->parent_bus->info->print_dev)
-        dev->parent_bus->info->print_dev(mon, dev, indent);
+    class = object_get_class(OBJECT(dev));
+    do {
+        qdev_print_props(mon, dev, DEVICE_CLASS(class)->props, indent);
+        class = object_class_get_parent(class);
+    } while (class != object_class_by_name(TYPE_DEVICE));
+    bus_print_dev(dev->parent_bus, mon, dev, indent + 2);
     QLIST_FOREACH(child, &dev->child_bus, sibling) {
         qbus_print(mon, child, indent);
     }
@@ -543,12 +551,13 @@ static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
 
 static void qbus_print(Monitor *mon, BusState *bus, int indent)
 {
-    struct DeviceState *dev;
+    BusChild *kid;
 
     qdev_printf("bus: %s\n", bus->name);
     indent += 2;
-    qdev_printf("type %s\n", bus->info->name);
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+    qdev_printf("type %s\n", object_get_typename(OBJECT(bus)));
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
         qdev_print(mon, dev, indent);
     }
 }
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 9ae318717e..099a7aa96f 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -915,26 +915,22 @@ static Property *qdev_prop_walk(Property *props, const char *name)
 
 static Property *qdev_prop_find(DeviceState *dev, const char *name)
 {
+    ObjectClass *class;
     Property *prop;
 
     /* device properties */
-    prop = qdev_prop_walk(qdev_get_props(dev), name);
-    if (prop)
-        return prop;
-
-    /* bus properties */
-    prop = qdev_prop_walk(dev->parent_bus->info->props, name);
-    if (prop)
-        return prop;
+    class = object_get_class(OBJECT(dev));
+    do {
+        prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name);
+        if (prop) {
+            return prop;
+        }
+        class = object_class_get_parent(class);
+    } while (class != object_class_by_name(TYPE_DEVICE));
 
     return NULL;
 }
 
-int qdev_prop_exists(DeviceState *dev, const char *name)
-{
-    return qdev_prop_find(dev, name) ? true : false;
-}
-
 void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
                                     Property *prop, const char *value)
 {
@@ -1105,28 +1101,6 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
     *ptr = value;
 }
 
-void qdev_prop_set_defaults(DeviceState *dev, Property *props)
-{
-    Object *obj = OBJECT(dev);
-    if (!props)
-        return;
-    for (; props->name; props++) {
-        Error *errp = NULL;
-        if (props->qtype == QTYPE_NONE) {
-            continue;
-        }
-        if (props->qtype == QTYPE_QBOOL) {
-            object_property_set_bool(obj, props->defval, props->name, &errp);
-        } else if (props->info->enum_table) {
-            object_property_set_str(obj, props->info->enum_table[props->defval],
-                                    props->name, &errp);
-        } else if (props->qtype == QTYPE_QINT) {
-            object_property_set_int(obj, props->defval, props->name, &errp);
-        }
-        assert_no_error(errp);
-    }
-}
-
 static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props);
 
 static void qdev_prop_register_global(GlobalProperty *prop)
@@ -1145,17 +1119,20 @@ void qdev_prop_register_global_list(GlobalProperty *props)
 
 void qdev_prop_set_globals(DeviceState *dev)
 {
-    GlobalProperty *prop;
-
-    QTAILQ_FOREACH(prop, &global_props, next) {
-        if (strcmp(object_get_typename(OBJECT(dev)), prop->driver) != 0 &&
-            strcmp(qdev_get_bus_info(dev)->name, prop->driver) != 0) {
-            continue;
+    ObjectClass *class = object_get_class(OBJECT(dev));
+
+    do {
+        GlobalProperty *prop;
+        QTAILQ_FOREACH(prop, &global_props, next) {
+            if (strcmp(object_class_get_name(class), prop->driver) != 0) {
+                continue;
+            }
+            if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
+                exit(1);
+            }
         }
-        if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
-            exit(1);
-        }
-    }
+        class = object_class_get_parent(class);
+    } while (class);
 }
 
 static int qdev_add_one_global(QemuOpts *opts, void *opaque)
diff --git a/hw/qdev.c b/hw/qdev.c
index 6a8f6bda2b..a6c4c02947 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -34,10 +34,6 @@ int qdev_hotplug = 0;
 static bool qdev_hot_added = false;
 static bool qdev_hot_removed = false;
 
-/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
-static BusState *main_system_bus;
-static void main_system_bus_create(void);
-
 /* Register a new device type.  */
 const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
 {
@@ -45,18 +41,6 @@ const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
     return dc->vmsd;
 }
 
-BusInfo *qdev_get_bus_info(DeviceState *dev)
-{
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-    return dc->bus_info;
-}
-
-Property *qdev_get_props(DeviceState *dev)
-{
-    DeviceClass *dc = DEVICE_GET_CLASS(dev);
-    return dc->props;
-}
-
 const char *qdev_fw_name(DeviceState *dev)
 {
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
@@ -76,22 +60,48 @@ bool qdev_exists(const char *name)
 static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
                                      Error **errp);
 
-void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
+static void bus_remove_child(BusState *bus, DeviceState *child)
 {
-    Property *prop;
+    BusChild *kid;
+
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        if (kid->child == child) {
+            char name[32];
+
+            snprintf(name, sizeof(name), "child[%d]", kid->index);
+            QTAILQ_REMOVE(&bus->children, kid, sibling);
+            object_property_del(OBJECT(bus), name, NULL);
+            g_free(kid);
+            return;
+        }
+    }
+}
+
+static void bus_add_child(BusState *bus, DeviceState *child)
+{
+    char name[32];
+    BusChild *kid = g_malloc0(sizeof(*kid));
 
     if (qdev_hotplug) {
         assert(bus->allow_hotplug);
     }
 
-    dev->parent_bus = bus;
-    QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
+    kid->index = bus->max_index++;
+    kid->child = child;
 
-    for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
-        qdev_property_add_legacy(dev, prop, NULL);
-        qdev_property_add_static(dev, prop, NULL);
-    }
-    qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
+    QTAILQ_INSERT_HEAD(&bus->children, kid, sibling);
+
+    snprintf(name, sizeof(name), "child[%d]", kid->index);
+    object_property_add_link(OBJECT(bus), name,
+                             object_get_typename(OBJECT(child)),
+                             (Object **)&kid->child,
+                             NULL);
+}
+
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
+{
+    dev->parent_bus = bus;
+    bus_add_child(bus, dev);
 }
 
 /* Create a new device.  This only initializes the device state structure
@@ -105,7 +115,7 @@ DeviceState *qdev_create(BusState *bus, const char *name)
     if (!dev) {
         if (bus) {
             hw_error("Unknown device '%s' for bus '%s'\n", name,
-                     bus->info->name);
+                     object_get_typename(OBJECT(bus)));
         } else {
             hw_error("Unknown device '%s' for default sysbus\n", name);
         }
@@ -131,7 +141,6 @@ DeviceState *qdev_try_create(BusState *bus, const char *type)
     }
 
     qdev_set_parent_bus(dev, bus);
-    qdev_prop_set_globals(dev);
 
     return dev;
 }
@@ -150,6 +159,7 @@ int qdev_init(DeviceState *dev)
 
     rc = dc->init(dev);
     if (rc < 0) {
+        object_unparent(OBJECT(dev));
         qdev_free(dev);
         return rc;
     }
@@ -209,18 +219,11 @@ static int qdev_reset_one(DeviceState *dev, void *opaque)
     return 0;
 }
 
-BusState *sysbus_get_default(void)
-{
-    if (!main_system_bus) {
-        main_system_bus_create();
-    }
-    return main_system_bus;
-}
-
 static int qbus_reset_one(BusState *bus, void *opaque)
 {
-    if (bus->info->reset) {
-        return bus->info->reset(bus);
+    BusClass *bc = BUS_GET_CLASS(bus);
+    if (bc->reset) {
+        return bc->reset(bus);
     }
     return 0;
 }
@@ -321,7 +324,7 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
     if (nd->netdev)
         qdev_prop_set_netdev(dev, "netdev", nd->netdev);
     if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
-        qdev_prop_exists(dev, "vectors")) {
+        object_property_find(OBJECT(dev), "vectors", NULL)) {
         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
     }
     nd->instantiated = 1;
@@ -342,7 +345,7 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
 int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
                        qbus_walkerfn *busfn, void *opaque)
 {
-    DeviceState *dev;
+    BusChild *kid;
     int err;
 
     if (busfn) {
@@ -352,8 +355,8 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
         }
     }
 
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        err = qdev_walk_children(dev, devfn, busfn, opaque);
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        err = qdev_walk_children(kid->child, devfn, busfn, opaque);
         if (err < 0) {
             return err;
         }
@@ -387,12 +390,17 @@ int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
 
 DeviceState *qdev_find_recursive(BusState *bus, const char *id)
 {
-    DeviceState *dev, *ret;
+    BusChild *kid;
+    DeviceState *ret;
     BusState *child;
 
-    QTAILQ_FOREACH(dev, &bus->children, sibling) {
-        if (dev->id && strcmp(dev->id, id) == 0)
+    QTAILQ_FOREACH(kid, &bus->children, sibling) {
+        DeviceState *dev = kid->child;
+
+        if (dev->id && strcmp(dev->id, id) == 0) {
             return dev;
+        }
+
         QLIST_FOREACH(child, &dev->child_bus, sibling) {
             ret = qdev_find_recursive(child, id);
             if (ret) {
@@ -403,84 +411,87 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
     return NULL;
 }
 
-void qbus_create_inplace(BusState *bus, BusInfo *info,
-                         DeviceState *parent, const char *name)
+static void qbus_realize(BusState *bus)
 {
+    const char *typename = object_get_typename(OBJECT(bus));
     char *buf;
     int i,len;
 
-    bus->info = info;
-    bus->parent = parent;
-
-    if (name) {
+    if (bus->name) {
         /* use supplied name */
-        bus->name = g_strdup(name);
-    } else if (parent && parent->id) {
+    } else if (bus->parent && bus->parent->id) {
         /* parent device has id -> use it for bus name */
-        len = strlen(parent->id) + 16;
+        len = strlen(bus->parent->id) + 16;
         buf = g_malloc(len);
-        snprintf(buf, len, "%s.%d", parent->id, parent->num_child_bus);
+        snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
         bus->name = buf;
     } else {
         /* no id -> use lowercase bus type for bus name */
-        len = strlen(info->name) + 16;
+        len = strlen(typename) + 16;
         buf = g_malloc(len);
-        len = snprintf(buf, len, "%s.%d", info->name,
-                       parent ? parent->num_child_bus : 0);
+        len = snprintf(buf, len, "%s.%d", typename,
+                       bus->parent ? bus->parent->num_child_bus : 0);
         for (i = 0; i < len; i++)
             buf[i] = qemu_tolower(buf[i]);
         bus->name = buf;
     }
 
-    QTAILQ_INIT(&bus->children);
-    if (parent) {
-        QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
-        parent->num_child_bus++;
-    } else if (bus != main_system_bus) {
+    if (bus->parent) {
+        QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
+        bus->parent->num_child_bus++;
+        object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL);
+    } else if (bus != sysbus_get_default()) {
         /* TODO: once all bus devices are qdevified,
            only reset handler for main_system_bus should be registered here. */
         qemu_register_reset(qbus_reset_all_fn, bus);
     }
 }
 
-BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
+void qbus_create_inplace(BusState *bus, const char *typename,
+                         DeviceState *parent, const char *name)
 {
-    BusState *bus;
+    object_initialize(bus, typename);
 
-    bus = g_malloc0(info->size);
-    bus->qdev_allocated = 1;
-    qbus_create_inplace(bus, info, parent, name);
-    return bus;
+    bus->parent = parent;
+    bus->name = name ? g_strdup(name) : NULL;
+    qbus_realize(bus);
 }
 
-static void main_system_bus_create(void)
+BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
 {
-    /* assign main_system_bus before qbus_create_inplace()
-     * in order to make "if (bus != main_system_bus)" work */
-    main_system_bus = g_malloc0(system_bus_info.size);
-    main_system_bus->qdev_allocated = 1;
-    qbus_create_inplace(main_system_bus, &system_bus_info, NULL,
-                        "main-system-bus");
+    BusState *bus;
+
+    bus = BUS(object_new(typename));
+    bus->qom_allocated = true;
+
+    bus->parent = parent;
+    bus->name = name ? g_strdup(name) : NULL;
+    qbus_realize(bus);
+
+    return bus;
 }
 
 void qbus_free(BusState *bus)
 {
-    DeviceState *dev;
-
-    while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
-        qdev_free(dev);
-    }
-    if (bus->parent) {
-        QLIST_REMOVE(bus, sibling);
-        bus->parent->num_child_bus--;
+    if (bus->qom_allocated) {
+        object_delete(OBJECT(bus));
     } else {
-        assert(bus != main_system_bus); /* main_system_bus is never freed */
-        qemu_unregister_reset(qbus_reset_all_fn, bus);
+        object_finalize(OBJECT(bus));
+        if (bus->glib_allocated) {
+            g_free(bus);
+        }
     }
-    g_free((void*)bus->name);
-    if (bus->qdev_allocated) {
-        g_free(bus);
+}
+
+static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
+{
+    BusClass *bc = BUS_GET_CLASS(bus);
+
+    if (bc->get_fw_dev_path) {
+        return bc->get_fw_dev_path(dev);
     }
+
+    return NULL;
 }
 
 static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
@@ -490,8 +501,8 @@ static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
     if (dev && dev->parent_bus) {
         char *d;
         l = qdev_get_fw_dev_path_helper(dev->parent_bus->parent, p, size);
-        if (dev->parent_bus->info->get_fw_dev_path) {
-            d = dev->parent_bus->info->get_fw_dev_path(dev);
+        d = bus_get_fw_dev_path(dev->parent_bus, dev);
+        if (d) {
             l += snprintf(p + l, size - l, "%s", d);
             g_free(d);
         } else {
@@ -515,9 +526,20 @@ char* qdev_get_fw_dev_path(DeviceState *dev)
     return strdup(path);
 }
 
-static char *qdev_get_type(Object *obj, Error **errp)
+char *qdev_get_dev_path(DeviceState *dev)
 {
-    return g_strdup(object_get_typename(obj));
+    BusClass *bc;
+
+    if (!dev || !dev->parent_bus) {
+        return NULL;
+    }
+
+    bc = BUS_GET_CLASS(dev->parent_bus);
+    if (bc->get_dev_path) {
+        return bc->get_dev_path(dev);
+    }
+
+    return NULL;
 }
 
 /**
@@ -605,6 +627,9 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
 void qdev_property_add_static(DeviceState *dev, Property *prop,
                               Error **errp)
 {
+    Error *local_err = NULL;
+    Object *obj = OBJECT(dev);
+
     /*
      * TODO qdev_prop_ptr does not have getters or setters.  It must
      * go now that it can be replaced with links.  The test should be
@@ -614,15 +639,34 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
         return;
     }
 
-    object_property_add(OBJECT(dev), prop->name, prop->info->name,
+    object_property_add(obj, prop->name, prop->info->name,
                         prop->info->get, prop->info->set,
                         prop->info->release,
-                        prop, errp);
+                        prop, &local_err);
+
+    if (local_err) {
+        error_propagate(errp, local_err);
+        return;
+    }
+    if (prop->qtype == QTYPE_NONE) {
+        return;
+    }
+
+    if (prop->qtype == QTYPE_QBOOL) {
+        object_property_set_bool(obj, prop->defval, prop->name, &local_err);
+    } else if (prop->info->enum_table) {
+        object_property_set_str(obj, prop->info->enum_table[prop->defval],
+                                prop->name, &local_err);
+    } else if (prop->qtype == QTYPE_QINT) {
+        object_property_set_int(obj, prop->defval, prop->name, &local_err);
+    }
+    assert_no_error(local_err);
 }
 
 static void device_initfn(Object *obj)
 {
     DeviceState *dev = DEVICE(obj);
+    ObjectClass *class;
     Property *prop;
 
     if (qdev_hotplug) {
@@ -633,13 +677,18 @@ static void device_initfn(Object *obj)
     dev->instance_id_alias = -1;
     dev->state = DEV_STATE_CREATED;
 
-    for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
-        qdev_property_add_legacy(dev, prop, NULL);
-        qdev_property_add_static(dev, prop, NULL);
-    }
+    class = object_get_class(OBJECT(dev));
+    do {
+        for (prop = DEVICE_CLASS(class)->props; prop && prop->name; prop++) {
+            qdev_property_add_legacy(dev, prop, NULL);
+            qdev_property_add_static(dev, prop, NULL);
+        }
+        class = object_class_get_parent(class);
+    } while (class != object_class_by_name(TYPE_DEVICE));
+    qdev_prop_set_globals(dev);
 
-    object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
-    qdev_prop_set_defaults(dev, qdev_get_props(dev));
+    object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS,
+                             (Object **)&dev->parent_bus, NULL);
 }
 
 /* Unlink device from bus and free the structure.  */
@@ -664,7 +713,19 @@ static void device_finalize(Object *obj)
             qemu_opts_del(dev->opts);
         }
     }
-    QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
+    if (dev->parent_bus) {
+        bus_remove_child(dev->parent_bus, dev);
+    }
+}
+
+static void device_class_base_init(ObjectClass *class, void *data)
+{
+    DeviceClass *klass = DEVICE_CLASS(class);
+
+    /* We explicitly look up properties in the superclasses,
+     * so do not propagate them to the subclasses.
+     */
+    klass->props = NULL;
 }
 
 void device_reset(DeviceState *dev)
@@ -693,12 +754,50 @@ static TypeInfo device_type_info = {
     .instance_size = sizeof(DeviceState),
     .instance_init = device_initfn,
     .instance_finalize = device_finalize,
+    .class_base_init = device_class_base_init,
     .abstract = true,
     .class_size = sizeof(DeviceClass),
 };
 
+static void qbus_initfn(Object *obj)
+{
+    BusState *bus = BUS(obj);
+
+    QTAILQ_INIT(&bus->children);
+}
+
+static void qbus_finalize(Object *obj)
+{
+    BusState *bus = BUS(obj);
+    BusChild *kid;
+
+    while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
+        DeviceState *dev = kid->child;
+        qdev_free(dev);
+    }
+    if (bus->parent) {
+        QLIST_REMOVE(bus, sibling);
+        bus->parent->num_child_bus--;
+    } else {
+        assert(bus != sysbus_get_default()); /* main_system_bus is never freed */
+        qemu_unregister_reset(qbus_reset_all_fn, bus);
+    }
+    g_free((char *)bus->name);
+}
+
+static const TypeInfo bus_info = {
+    .name = TYPE_BUS,
+    .parent = TYPE_OBJECT,
+    .instance_size = sizeof(BusState),
+    .abstract = true,
+    .class_size = sizeof(BusClass),
+    .instance_init = qbus_initfn,
+    .instance_finalize = qbus_finalize,
+};
+
 static void qdev_register_types(void)
 {
+    type_register_static(&bus_info);
     type_register_static(&device_type_info);
 }
 
diff --git a/hw/qdev.h b/hw/qdev.h
index 5386b165bc..ae1d2812bf 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -17,7 +17,7 @@ typedef struct CompatProperty CompatProperty;
 
 typedef struct BusState BusState;
 
-typedef struct BusInfo BusInfo;
+typedef struct BusClass BusClass;
 
 enum DevState {
     DEV_STATE_CREATED = 1,
@@ -55,7 +55,7 @@ typedef struct DeviceClass {
     qdev_initfn init;
     qdev_event unplug;
     qdev_event exit;
-    BusInfo *bus_info;
+    const char *bus_type;
 } DeviceClass;
 
 /* This structure should not be accessed directly.  We declare it here
@@ -74,38 +74,52 @@ struct DeviceState {
     qemu_irq *gpio_in;
     QLIST_HEAD(, BusState) child_bus;
     int num_child_bus;
-    QTAILQ_ENTRY(DeviceState) sibling;
     int instance_id_alias;
     int alias_required_for_version;
 };
 
-typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
-typedef char *(*bus_get_dev_path)(DeviceState *dev);
 /*
  * This callback is used to create Open Firmware device path in accordance with
  * OF spec http://forthworks.com/standards/of1275.pdf. Indicidual bus bindings
  * can be found here http://playground.sun.com/1275/bindings/.
  */
-typedef char *(*bus_get_fw_dev_path)(DeviceState *dev);
-typedef int (qbus_resetfn)(BusState *bus);
 
-struct BusInfo {
-    const char *name;
-    size_t size;
-    bus_dev_printfn print_dev;
-    bus_get_dev_path get_dev_path;
-    bus_get_fw_dev_path get_fw_dev_path;
-    qbus_resetfn *reset;
-    Property *props;
+#define TYPE_BUS "bus"
+#define BUS(obj) OBJECT_CHECK(BusState, (obj), TYPE_BUS)
+#define BUS_CLASS(klass) OBJECT_CLASS_CHECK(BusClass, (klass), TYPE_BUS)
+#define BUS_GET_CLASS(obj) OBJECT_GET_CLASS(BusClass, (obj), TYPE_BUS)
+
+struct BusClass {
+    ObjectClass parent_class;
+
+    /* FIXME first arg should be BusState */
+    void (*print_dev)(Monitor *mon, DeviceState *dev, int indent);
+    char *(*get_dev_path)(DeviceState *dev);
+    char *(*get_fw_dev_path)(DeviceState *dev);
+    int (*reset)(BusState *bus);
 };
 
+typedef struct BusChild {
+    DeviceState *child;
+    int index;
+    QTAILQ_ENTRY(BusChild) sibling;
+} BusChild;
+
+/**
+ * BusState:
+ * @qom_allocated: Indicates whether the object was allocated by QOM.
+ * @glib_allocated: Indicates whether the object was initialized in-place
+ * yet is expected to be freed with g_free().
+ */
 struct BusState {
+    Object obj;
     DeviceState *parent;
-    BusInfo *info;
     const char *name;
     int allow_hotplug;
-    int qdev_allocated;
-    QTAILQ_HEAD(ChildrenHead, DeviceState) children;
+    bool qom_allocated;
+    bool glib_allocated;
+    int max_index;
+    QTAILQ_HEAD(ChildrenHead, BusChild) children;
     QLIST_ENTRY(BusState) sibling;
 };
 
@@ -175,9 +189,9 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id);
 typedef int (qbus_walkerfn)(BusState *bus, void *opaque);
 typedef int (qdev_walkerfn)(DeviceState *dev, void *opaque);
 
-void qbus_create_inplace(BusState *bus, BusInfo *info,
+void qbus_create_inplace(BusState *bus, const char *typename,
                          DeviceState *parent, const char *name);
-BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name);
+BusState *qbus_create(const char *typename, DeviceState *parent, const char *name);
 /* Returns > 0 if either devfn or busfn skip walk somewhere in cursion,
  *         < 0 if either devfn or busfn terminate walk somewhere in cursion,
  *           0 otherwise. */
@@ -292,7 +306,6 @@ extern PropertyInfo qdev_prop_blocksize;
 
 /* Set properties between creation and init.  */
 void *qdev_get_prop_ptr(DeviceState *dev, Property *prop);
-int qdev_prop_exists(DeviceState *dev, const char *name);
 int qdev_prop_parse(DeviceState *dev, const char *name, const char *value);
 void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value);
 void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value);
@@ -310,7 +323,6 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
 void qdev_prop_set_enum(DeviceState *dev, const char *name, int value);
 /* FIXME: Remove opaque pointer properties.  */
 void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
-void qdev_prop_set_defaults(DeviceState *dev, Property *props);
 
 void qdev_prop_register_global_list(GlobalProperty *props);
 void qdev_prop_set_globals(DeviceState *dev);
@@ -319,9 +331,6 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
 
 char *qdev_get_fw_dev_path(DeviceState *dev);
 
-/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
-extern struct BusInfo system_bus_info;
-
 /**
  * @qdev_property_add_static - add a @Property to a device referencing a
  * field in a struct.
@@ -347,10 +356,6 @@ const VMStateDescription *qdev_get_vmsd(DeviceState *dev);
 
 const char *qdev_fw_name(DeviceState *dev);
 
-BusInfo *qdev_get_bus_info(DeviceState *dev);
-
-Property *qdev_get_props(DeviceState *dev);
-
 Object *qdev_get_machine(void);
 
 /* FIXME: make this a link<> */
@@ -358,4 +363,6 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
 
 extern int qdev_hotplug;
 
+char *qdev_get_dev_path(DeviceState *dev);
+
 #endif
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index eb22d04fad..f6f144b525 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -802,7 +802,7 @@ static int rtl8139_can_receive(VLANClientState *nc)
     } else {
         avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
                      s->RxBufferSize);
-        return (avail == 0 || avail >= 1514);
+        return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
     }
 }
 
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 23ef35b3bb..4d49b96f94 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -45,9 +45,10 @@
 
 #define VIRTIO_EXT_CODE   0x2603
 
-struct BusInfo s390_virtio_bus_info = {
-    .name       = "s390-virtio",
-    .size       = sizeof(VirtIOS390Bus),
+static const TypeInfo s390_virtio_bus_info = {
+    .name = TYPE_S390_VIRTIO_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(VirtIOS390Bus),
 };
 
 static const VirtIOBindings virtio_s390_bindings;
@@ -92,7 +93,7 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size)
 
     /* Create bus on bridge device */
 
-    _bus = qbus_create(&s390_virtio_bus_info, dev, "s390-virtio");
+    _bus = qbus_create(TYPE_S390_VIRTIO_BUS, dev, "s390-virtio");
     bus = DO_UPCAST(VirtIOS390Bus, bus, _bus);
 
     bus->dev_page = *ram_size;
@@ -314,20 +315,20 @@ VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
                                              ram_addr_t mem,
                                              int *vq_num)
 {
-    VirtIOS390Device *_dev;
-    DeviceState *dev;
+    BusChild *kid;
     int i;
 
-    QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
-        _dev = (VirtIOS390Device *)dev;
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        VirtIOS390Device *dev = (VirtIOS390Device *)kid->child;
+
         for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
-            if (!virtio_queue_get_addr(_dev->vdev, i))
+            if (!virtio_queue_get_addr(dev->vdev, i))
                 break;
-            if (virtio_queue_get_addr(_dev->vdev, i) == mem) {
+            if (virtio_queue_get_addr(dev->vdev, i) == mem) {
                 if (vq_num) {
                     *vq_num = i;
                 }
-                return _dev;
+                return dev;
             }
         }
     }
@@ -338,13 +339,12 @@ VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
 /* Find a device by device descriptor location */
 VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem)
 {
-    VirtIOS390Device *_dev;
-    DeviceState *dev;
+    BusChild *kid;
 
-    QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
-        _dev = (VirtIOS390Device *)dev;
-        if (_dev->dev_offs == mem) {
-            return _dev;
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        VirtIOS390Device *dev = (VirtIOS390Device *)kid->child;
+        if (dev->dev_offs == mem) {
+            return dev;
         }
     }
 
@@ -460,7 +460,7 @@ static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->init = s390_virtio_busdev_init;
-    dc->bus_info = &s390_virtio_bus_info;
+    dc->bus_type = TYPE_S390_VIRTIO_BUS;
     dc->unplug = qdev_simple_unplug_cb;
 }
 
@@ -521,6 +521,7 @@ static TypeInfo s390_virtio_bridge_info = {
 
 static void s390_virtio_register_types(void)
 {
+    type_register_static(&s390_virtio_bus_info);
     type_register_static(&virtio_s390_device_info);
     type_register_static(&s390_virtio_serial);
     type_register_static(&s390_virtio_blk);
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index 4b99d02298..4873134ae9 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -52,6 +52,10 @@
 #define VIRTIO_S390_DEVICE_GET_CLASS(obj) \
      OBJECT_GET_CLASS(VirtIOS390DeviceClass, (obj), TYPE_VIRTIO_S390_DEVICE)
 
+#define TYPE_S390_VIRTIO_BUS "s390-virtio-bus"
+#define S390_VIRTIO_BUS(obj) \
+     OBJECT_CHECK(VirtIOS390Bus, (obj), TYPE_S390_VIRTIO_BUS)
+
 typedef struct VirtIOS390Device VirtIOS390Device;
 
 typedef struct VirtIOS390DeviceClass {
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 4a798210ce..14e2f730b8 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -12,17 +12,26 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev);
 static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
 static void scsi_req_dequeue(SCSIRequest *req);
 
-static struct BusInfo scsi_bus_info = {
-    .name  = "SCSI",
-    .size  = sizeof(SCSIBus),
-    .get_dev_path = scsibus_get_dev_path,
-    .get_fw_dev_path = scsibus_get_fw_dev_path,
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
-        DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
-        DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property scsi_props[] = {
+    DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
+    DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
+    DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->get_dev_path = scsibus_get_dev_path;
+    k->get_fw_dev_path = scsibus_get_fw_dev_path;
+}
+
+static const TypeInfo scsi_bus_info = {
+    .name = TYPE_SCSI_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(SCSIBus),
+    .class_init = scsi_bus_class_init,
 };
 static int next_scsi_bus;
 
@@ -65,7 +74,7 @@ static void scsi_device_unit_attention_reported(SCSIDevice *s)
 /* Create a scsi bus, and attach devices to it.  */
 void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
 {
-    qbus_create_inplace(&bus->qbus, &scsi_bus_info, host, NULL);
+    qbus_create_inplace(&bus->qbus, TYPE_SCSI_BUS, host, NULL);
     bus->busnr = next_scsi_bus++;
     bus->info = info;
     bus->qbus.allow_hotplug = 1;
@@ -205,7 +214,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
     if (bootindex >= 0) {
         qdev_prop_set_int32(dev, "bootindex", bootindex);
     }
-    if (qdev_prop_exists(dev, "removable")) {
+    if (object_property_find(OBJECT(dev), "removable", NULL)) {
         qdev_prop_set_bit(dev, "removable", removable);
     }
     if (qdev_prop_set_drive(dev, "drive", bdrv) < 0) {
@@ -306,7 +315,7 @@ static void store_lun(uint8_t *outbuf, int lun)
 
 static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
 {
-    DeviceState *qdev;
+    BusChild *kid;
     int i, len, n;
     int channel, id;
     bool found_lun0;
@@ -321,7 +330,8 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
     id = r->req.dev->id;
     found_lun0 = false;
     n = 0;
-    QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
+    QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
         SCSIDevice *dev = SCSI_DEVICE(qdev);
 
         if (dev->channel == channel && dev->id == id) {
@@ -343,7 +353,8 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
     memset(r->buf, 0, len);
     stl_be_p(&r->buf, n);
     i = found_lun0 ? 8 : 16;
-    QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
+    QTAILQ_FOREACH(kid, &r->req.bus->qbus.children, sibling) {
+        DeviceState *qdev = kid->child;
         SCSIDevice *dev = SCSI_DEVICE(qdev);
 
         if (dev->channel == channel && dev->id == id) {
@@ -406,7 +417,7 @@ static bool scsi_target_emulate_inquiry(SCSITargetReq *r)
         r->buf[7] = 0x10 | (r->req.bus->info->tcq ? 0x02 : 0); /* Sync, TCQ.  */
         memcpy(&r->buf[8], "QEMU    ", 8);
         memcpy(&r->buf[16], "QEMU TARGET     ", 16);
-        strncpy((char *) &r->buf[32], QEMU_VERSION, 4);
+        pstrcpy((char *) &r->buf[32], 4, qemu_get_version());
     }
     return true;
 }
@@ -1452,12 +1463,10 @@ static char *scsibus_get_dev_path(DeviceState *dev)
 {
     SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
     DeviceState *hba = dev->parent_bus->parent;
-    char *id = NULL;
+    char *id;
     char *path;
 
-    if (hba && hba->parent_bus && hba->parent_bus->info->get_dev_path) {
-        id = hba->parent_bus->info->get_dev_path(hba);
-    }
+    id = qdev_get_dev_path(hba);
     if (id) {
         path = g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
     } else {
@@ -1480,10 +1489,11 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev)
 
 SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
 {
-    DeviceState *qdev;
+    BusChild *kid;
     SCSIDevice *target_dev = NULL;
 
-    QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
+    QTAILQ_FOREACH_REVERSE(kid, &bus->qbus.children, ChildrenHead, sibling) {
+        DeviceState *qdev = kid->child;
         SCSIDevice *dev = SCSI_DEVICE(qdev);
 
         if (dev->channel == channel && dev->id == id) {
@@ -1595,10 +1605,11 @@ const VMStateDescription vmstate_scsi_device = {
 static void scsi_device_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
-    k->bus_info = &scsi_bus_info;
+    k->bus_type = TYPE_SCSI_BUS;
     k->init     = scsi_qdev_init;
     k->unplug   = qdev_simple_unplug_cb;
     k->exit     = scsi_qdev_exit;
+    k->props    = scsi_props;
 }
 
 static TypeInfo scsi_device_type_info = {
@@ -1612,6 +1623,7 @@ static TypeInfo scsi_device_type_info = {
 
 static void scsi_register_types(void)
 {
+    type_register_static(&scsi_bus_info);
     type_register_static(&scsi_device_type_info);
 }
 
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 1691491c03..ae2519458c 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -34,7 +34,6 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 #include "scsi-defs.h"
 #include "sysemu.h"
 #include "blockdev.h"
-#include "block_int.h"
 #include "dma.h"
 
 #ifdef __linux
@@ -1716,7 +1715,7 @@ static int scsi_initfn(SCSIDevice *dev)
     }
 
     if (!s->version) {
-        s->version = g_strdup(QEMU_VERSION);
+        s->version = g_strdup(qemu_get_version());
     }
 
     if (bdrv_is_sg(s->qdev.conf.bs)) {
@@ -1889,7 +1888,7 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
 	 * ones (such as WRITE SAME or EXTENDED COPY, etc.).  So, without
 	 * O_DIRECT everything must go through SG_IO.
          */
-        if (!(s->qdev.conf.bs->open_flags & BDRV_O_NOCACHE)) {
+        if (bdrv_get_flags(s->qdev.conf.bs) & BDRV_O_NOCACHE) {
             break;
         }
 
diff --git a/hw/scsi.h b/hw/scsi.h
index 2eb66f7393..76f06d41de 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -136,6 +136,9 @@ struct SCSIBusInfo {
     void *(*load_request)(QEMUFile *f, SCSIRequest *req);
 };
 
+#define TYPE_SCSI_BUS "SCSI"
+#define SCSI_BUS(obj) OBJECT_CHECK(SCSIBus, (obj), TYPE_SCSI_BUS)
+
 struct SCSIBus {
     BusState qbus;
     int busnr;
diff --git a/hw/shpc.c b/hw/shpc.c
index a5baf246f1..6b9884d544 100644
--- a/hw/shpc.c
+++ b/hw/shpc.c
@@ -253,6 +253,7 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
          ++devfn) {
         PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
         if (affected_dev) {
+            object_unparent(OBJECT(affected_dev));
             qdev_free(&affected_dev->qdev);
         }
     }
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 25b400aa47..97d417a997 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -35,17 +35,18 @@
 static PCIDevice *find_dev(sPAPREnvironment *spapr,
                            uint64_t buid, uint32_t config_addr)
 {
-    DeviceState *qdev;
     int devfn = (config_addr >> 8) & 0xFF;
     sPAPRPHBState *phb;
 
     QLIST_FOREACH(phb, &spapr->phbs, list) {
+        BusChild *kid;
+
         if (phb->buid != buid) {
             continue;
         }
 
-        QTAILQ_FOREACH(qdev, &phb->host_state.bus->qbus.children, sibling) {
-            PCIDevice *dev = (PCIDevice *)qdev;
+        QTAILQ_FOREACH(kid, &phb->host_state.bus->qbus.children, sibling) {
+            PCIDevice *dev = (PCIDevice *)kid->child;
             if (dev->devfn == devfn) {
                 return dev;
             }
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 315ab8091c..c8271c626c 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -49,22 +49,24 @@
     do { } while (0)
 #endif
 
-static struct BusInfo spapr_vio_bus_info = {
-    .name       = "spapr-vio",
-    .size       = sizeof(VIOsPAPRBus),
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \
-        DEFINE_PROP_END_OF_LIST(),
-    },
+static Property spapr_vio_props[] = {
+    DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, vio_irq_num, 0), \
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const TypeInfo spapr_vio_bus_info = {
+    .name = TYPE_SPAPR_VIO_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(VIOsPAPRBus),
 };
 
 VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
 {
-    DeviceState *qdev;
+    BusChild *kid;
     VIOsPAPRDevice *dev = NULL;
 
-    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
-        dev = (VIOsPAPRDevice *)qdev;
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)kid->child;
         if (dev->reg == reg) {
             return dev;
         }
@@ -604,7 +606,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
                          uint32_t nret, target_ulong rets)
 {
     VIOsPAPRBus *bus = spapr->vio_bus;
-    DeviceState *qdev;
+    BusChild *kid;
     VIOsPAPRDevice *dev = NULL;
 
     if (nargs != 0) {
@@ -612,8 +614,8 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
         return;
     }
 
-    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
-        dev = (VIOsPAPRDevice *)qdev;
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)kid->child;
         spapr_vio_quiesce_one(dev);
     }
 
@@ -623,7 +625,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
 static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
 {
     VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus);
-    DeviceState *qdev;
+    BusChild *kid;
     VIOsPAPRDevice *other;
 
     /*
@@ -631,8 +633,8 @@ static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
      * using the requested address. We have to open code this because
      * the given dev might already be in the list.
      */
-    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
-        other = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        other = DO_UPCAST(VIOsPAPRDevice, qdev, kid->child);
 
         if (other != dev && other->reg == dev->reg) {
             return other;
@@ -742,7 +744,7 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
 
     /* Create bus on bridge device */
 
-    qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
+    qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
     bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
     bus->next_reg = 0x1000;
 
@@ -794,7 +796,8 @@ static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
     DeviceClass *k = DEVICE_CLASS(klass);
     k->init = spapr_vio_busdev_init;
     k->reset = spapr_vio_busdev_reset;
-    k->bus_info = &spapr_vio_bus_info;
+    k->bus_type = TYPE_SPAPR_VIO_BUS;
+    k->props = spapr_vio_props;
 }
 
 static TypeInfo spapr_vio_type_info = {
@@ -808,6 +811,7 @@ static TypeInfo spapr_vio_type_info = {
 
 static void spapr_vio_register_types(void)
 {
+    type_register_static(&spapr_vio_bus_info);
     type_register_static(&spapr_vio_bridge_info);
     type_register_static(&spapr_vio_type_info);
 }
@@ -836,19 +840,20 @@ static int compare_reg(const void *p1, const void *p2)
 int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
 {
     DeviceState *qdev, **qdevs;
+    BusChild *kid;
     int i, num, ret = 0;
 
     /* Count qdevs on the bus list */
     num = 0;
-    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
         num++;
     }
 
     /* Copy out into an array of pointers */
     qdevs = g_malloc(sizeof(qdev) * num);
     num = 0;
-    QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
-        qdevs[num++] = qdev;
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        qdevs[num++] = kid->child;
     }
 
     /* Sort the array */
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 87816e456d..2adad77d02 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -40,6 +40,9 @@ enum VIOsPAPR_TCEAccess {
 #define VIO_SPAPR_DEVICE_GET_CLASS(obj) \
      OBJECT_GET_CLASS(VIOsPAPRDeviceClass, (obj), TYPE_VIO_SPAPR_DEVICE)
 
+#define TYPE_SPAPR_VIO_BUS "spapr-vio-bus"
+#define SPAPR_VIO_BUS(obj) OBJECT_CHECK(VIOsPAPRBus, (obj), TYPE_SPAPR_VIO_BUS)
+
 struct VIOsPAPRDevice;
 
 typedef struct VIOsPAPR_RTCE {
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index c9674f36a6..f340b83237 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -160,7 +160,7 @@ static TypeInfo spapr_vty_info = {
 VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
 {
     VIOsPAPRDevice *sdev, *selected;
-    DeviceState *iter;
+    BusChild *kid;
 
     /*
      * To avoid the console bouncing around we want one VTY to be
@@ -169,7 +169,9 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
      */
 
     selected = NULL;
-    QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
+    QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
+        DeviceState *iter = kid->child;
+
         /* Only look at VTY devices */
         if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
             continue;
diff --git a/hw/ssi.c b/hw/ssi.c
index 8f2d9bc034..e5f14a0cef 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -16,9 +16,13 @@ struct SSIBus {
     BusState qbus;
 };
 
-static struct BusInfo ssi_bus_info = {
-    .name = "SSI",
-    .size = sizeof(SSIBus),
+#define TYPE_SSI_BUS "SSI"
+#define SSI_BUS(obj) OBJECT_CHECK(SSIBus, (obj), TYPE_SSI_BUS)
+
+static const TypeInfo ssi_bus_info = {
+    .name = TYPE_SSI_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(SSIBus),
 };
 
 static int ssi_slave_init(DeviceState *dev)
@@ -26,10 +30,11 @@ static int ssi_slave_init(DeviceState *dev)
     SSISlave *s = SSI_SLAVE(dev);
     SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
     SSIBus *bus;
+    BusChild *kid;
 
     bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
-    if (QTAILQ_FIRST(&bus->qbus.children) != dev
-        || QTAILQ_NEXT(dev, sibling) != NULL) {
+    kid = QTAILQ_FIRST(&bus->qbus.children);
+    if (kid->child != dev || QTAILQ_NEXT(kid, sibling) != NULL) {
         hw_error("Too many devices on SSI bus");
     }
 
@@ -40,7 +45,7 @@ static void ssi_slave_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     dc->init = ssi_slave_init;
-    dc->bus_info = &ssi_bus_info;
+    dc->bus_type = TYPE_SSI_BUS;
 }
 
 static TypeInfo ssi_slave_info = {
@@ -62,26 +67,28 @@ DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
 SSIBus *ssi_create_bus(DeviceState *parent, const char *name)
 {
     BusState *bus;
-    bus = qbus_create(&ssi_bus_info, parent, name);
+    bus = qbus_create(TYPE_SSI_BUS, parent, name);
     return FROM_QBUS(SSIBus, bus);
 }
 
 uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
 {
-    DeviceState *dev;
+    BusChild *kid;
     SSISlave *slave;
     SSISlaveClass *ssc;
-    dev = QTAILQ_FIRST(&bus->qbus.children);
-    if (!dev) {
+
+    kid = QTAILQ_FIRST(&bus->qbus.children);
+    if (!kid) {
         return 0;
     }
-    slave = SSI_SLAVE(dev);
+    slave = SSI_SLAVE(kid->child);
     ssc = SSI_SLAVE_GET_CLASS(slave);
     return ssc->transfer(slave, val);
 }
 
 static void ssi_slave_register_types(void)
 {
+    type_register_static(&ssi_bus_info);
     type_register_static(&ssi_slave_info);
 }
 
diff --git a/hw/sysbus.c b/hw/sysbus.c
index db4efccef4..9d8b1eaf7d 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -24,11 +24,19 @@
 static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);
 static char *sysbus_get_fw_dev_path(DeviceState *dev);
 
-struct BusInfo system_bus_info = {
-    .name       = "System",
-    .size       = sizeof(BusState),
-    .print_dev  = sysbus_dev_print,
-    .get_fw_dev_path = sysbus_get_fw_dev_path,
+static void system_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->print_dev = sysbus_dev_print;
+    k->get_fw_dev_path = sysbus_get_fw_dev_path;
+}
+
+static const TypeInfo system_bus_info = {
+    .name = TYPE_SYSTEM_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(BusState),
+    .class_init = system_bus_class_init,
 };
 
 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
@@ -244,7 +252,7 @@ static void sysbus_device_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
     k->init = sysbus_device_init;
-    k->bus_info = &system_bus_info;
+    k->bus_type = TYPE_SYSTEM_BUS;
 }
 
 static TypeInfo sysbus_device_type_info = {
@@ -256,8 +264,33 @@ static TypeInfo sysbus_device_type_info = {
     .class_init = sysbus_device_class_init,
 };
 
+/* This is a nasty hack to allow passing a NULL bus to qdev_create.  */
+static BusState *main_system_bus;
+
+static void main_system_bus_create(void)
+{
+    /* assign main_system_bus before qbus_create_inplace()
+     * in order to make "if (bus != sysbus_get_default())" work */
+    main_system_bus = g_malloc0(system_bus_info.instance_size);
+    qbus_create_inplace(main_system_bus, TYPE_SYSTEM_BUS, NULL,
+                        "main-system-bus");
+    main_system_bus->glib_allocated = true;
+    object_property_add_child(container_get(qdev_get_machine(),
+                                            "/unattached"),
+                              "sysbus", OBJECT(main_system_bus), NULL);
+}
+
+BusState *sysbus_get_default(void)
+{
+    if (!main_system_bus) {
+        main_system_bus_create();
+    }
+    return main_system_bus;
+}
+
 static void sysbus_register_types(void)
 {
+    type_register_static(&system_bus_info);
     type_register_static(&sysbus_device_type_info);
 }
 
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 22555cd443..acfbcfba52 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -10,6 +10,9 @@
 #define QDEV_MAX_PIO 32
 #define QDEV_MAX_IRQ 512
 
+#define TYPE_SYSTEM_BUS "System"
+#define SYSTEM_BUS(obj) OBJECT_CHECK(IDEBus, (obj), TYPE_IDE_BUS)
+
 typedef struct SysBusDevice SysBusDevice;
 
 #define TYPE_SYS_BUS_DEVICE "sys-bus-device"
diff --git a/hw/usb.h b/hw/usb.h
index ae7ccda18c..2a56fe554f 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -421,6 +421,9 @@ void musb_set_size(MUSBState *s, int epnum, int size, int is_tx);
 
 /* usb-bus.c */
 
+#define TYPE_USB_BUS "usb-bus"
+#define USB_BUS(obj) OBJECT_CHECK(USBBus, (obj), TYPE_USB_BUS)
+
 struct USBBus {
     BusState qbus;
     USBBusOps *ops;
diff --git a/hw/usb/bus.c b/hw/usb/bus.c
index 2068640a58..f87cc5f443 100644
--- a/hw/usb/bus.c
+++ b/hw/usb/bus.c
@@ -11,19 +11,29 @@ static char *usb_get_dev_path(DeviceState *dev);
 static char *usb_get_fw_dev_path(DeviceState *qdev);
 static int usb_qdev_exit(DeviceState *qdev);
 
-static struct BusInfo usb_bus_info = {
-    .name      = "USB",
-    .size      = sizeof(USBBus),
-    .print_dev = usb_bus_dev_print,
-    .get_dev_path = usb_get_dev_path,
-    .get_fw_dev_path = usb_get_fw_dev_path,
-    .props      = (Property[]) {
-        DEFINE_PROP_STRING("port", USBDevice, port_path),
-        DEFINE_PROP_BIT("full-path", USBDevice, flags,
-                        USB_DEV_FLAG_FULL_PATH, true),
-        DEFINE_PROP_END_OF_LIST()
-    },
+static Property usb_props[] = {
+    DEFINE_PROP_STRING("port", USBDevice, port_path),
+    DEFINE_PROP_BIT("full-path", USBDevice, flags,
+                    USB_DEV_FLAG_FULL_PATH, true),
+    DEFINE_PROP_END_OF_LIST()
 };
+
+static void usb_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->print_dev = usb_bus_dev_print;
+    k->get_dev_path = usb_get_dev_path;
+    k->get_fw_dev_path = usb_get_fw_dev_path;
+}
+
+static const TypeInfo usb_bus_info = {
+    .name = TYPE_USB_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(USBBus),
+    .class_init = usb_bus_class_init,
+};
+
 static int next_usb_bus = 0;
 static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
 
@@ -45,7 +55,7 @@ const VMStateDescription vmstate_usb_device = {
 
 void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host)
 {
-    qbus_create_inplace(&bus->qbus, &usb_bus_info, host, NULL);
+    qbus_create_inplace(&bus->qbus, TYPE_USB_BUS, host, NULL);
     bus->ops = ops;
     bus->busnr = next_usb_bus++;
     bus->qbus.allow_hotplug = 1; /* Yes, we can */
@@ -465,9 +475,8 @@ static char *usb_get_dev_path(DeviceState *qdev)
     DeviceState *hcd = qdev->parent_bus->parent;
     char *id = NULL;
 
-    if ((dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) &&
-        hcd && hcd->parent_bus && hcd->parent_bus->info->get_dev_path) {
-        id = hcd->parent_bus->info->get_dev_path(hcd);
+    if (dev->flags & (1 << USB_DEV_FLAG_FULL_PATH)) {
+        id = qdev_get_dev_path(hcd);
     }
     if (id) {
         char *ret = g_strdup_printf("%s/%s", id, dev->port->path);
@@ -576,10 +585,11 @@ USBDevice *usbdevice_create(const char *cmdline)
 static void usb_device_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
-    k->bus_info = &usb_bus_info;
+    k->bus_type = TYPE_USB_BUS;
     k->init     = usb_qdev_init;
     k->unplug   = qdev_simple_unplug_cb;
     k->exit     = usb_qdev_exit;
+    k->props    = usb_props;
 }
 
 static TypeInfo usb_device_type_info = {
@@ -593,6 +603,7 @@ static TypeInfo usb_device_type_info = {
 
 static void usb_register_types(void)
 {
+    type_register_static(&usb_bus_info);
     type_register_static(&usb_device_type_info);
 }
 
diff --git a/hw/usb/desc.c b/hw/usb/desc.c
index e8a3c6af3d..0a9d3c9f60 100644
--- a/hw/usb/desc.c
+++ b/hw/usb/desc.c
@@ -432,12 +432,13 @@ void usb_desc_create_serial(USBDevice *dev)
     const USBDesc *desc = usb_device_get_usb_desc(dev);
     int index = desc->id.iSerialNumber;
     char serial[64];
+    char *path;
     int dst;
 
     assert(index != 0 && desc->str[index] != NULL);
     dst = snprintf(serial, sizeof(serial), "%s", desc->str[index]);
-    if (hcd && hcd->parent_bus && hcd->parent_bus->info->get_dev_path) {
-        char *path = hcd->parent_bus->info->get_dev_path(hcd);
+    path = qdev_get_dev_path(hcd);
+    if (path) {
         dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", path);
     }
     dst += snprintf(serial+dst, sizeof(serial)-dst, "-%s", dev->port->path);
diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c
index 6b74eff4ad..55bc19184b 100644
--- a/hw/usb/dev-bluetooth.c
+++ b/hw/usb/dev-bluetooth.c
@@ -57,7 +57,7 @@ enum {
 };
 
 static const USBDescStrings desc_strings = {
-    [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
+    [STR_MANUFACTURER]     = "QEMU",
     [STR_SERIALNUMBER]     = "1",
 };
 
diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c
index f29544d954..b3dcd23109 100644
--- a/hw/usb/dev-hid.c
+++ b/hw/usb/dev-hid.c
@@ -60,7 +60,7 @@ enum {
 };
 
 static const USBDescStrings desc_strings = {
-    [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
+    [STR_MANUFACTURER]     = "QEMU",
     [STR_PRODUCT_MOUSE]    = "QEMU USB Mouse",
     [STR_PRODUCT_TABLET]   = "QEMU USB Tablet",
     [STR_PRODUCT_KEYBOARD] = "QEMU USB Keyboard",
diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c
index b5962da72a..8fd30df0e6 100644
--- a/hw/usb/dev-hub.c
+++ b/hw/usb/dev-hub.c
@@ -90,7 +90,7 @@ enum {
 };
 
 static const USBDescStrings desc_strings = {
-    [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+    [STR_MANUFACTURER] = "QEMU",
     [STR_PRODUCT]      = "QEMU USB Hub",
     [STR_SERIALNUMBER] = "314159",
 };
diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c
index 56743ee020..8aa655286b 100644
--- a/hw/usb/dev-serial.c
+++ b/hw/usb/dev-serial.c
@@ -111,7 +111,7 @@ enum {
 };
 
 static const USBDescStrings desc_strings = {
-    [STR_MANUFACTURER]    = "QEMU " QEMU_VERSION,
+    [STR_MANUFACTURER]    = "QEMU",
     [STR_PRODUCT_SERIAL]  = "QEMU USB SERIAL",
     [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE",
     [STR_SERIALNUMBER]    = "1",
diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c
index 3b7604e8b1..1ea079176a 100644
--- a/hw/usb/dev-smartcard-reader.c
+++ b/hw/usb/dev-smartcard-reader.c
@@ -81,7 +81,7 @@ do { \
 #define CCID_CONTROL_GET_DATA_RATES         0x3
 
 #define CCID_PRODUCT_DESCRIPTION        "QEMU USB CCID"
-#define CCID_VENDOR_DESCRIPTION         "QEMU " QEMU_VERSION
+#define CCID_VENDOR_DESCRIPTION         "QEMU"
 #define CCID_INTERFACE_NAME             "CCID Interface"
 #define CCID_SERIAL_NUMBER_STRING       "1"
 /*
@@ -401,7 +401,7 @@ enum {
 };
 
 static const USBDescStrings desc_strings = {
-    [STR_MANUFACTURER]  = "QEMU " QEMU_VERSION,
+    [STR_MANUFACTURER]  = "QEMU",
     [STR_PRODUCT]       = "QEMU USB CCID",
     [STR_SERIALNUMBER]  = "1",
     [STR_INTERFACE]     = "CCID Interface",
@@ -1055,13 +1055,18 @@ static Answer *ccid_peek_next_answer(USBCCIDState *s)
         : &s->pending_answers[s->pending_answers_start % PENDING_ANSWERS_NUM];
 }
 
-static struct BusInfo ccid_bus_info = {
-    .name = "ccid-bus",
-    .size = sizeof(CCIDBus),
-    .props = (Property[]) {
-        DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
+static Property ccid_props[] = {
+    DEFINE_PROP_UINT32("slot", struct CCIDCardState, slot, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+#define TYPE_CCID_BUS "ccid-bus"
+#define CCID_BUS(obj) OBJECT_CHECK(CCIDBus, (obj), TYPE_CCID_BUS)
+
+static const TypeInfo ccid_bus_info = {
+    .name = TYPE_CCID_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(CCIDBus),
 };
 
 void ccid_card_send_apdu_to_guest(CCIDCardState *card,
@@ -1191,7 +1196,7 @@ static int ccid_initfn(USBDevice *dev)
 
     usb_desc_create_serial(dev);
     usb_desc_init(dev);
-    qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
+    qbus_create_inplace(&s->bus.qbus, TYPE_CCID_BUS, &dev->qdev, NULL);
     s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
     s->bus.qbus.allow_hotplug = 1;
     s->card = NULL;
@@ -1342,9 +1347,10 @@ static TypeInfo ccid_info = {
 static void ccid_card_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
-    k->bus_info = &ccid_bus_info;
+    k->bus_type = TYPE_CCID_BUS;
     k->init = ccid_card_init;
     k->exit = ccid_card_exit;
+    k->props = ccid_props;
 }
 
 static TypeInfo ccid_card_type_info = {
@@ -1358,6 +1364,7 @@ static TypeInfo ccid_card_type_info = {
 
 static void ccid_register_types(void)
 {
+    type_register_static(&ccid_bus_info);
     type_register_static(&ccid_card_type_info);
     type_register_static(&ccid_info);
     usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 097d7b4a6d..251e7de1cd 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -81,7 +81,7 @@ enum {
 };
 
 static const USBDescStrings desc_strings = {
-    [STR_MANUFACTURER] = "QEMU " QEMU_VERSION,
+    [STR_MANUFACTURER] = "QEMU",
     [STR_PRODUCT]      = "QEMU USB HARDDRIVE",
     [STR_SERIALNUMBER] = "1",
     [STR_CONFIG_FULL]  = "Full speed config (usb 1.1)",
diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c
index 3b51d458f4..ed9a5ee358 100644
--- a/hw/usb/dev-wacom.c
+++ b/hw/usb/dev-wacom.c
@@ -62,7 +62,7 @@ enum {
 };
 
 static const USBDescStrings desc_strings = {
-    [STR_MANUFACTURER]     = "QEMU " QEMU_VERSION,
+    [STR_MANUFACTURER]     = "QEMU",
     [STR_PRODUCT]          = "Wacom PenPartner",
     [STR_SERIALNUMBER]     = "1",
 };
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 51c27b4051..d949f040d5 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -143,8 +143,6 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
 static int usbredir_handle_status(USBRedirDevice *dev,
                                        int status, int actual_len);
 
-#define VERSION "qemu usb-redir guest " QEMU_VERSION
-
 /*
  * Logging stuff
  */
@@ -794,6 +792,10 @@ static void usbredir_open_close_bh(void *opaque)
 {
     USBRedirDevice *dev = opaque;
     uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
+    char version[32];
+
+    strcpy(version, "qemu usb-redir guest ");
+    pstrcat(version, sizeof(version), qemu_get_version());
 
     usbredir_device_disconnect(dev);
 
@@ -828,7 +830,7 @@ static void usbredir_open_close_bh(void *opaque)
 
         usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version);
         usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
-        usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0);
+        usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0);
         usbredirparser_do_write(dev->parser);
     }
 }
diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
index 075ed87e37..d048cef50f 100644
--- a/hw/virtio-balloon.c
+++ b/hw/virtio-balloon.c
@@ -146,8 +146,13 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
 {
     VirtIOBalloon *dev = to_virtio_balloon(vdev);
     struct virtio_balloon_config config;
+    uint32_t oldactual = dev->actual;
     memcpy(&config, config_data, 8);
     dev->actual = le32_to_cpu(config.actual);
+    if (dev->actual != oldactual) {
+        qemu_balloon_changed(ram_size -
+                             (dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
+    }
 }
 
 static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index d08c1590d2..9342eed070 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -278,7 +278,6 @@ void virtio_pci_reset(DeviceState *d)
     VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
     virtio_pci_stop_ioeventfd(proxy);
     virtio_reset(proxy->vdev);
-    msix_reset(&proxy->pci_dev);
     proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
 }
 
@@ -521,8 +520,6 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
         virtio_set_status(proxy->vdev,
                           proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
     }
-
-    msix_write_config(pci_dev, address, val, len);
 }
 
 static unsigned virtio_pci_get_features(void *opaque)
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 5e39ce93c4..e1a767ea78 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -275,7 +275,7 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
 {
     SCSIDevice *d = virtio_scsi_device_find(s, req->req.tmf->lun);
     SCSIRequest *r, *next;
-    DeviceState *qdev;
+    BusChild *kid;
     int target;
 
     /* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE".  */
@@ -346,8 +346,8 @@ static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
     case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET:
         target = req->req.tmf->lun[1];
         s->resetting++;
-        QTAILQ_FOREACH(qdev, &s->bus.qbus.children, sibling) {
-             d = DO_UPCAST(SCSIDevice, qdev, qdev);
+        QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+             d = DO_UPCAST(SCSIDevice, qdev, kid->child);
              if (d->channel == 0 && d->id == target) {
                 qdev_reset_all(&d->qdev);
              }
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 72287d10ce..96382a4ea1 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -728,15 +728,27 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
 
 static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent);
 
-static struct BusInfo virtser_bus_info = {
-    .name      = "virtio-serial-bus",
-    .size      = sizeof(VirtIOSerialBus),
-    .print_dev = virtser_bus_dev_print,
-    .props      = (Property[]) {
-        DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
-        DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
-        DEFINE_PROP_END_OF_LIST()
-    }
+static Property virtser_props[] = {
+    DEFINE_PROP_UINT32("nr", VirtIOSerialPort, id, VIRTIO_CONSOLE_BAD_ID),
+    DEFINE_PROP_STRING("name", VirtIOSerialPort, name),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+#define TYPE_VIRTIO_SERIAL_BUS "virtio-serial-bus"
+#define VIRTIO_SERIAL_BUS(obj) \
+      OBJECT_CHECK(VirtIOSerialBus, (obj), TYPE_VIRTIO_SERIAL_BUS)
+
+static void virtser_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+    k->print_dev = virtser_bus_dev_print;
+}
+
+static const TypeInfo virtser_bus_info = {
+    .name = TYPE_VIRTIO_SERIAL_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(VirtIOSerialBus),
+    .class_init = virtser_bus_class_init,
 };
 
 static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
@@ -904,7 +916,7 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
 
     /* Spawn a new virtio-serial bus on which the ports will ride as devices */
-    qbus_create_inplace(&vser->bus.qbus, &virtser_bus_info, dev, NULL);
+    qbus_create_inplace(&vser->bus.qbus, TYPE_VIRTIO_SERIAL_BUS, dev, NULL);
     vser->bus.qbus.allow_hotplug = 1;
     vser->bus.vser = vser;
     QTAILQ_INIT(&vser->ports);
@@ -980,9 +992,10 @@ static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
     k->init = virtser_port_qdev_init;
-    k->bus_info = &virtser_bus_info;
+    k->bus_type = TYPE_VIRTIO_SERIAL_BUS;
     k->exit = virtser_port_qdev_exit;
     k->unplug = qdev_simple_unplug_cb;
+    k->props = virtser_props;
 }
 
 static TypeInfo virtio_serial_port_type_info = {
@@ -996,6 +1009,7 @@ static TypeInfo virtio_serial_port_type_info = {
 
 static void virtio_serial_register_types(void)
 {
+    type_register_static(&virtser_bus_info);
     type_register_static(&virtio_serial_port_type_info);
 }
 
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index 6fb7950fa6..5d7c00cf4b 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -210,7 +210,7 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
         pm_update_sci(s);
         break;
     case 0x04:
-        acpi_pm1_cnt_write(&s->ar, val);
+        acpi_pm1_cnt_write(&s->ar, val, 0);
         break;
     default:
         break;
diff --git a/hw/xen_devconfig.c b/hw/xen_devconfig.c
index 41accbbfa9..0928613b55 100644
--- a/hw/xen_devconfig.c
+++ b/hw/xen_devconfig.c
@@ -1,6 +1,5 @@
 #include "xen_backend.h"
 #include "blockdev.h"
-#include "block_int.h" /* XXX */
 
 /* ------------------------------------------------------------- */
 
@@ -94,16 +93,16 @@ static int xen_config_dev_all(char *fe, char *be)
 
 int xen_config_dev_blk(DriveInfo *disk)
 {
-    char fe[256], be[256];
+    char fe[256], be[256], device_name[32];
     int vdev = 202 * 256 + 16 * disk->unit;
     int cdrom = disk->media_cd;
     const char *devtype = cdrom ? "cdrom" : "disk";
     const char *mode    = cdrom ? "r"     : "w";
+    const char *filename = qemu_opt_get(disk->opts, "file");
 
-    snprintf(disk->bdrv->device_name, sizeof(disk->bdrv->device_name),
-	     "xvd%c", 'a' + disk->unit);
+    snprintf(device_name, sizeof(device_name), "xvd%c", 'a' + disk->unit);
     xen_be_printf(NULL, 1, "config disk %d [%s]: %s\n",
-                  disk->unit, disk->bdrv->device_name, disk->bdrv->filename);
+                  disk->unit, device_name, filename);
     xen_config_dev_dirs("vbd", "qdisk", vdev, fe, be, sizeof(fe));
 
     /* frontend */
@@ -111,9 +110,9 @@ int xen_config_dev_blk(DriveInfo *disk)
     xenstore_write_str(fe, "device-type",     devtype);
 
     /* backend */
-    xenstore_write_str(be, "dev",             disk->bdrv->device_name);
+    xenstore_write_str(be, "dev",             device_name);
     xenstore_write_str(be, "type",            "file");
-    xenstore_write_str(be, "params",          disk->bdrv->filename);
+    xenstore_write_str(be, "params",          filename);
     xenstore_write_str(be, "mode",            mode);
 
     /* common stuff */
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index de7e8a4a5c..fb68ed9bbf 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -40,7 +40,6 @@
 #include <xen/io/xenbus.h>
 
 #include "hw.h"
-#include "block_int.h"
 #include "qemu-char.h"
 #include "xen_blkif.h"
 #include "xen_backend.h"
@@ -650,7 +649,7 @@ static int blk_init(struct XenDevice *xendev)
     if (blkdev->file_size < 0) {
         xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
                       (int)blkdev->file_size, strerror(-blkdev->file_size),
-                      blkdev->bs->drv ? blkdev->bs->drv->format_name : "-");
+                      bdrv_get_format_name(blkdev->bs) ?: "-");
         blkdev->file_size = 0;
     }
 
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index 0683ce1ecf..b562bd065e 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -23,7 +23,6 @@
  */
 
 #include "sysbus.h"
-#include "qemu-timer.h"
 #include "ptimer.h"
 
 #define D(x)
@@ -137,7 +136,7 @@ static void timer_enable(struct xlx_timer *xt)
         count = xt->regs[R_TLR];
     else
         count = ~0 - xt->regs[R_TLR];
-    ptimer_set_count(xt->ptimer, count);
+    ptimer_set_limit(xt->ptimer, count, 1);
     ptimer_run(xt->ptimer, 1);
 }
 
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index 319624f212..56d1b353d0 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -41,14 +41,13 @@ static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
     pci_bridge_write_config(d, address, val, len);
     pcie_cap_flr_write_config(d, address, val, len);
     pcie_cap_slot_write_config(d, address, val, len);
-    msi_write_config(d, address, val, len);
     pcie_aer_write_config(d, address, val, len);
 }
 
 static void xio3130_downstream_reset(DeviceState *qdev)
 {
     PCIDevice *d = PCI_DEVICE(qdev);
-    msi_reset(d);
+
     pcie_cap_deverr_reset(d);
     pcie_cap_slot_reset(d);
     pcie_cap_ari_reset(d);
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 34a99bba08..79725813a2 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -40,14 +40,13 @@ static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
 {
     pci_bridge_write_config(d, address, val, len);
     pcie_cap_flr_write_config(d, address, val, len);
-    msi_write_config(d, address, val, len);
     pcie_aer_write_config(d, address, val, len);
 }
 
 static void xio3130_upstream_reset(DeviceState *qdev)
 {
     PCIDevice *d = PCI_DEVICE(qdev);
-    msi_reset(d);
+
     pci_bridge_reset(qdev);
     pcie_cap_deverr_reset(d);
 }
diff --git a/hw/xtensa_lx60.c b/hw/xtensa_lx60.c
index b153bfdddf..152eed95d8 100644
--- a/hw/xtensa_lx60.c
+++ b/hw/xtensa_lx60.c
@@ -34,6 +34,7 @@
 #include "pc.h"
 #include "sysbus.h"
 #include "flash.h"
+#include "blockdev.h"
 #include "xtensa_bootparam.h"
 
 typedef struct LxBoardDesc {