Merge remote-tracking branch 'remotes/kraxel/tags/pull-input-6' into staging

input: activate legacy kbd
gtk: Add mouse wheel support

# gpg: Signature made Thu 13 Mar 2014 10:34:17 GMT using RSA key ID D3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>"
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>"
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>"

* remotes/kraxel/tags/pull-input-6:
  gtk: Add mouse wheel support
  input: activate legacy kbd

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/.gitmodules b/.gitmodules
index 45e51e7..444c24a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,6 +13,9 @@
 [submodule "roms/openbios"]
 	path = roms/openbios
 	url = git://git.qemu-project.org/openbios.git
+[submodule "roms/openhackware"]
+	path = roms/openhackware
+	url = git://git.qemu-project.org/openhackware.git
 [submodule "roms/qemu-palcode"]
 	path = roms/qemu-palcode
 	url = git://github.com/rth7680/qemu-palcode.git
diff --git a/Makefile.objs b/Makefile.objs
index 5cd3d81..a6e0e2a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -39,6 +39,7 @@
 
 ifeq ($(CONFIG_SOFTMMU),y)
 common-obj-y = blockdev.o blockdev-nbd.o block/
+common-obj-y += iothread.o
 common-obj-y += net/
 common-obj-y += qdev-monitor.o device-hotplug.o
 common-obj-$(CONFIG_WIN32) += os-win32.o
diff --git a/async.c b/async.c
index 5fb3fa6..6930185 100644
--- a/async.c
+++ b/async.c
@@ -214,6 +214,7 @@
     thread_pool_free(ctx->thread_pool);
     aio_set_event_notifier(ctx, &ctx->notifier, NULL);
     event_notifier_cleanup(&ctx->notifier);
+    rfifolock_destroy(&ctx->lock);
     qemu_mutex_destroy(&ctx->bh_lock);
     g_array_free(ctx->pollfds, TRUE);
     timerlistgroup_deinit(&ctx->tlg);
@@ -250,6 +251,12 @@
     aio_notify(opaque);
 }
 
+static void aio_rfifolock_cb(void *opaque)
+{
+    /* Kick owner thread in case they are blocked in aio_poll() */
+    aio_notify(opaque);
+}
+
 AioContext *aio_context_new(void)
 {
     AioContext *ctx;
@@ -257,6 +264,7 @@
     ctx->pollfds = g_array_new(FALSE, FALSE, sizeof(GPollFD));
     ctx->thread_pool = NULL;
     qemu_mutex_init(&ctx->bh_lock);
+    rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx);
     event_notifier_init(&ctx->notifier, false);
     aio_set_event_notifier(ctx, &ctx->notifier, 
                            (EventNotifierHandler *)
@@ -275,3 +283,13 @@
 {
     g_source_unref(&ctx->source);
 }
+
+void aio_context_acquire(AioContext *ctx)
+{
+    rfifolock_lock(&ctx->lock);
+}
+
+void aio_context_release(AioContext *ctx)
+{
+    rfifolock_unlock(&ctx->lock);
+}
diff --git a/block.c b/block.c
index f1ef4b0..fae50c9 100644
--- a/block.c
+++ b/block.c
@@ -1321,7 +1321,7 @@
                           bdrv_open_flags(bs, flags | BDRV_O_UNMAP) |
                           BDRV_O_PROTOCOL, true, &local_err);
     if (ret < 0) {
-        goto fail;
+        goto unlink_and_fail;
     }
 
     /* Find the right image format driver */
@@ -4055,7 +4055,7 @@
 
 int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
 {
-    while (bs && bs->drv && !bs->drv->bdrv_debug_resume) {
+    while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) {
         bs = bs->file;
     }
 
@@ -4776,9 +4776,17 @@
 
 void bdrv_invalidate_cache(BlockDriverState *bs)
 {
-    if (bs->drv && bs->drv->bdrv_invalidate_cache) {
-        bs->drv->bdrv_invalidate_cache(bs);
+    if (!bs->drv)  {
+        return;
     }
+
+    if (bs->drv->bdrv_invalidate_cache) {
+        bs->drv->bdrv_invalidate_cache(bs);
+    } else if (bs->file) {
+        bdrv_invalidate_cache(bs->file);
+    }
+
+    refresh_total_sectors(bs, bs->total_sectors);
 }
 
 void bdrv_invalidate_cache_all(void)
@@ -5390,43 +5398,37 @@
     return bs->drv->bdrv_amend_options(bs, options);
 }
 
-/* Used to recurse on single child block filters.
- * Single child block filter will store their child in bs->file.
+/* This function will be called by the bdrv_recurse_is_first_non_filter method
+ * of block filter and by bdrv_is_first_non_filter.
+ * It is used to test if the given bs is the candidate or recurse more in the
+ * node graph.
  */
-bool bdrv_generic_is_first_non_filter(BlockDriverState *bs,
-                                      BlockDriverState *candidate)
-{
-    if (!bs->drv) {
-        return false;
-    }
-
-    if (!bs->drv->authorizations[BS_IS_A_FILTER]) {
-        if (bs == candidate) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    if (!bs->drv->authorizations[BS_FILTER_PASS_DOWN]) {
-        return false;
-    }
-
-    if (!bs->file) {
-        return false;
-    }
-
-    return bdrv_recurse_is_first_non_filter(bs->file, candidate);
-}
-
 bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
                                       BlockDriverState *candidate)
 {
-    if (bs->drv && bs->drv->bdrv_recurse_is_first_non_filter) {
+    /* return false if basic checks fails */
+    if (!bs || !bs->drv) {
+        return false;
+    }
+
+    /* the code reached a non block filter driver -> check if the bs is
+     * the same as the candidate. It's the recursion termination condition.
+     */
+    if (!bs->drv->is_filter) {
+        return bs == candidate;
+    }
+    /* Down this path the driver is a block filter driver */
+
+    /* If the block filter recursion method is defined use it to recurse down
+     * the node graph.
+     */
+    if (bs->drv->bdrv_recurse_is_first_non_filter) {
         return bs->drv->bdrv_recurse_is_first_non_filter(bs, candidate);
     }
 
-    return bdrv_generic_is_first_non_filter(bs, candidate);
+    /* the driver is a block filter but don't allow to recurse -> return false
+     */
+    return false;
 }
 
 /* This function checks if the candidate is the first non filter bs down it's
@@ -5441,6 +5443,7 @@
     QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
         bool perm;
 
+        /* try to recurse in this top level bs */
         perm = bdrv_recurse_is_first_non_filter(bs, candidate);
 
         /* candidate is the first non filter */
diff --git a/block/blkverify.c b/block/blkverify.c
index b98b08b..e1c3117 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -288,6 +288,20 @@
     return bdrv_aio_flush(s->test_file, cb, opaque);
 }
 
+static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs,
+                                                  BlockDriverState *candidate)
+{
+    BDRVBlkverifyState *s = bs->opaque;
+
+    bool perm = bdrv_recurse_is_first_non_filter(bs->file, candidate);
+
+    if (perm) {
+        return true;
+    }
+
+    return bdrv_recurse_is_first_non_filter(s->test_file, candidate);
+}
+
 static BlockDriver bdrv_blkverify = {
     .format_name            = "blkverify",
     .protocol_name          = "blkverify",
@@ -302,7 +316,8 @@
     .bdrv_aio_writev        = blkverify_aio_writev,
     .bdrv_aio_flush         = blkverify_aio_flush,
 
-    .authorizations         = { true, false },
+    .is_filter              = true,
+    .bdrv_recurse_is_first_non_filter = blkverify_recurse_is_first_non_filter,
 };
 
 static void bdrv_blkverify_init(void)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 36c1bed..9499df9 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -380,6 +380,10 @@
 
     BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
 
+    if (!bs->drv) {
+        return -ENOMEDIUM;
+    }
+
     /* Call .bdrv_co_readv() directly instead of using the public block-layer
      * interface.  This avoids double I/O throttling and request tracking,
      * which can lead to deadlock when block layer copy-on-read is enabled.
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 8712d8b..6151148 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -96,7 +96,8 @@
     refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
     if (refcount_table_index >= s->refcount_table_size)
         return 0;
-    refcount_block_offset = s->refcount_table[refcount_table_index];
+    refcount_block_offset =
+        s->refcount_table[refcount_table_index] & REFT_OFFSET_MASK;
     if (!refcount_block_offset)
         return 0;
 
diff --git a/block/qcow2.c b/block/qcow2.c
index cfe80be..945c9d6 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -644,7 +644,7 @@
     }
 
     /* Clear unknown autoclear feature bits */
-    if (!bs->read_only && s->autoclear_features != 0) {
+    if (!bs->read_only && !(flags & BDRV_O_INCOMING) && s->autoclear_features) {
         s->autoclear_features = 0;
         ret = qcow2_update_header(bs);
         if (ret < 0) {
@@ -657,7 +657,7 @@
     qemu_co_mutex_init(&s->lock);
 
     /* Repair image if dirty */
-    if (!(flags & BDRV_O_CHECK) && !bs->read_only &&
+    if (!(flags & (BDRV_O_CHECK | BDRV_O_INCOMING)) && !bs->read_only &&
         (s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
         BdrvCheckResult result = {0};
 
@@ -1137,10 +1137,12 @@
     /* else pre-write overlap checks in cache_destroy may crash */
     s->l1_table = NULL;
 
-    qcow2_cache_flush(bs, s->l2_table_cache);
-    qcow2_cache_flush(bs, s->refcount_block_cache);
+    if (!(bs->open_flags & BDRV_O_INCOMING)) {
+        qcow2_cache_flush(bs, s->l2_table_cache);
+        qcow2_cache_flush(bs, s->refcount_block_cache);
 
-    qcow2_mark_clean(bs);
+        qcow2_mark_clean(bs);
+    }
 
     qcow2_cache_destroy(bs, s->l2_table_cache);
     qcow2_cache_destroy(bs, s->refcount_block_cache);
@@ -1176,11 +1178,10 @@
 
     qcow2_close(bs);
 
-    options = qdict_new();
-    qdict_put(options, QCOW2_OPT_LAZY_REFCOUNTS,
-              qbool_from_int(s->use_lazy_refcounts));
+    bdrv_invalidate_cache(bs->file);
 
     memset(s, 0, sizeof(BDRVQcowState));
+    options = qdict_clone_shallow(bs->options);
     qcow2_open(bs, options, flags, NULL);
 
     QDECREF(options);
diff --git a/block/qed.c b/block/qed.c
index 8802ad3..837accd 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1563,6 +1563,9 @@
     BDRVQEDState *s = bs->opaque;
 
     bdrv_qed_close(bs);
+
+    bdrv_invalidate_cache(bs->file);
+
     memset(s, 0, sizeof(BDRVQEDState));
     bdrv_qed_open(bs, NULL, bs->open_flags, NULL);
 }
diff --git a/block/quorum.c b/block/quorum.c
index bd997b7..33bf2ae 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -852,8 +852,6 @@
     .bdrv_file_open     = quorum_open,
     .bdrv_close         = quorum_close,
 
-    .authorizations     = { true, true },
-
     .bdrv_co_flush_to_disk = quorum_co_flush,
 
     .bdrv_getlength     = quorum_getlength,
@@ -862,6 +860,7 @@
     .bdrv_aio_writev    = quorum_aio_writev,
     .bdrv_invalidate_cache = quorum_invalidate_cache,
 
+    .is_filter           = true,
     .bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter,
 };
 
diff --git a/block/raw-posix.c b/block/raw-posix.c
index e6b4c1f..1688e16 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1561,6 +1561,15 @@
     return 0;
 }
 
+static void hdev_parse_filename(const char *filename, QDict *options,
+                                Error **errp)
+{
+    /* The prefix is optional, just as for "file". */
+    strstart(filename, "host_device:", &filename);
+
+    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
 static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
                      Error **errp)
 {
@@ -1767,6 +1776,18 @@
     int ret = 0;
     struct stat stat_buf;
     int64_t total_size = 0;
+    bool has_prefix;
+
+    /* This function is used by all three protocol block drivers and therefore
+     * any of these three prefixes may be given.
+     * The return value has to be stored somewhere, otherwise this is an error
+     * due to -Werror=unused-value. */
+    has_prefix =
+        strstart(filename, "host_device:", &filename) ||
+        strstart(filename, "host_cdrom:" , &filename) ||
+        strstart(filename, "host_floppy:", &filename);
+
+    (void)has_prefix;
 
     /* Read out options */
     while (options && options->name) {
@@ -1805,6 +1826,7 @@
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_needs_filename = true,
     .bdrv_probe_device  = hdev_probe_device,
+    .bdrv_parse_filename = hdev_parse_filename,
     .bdrv_file_open     = hdev_open,
     .bdrv_close         = raw_close,
     .bdrv_reopen_prepare = raw_reopen_prepare,
@@ -1834,6 +1856,15 @@
 };
 
 #ifdef __linux__
+static void floppy_parse_filename(const char *filename, QDict *options,
+                                  Error **errp)
+{
+    /* The prefix is optional, just as for "file". */
+    strstart(filename, "host_floppy:", &filename);
+
+    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
 static int floppy_open(BlockDriverState *bs, QDict *options, int flags,
                        Error **errp)
 {
@@ -1939,6 +1970,7 @@
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_needs_filename = true,
     .bdrv_probe_device	= floppy_probe_device,
+    .bdrv_parse_filename = floppy_parse_filename,
     .bdrv_file_open     = floppy_open,
     .bdrv_close         = raw_close,
     .bdrv_reopen_prepare = raw_reopen_prepare,
@@ -1963,7 +1995,20 @@
     .bdrv_media_changed = floppy_media_changed,
     .bdrv_eject         = floppy_eject,
 };
+#endif
 
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+static void cdrom_parse_filename(const char *filename, QDict *options,
+                                 Error **errp)
+{
+    /* The prefix is optional, just as for "file". */
+    strstart(filename, "host_cdrom:", &filename);
+
+    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+#endif
+
+#ifdef __linux__
 static int cdrom_open(BlockDriverState *bs, QDict *options, int flags,
                       Error **errp)
 {
@@ -2050,6 +2095,7 @@
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_needs_filename = true,
     .bdrv_probe_device	= cdrom_probe_device,
+    .bdrv_parse_filename = cdrom_parse_filename,
     .bdrv_file_open     = cdrom_open,
     .bdrv_close         = raw_close,
     .bdrv_reopen_prepare = raw_reopen_prepare,
@@ -2180,6 +2226,7 @@
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_needs_filename = true,
     .bdrv_probe_device	= cdrom_probe_device,
+    .bdrv_parse_filename = cdrom_parse_filename,
     .bdrv_file_open     = cdrom_open,
     .bdrv_close         = raw_close,
     .bdrv_reopen_prepare = raw_reopen_prepare,
diff --git a/block/raw-win32.c b/block/raw-win32.c
index 9954748..48cb2c2 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -593,6 +593,15 @@
     return 0;
 }
 
+static void hdev_parse_filename(const char *filename, QDict *options,
+                                Error **errp)
+{
+    /* The prefix is optional, just as for "file". */
+    strstart(filename, "host_device:", &filename);
+
+    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
 static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
                      Error **errp)
 {
@@ -663,6 +672,7 @@
     .protocol_name	= "host_device",
     .instance_size	= sizeof(BDRVRawState),
     .bdrv_needs_filename = true,
+    .bdrv_parse_filename = hdev_parse_filename,
     .bdrv_probe_device	= hdev_probe_device,
     .bdrv_file_open	= hdev_open,
     .bdrv_close		= raw_close,
diff --git a/configure b/configure
index 9539979..8c2838e 100755
--- a/configure
+++ b/configure
@@ -31,19 +31,6 @@
 echo >> config.log
 echo "#" >> config.log
 
-# Save the configure command line for later reuse.
-cat <<EOD >config.status
-#!/bin/sh
-# Generated by configure.
-# Run this file to recreate the current configuration.
-# Compiler output produced by configure, useful for debugging
-# configure, is in config.log if it exists.
-EOD
-printf "exec" >>config.status
-printf " '%s'" "$0" "$@" >>config.status
-echo >>config.status
-chmod +x config.status
-
 error_exit() {
     echo
     echo "ERROR: $1"
@@ -5146,3 +5133,17 @@
 if test "$docs" = "yes" ; then
   mkdir -p QMP
 fi
+
+# Save the configure command line for later reuse.
+cat <<EOD >config.status
+#!/bin/sh
+# Generated by configure.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+EOD
+printf "exec" >>config.status
+printf " '%s'" "$0" "$@" >>config.status
+echo >>config.status
+chmod +x config.status
+
diff --git a/device-hotplug.c b/device-hotplug.c
index 103d34a..ebfa6b1 100644
--- a/device-hotplug.c
+++ b/device-hotplug.c
@@ -33,12 +33,14 @@
 {
     DriveInfo *dinfo;
     QemuOpts *opts;
+    MachineClass *mc;
 
     opts = drive_def(optstr);
     if (!opts)
         return NULL;
 
-    dinfo = drive_init(opts, current_machine->block_default_type);
+    mc = MACHINE_GET_CLASS(current_machine);
+    dinfo = drive_init(opts, mc->qemu_machine->block_default_type);
     if (!dinfo) {
         qemu_opts_del(opts);
         return NULL;
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 0728f36..d78921f 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -123,11 +123,12 @@
 
 Flat union types avoid the nesting on the wire. They are used whenever a
 specific field of the base type is declared as the discriminator ('type' is
-then no longer generated). The discriminator must always be a string field.
+then no longer generated). The discriminator must be of enumeration type.
 The above example can then be modified as follows:
 
+ { 'enum': 'BlockdevDriver', 'data': [ 'raw', 'qcow2' ] }
  { 'type': 'BlockdevCommonOptions',
-   'data': { 'driver': 'str', 'readonly': 'bool' } }
+   'data': { 'driver': 'BlockdevDriver', 'readonly': 'bool' } }
  { 'union': 'BlockdevOptions',
    'base': 'BlockdevCommonOptions',
    'discriminator': 'driver',
diff --git a/docs/qemupciserial.inf b/docs/qemupciserial.inf
index 3474310..6f7eef4 100644
--- a/docs/qemupciserial.inf
+++ b/docs/qemupciserial.inf
@@ -11,99 +11,92 @@
 ; (Com+Lpt)" from the list.  Click "Have a disk".  Select this file.
 ; Procedure may vary a bit depending on the windows version.
 
-; FIXME: This file covers the single port version only.
+; This file covers all options: pci-serial, pci-serial-2x, pci-serial-4x
+; for both 32 and 64 bit platforms.
 
 [Version]
-Signature="$CHICAGO$"
-Class=Ports
-ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
+Signature="$Windows NT$"
+Class=MultiFunction
+ClassGUID={4d36e971-e325-11ce-bfc1-08002be10318}
 Provider=%QEMU%
-DriverVer=09/24/2012,1.3.0
-
-[SourceDisksNames]
-3426=windows cd
-
-[SourceDisksFiles]
-serial.sys 		= 3426
-serenum.sys 		= 3426
-
-[DestinationDirs]
-DefaultDestDir  = 11        ;LDID_SYS
-ComPort.NT.Copy = 12        ;DIRID_DRIVERS
-SerialEnumerator.NT.Copy=12 ;DIRID_DRIVERS
-
-; Drivers
-;----------------------------------------------------------
+DriverVer=12/29/2013,1.3.0
+[ControlFlags]
+ExcludeFromSelect=*
 [Manufacturer]
-%QEMU%=QEMU,NTx86
+%QEMU%=QEMU,NTx86,NTAMD64
 
 [QEMU.NTx86]
-%QEMU-PCI_SERIAL.DeviceDesc% = ComPort, "PCI\VEN_1b36&DEV_0002&CC_0700"
+%QEMU-PCI_SERIAL_1_PORT%=ComPort_inst1, PCI\VEN_1B36&DEV_0002
+%QEMU-PCI_SERIAL_2_PORT%=ComPort_inst2, PCI\VEN_1B36&DEV_0003
+%QEMU-PCI_SERIAL_4_PORT%=ComPort_inst4, PCI\VEN_1B36&DEV_0004
 
-; COM sections
-;----------------------------------------------------------
-[ComPort.AddReg]
-HKR,,PortSubClass,1,01
+[QEMU.NTAMD64]
+%QEMU-PCI_SERIAL_1_PORT%=ComPort_inst1, PCI\VEN_1B36&DEV_0002
+%QEMU-PCI_SERIAL_2_PORT%=ComPort_inst2, PCI\VEN_1B36&DEV_0003
+%QEMU-PCI_SERIAL_4_PORT%=ComPort_inst4, PCI\VEN_1B36&DEV_0004
 
-[ComPort.NT]
-AddReg=ComPort.AddReg, ComPort.NT.AddReg
-LogConfig=caa
-SyssetupPnPFlags = 1
+[ComPort_inst1]
+Include=mf.inf
+Needs=MFINSTALL.mf
 
-[ComPort.NT.HW]
-AddReg=ComPort.NT.HW.AddReg
+[ComPort_inst2]
+Include=mf.inf
+Needs=MFINSTALL.mf
 
-[ComPort.NT.AddReg]
-HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
+[ComPort_inst4]
+Include=mf.inf
+Needs=MFINSTALL.mf
 
-[ComPort.NT.HW.AddReg]
-HKR,,"UpperFilters",0x00010000,"serenum"
+[ComPort_inst1.HW]
+AddReg=ComPort_inst1.RegHW
 
-;-------------- Service installation
-; Port Driver (function driver for this device)
-[ComPort.NT.Services]
-AddService = Serial, 0x00000002, Serial_Service_Inst, Serial_EventLog_Inst
-AddService = Serenum,,Serenum_Service_Inst
+[ComPort_inst2.HW]
+AddReg=ComPort_inst2.RegHW
 
-; -------------- Serial Port Driver install sections
-[Serial_Service_Inst]
-DisplayName    = %Serial.SVCDESC%
-ServiceType    = 1               ; SERVICE_KERNEL_DRIVER
-StartType      = 1               ; SERVICE_SYSTEM_START (this driver may do detection)
-ErrorControl   = 0               ; SERVICE_ERROR_IGNORE
-ServiceBinary  = %12%\serial.sys
-LoadOrderGroup = Extended base
+[ComPort_inst4.HW]
+AddReg=ComPort_inst4.RegHW
 
-; -------------- Serenum Driver install section
-[Serenum_Service_Inst]
-DisplayName    = %Serenum.SVCDESC%
-ServiceType    = 1               ; SERVICE_KERNEL_DRIVER
-StartType      = 3               ; SERVICE_DEMAND_START
-ErrorControl   = 1               ; SERVICE_ERROR_NORMAL
-ServiceBinary  = %12%\serenum.sys
-LoadOrderGroup = PNP Filter
+[ComPort_inst1.Services]
+Include=mf.inf
+Needs=MFINSTALL.mf.Services
 
-[Serial_EventLog_Inst]
-AddReg = Serial_EventLog_AddReg
+[ComPort_inst2.Services]
+Include=mf.inf
+Needs=MFINSTALL.mf.Services
 
-[Serial_EventLog_AddReg]
-HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\IoLogMsg.dll;%%SystemRoot%%\System32\drivers\serial.sys"
-HKR,,TypesSupported,0x00010001,7
+[ComPort_inst4.Services]
+Include=mf.inf
+Needs=MFINSTALL.mf.Services
 
-; The following sections are COM port resource configs.
-; Section name format means:
-; Char 1 = c (COM port)
-; Char 2 = I/O config: 1 (3f8), 2 (2f8), 3 (3e8), 4 (2e8), a (any)
-; Char 3 = IRQ config: #, a (any)
+[ComPort_inst1.RegHW]
+HKR,Child0000,HardwareID,,*PNP0501
+HKR,Child0000,VaryingResourceMap,1,00, 00,00,00,00, 08,00,00,00
+HKR,Child0000,ResourceMap,1,02
 
-[caa]                   ; Any base, any IRQ
-ConfigPriority=HARDRECONFIG
-IOConfig=8@100-ffff%fff8(3ff::)
-IRQConfig=S:3,4,5,7,9,10,11,12,14,15
+[ComPort_inst2.RegHW]
+HKR,Child0000,HardwareID,,*PNP0501
+HKR,Child0000,VaryingResourceMap,1,00, 00,00,00,00, 08,00,00,00
+HKR,Child0000,ResourceMap,1,02
+HKR,Child0001,HardwareID,,*PNP0501
+HKR,Child0001,VaryingResourceMap,1,00, 08,00,00,00, 08,00,00,00
+HKR,Child0001,ResourceMap,1,02
+
+[ComPort_inst4.RegHW]
+HKR,Child0000,HardwareID,,*PNP0501
+HKR,Child0000,VaryingResourceMap,1,00, 00,00,00,00, 08,00,00,00
+HKR,Child0000,ResourceMap,1,02
+HKR,Child0001,HardwareID,,*PNP0501
+HKR,Child0001,VaryingResourceMap,1,00, 08,00,00,00, 08,00,00,00
+HKR,Child0001,ResourceMap,1,02
+HKR,Child0002,HardwareID,,*PNP0501
+HKR,Child0002,VaryingResourceMap,1,00, 10,00,00,00, 08,00,00,00
+HKR,Child0002,ResourceMap,1,02
+HKR,Child0003,HardwareID,,*PNP0501
+HKR,Child0003,VaryingResourceMap,1,00, 18,00,00,00, 08,00,00,00
+HKR,Child0003,ResourceMap,1,02
 
 [Strings]
 QEMU="QEMU"
-QEMU-PCI_SERIAL.DeviceDesc="QEMU Serial PCI Card"
-
-Serial.SVCDESC   = "Serial port driver"
-Serenum.SVCDESC = "Serenum Filter Driver"
+QEMU-PCI_SERIAL_1_PORT="1x QEMU PCI Serial Card"
+QEMU-PCI_SERIAL_2_PORT="2x QEMU PCI Serial Card"
+QEMU-PCI_SERIAL_4_PORT="4x QEMU PCI Serial Card"
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
index 2decff1..392ca84 100644
--- a/hw/arm/spitz.c
+++ b/hw/arm/spitz.c
@@ -658,14 +658,15 @@
         max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
 }
 
-static int corgi_ssp_init(SSISlave *dev)
+static int corgi_ssp_init(SSISlave *d)
 {
-    CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev);
+    DeviceState *dev = DEVICE(d);
+    CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d);
 
-    qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3);
-    s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0");
-    s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1");
-    s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2");
+    qdev_init_gpio_in(dev, corgi_ssp_gpio_cs, 3);
+    s->bus[0] = ssi_create_bus(dev, "ssi0");
+    s->bus[1] = ssi_create_bus(dev, "ssi1");
+    s->bus[2] = ssi_create_bus(dev, "ssi2");
 
     return 0;
 }
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index d1c7ad4..a5afc21 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -23,6 +23,7 @@
 #include "virtio-blk.h"
 #include "block/aio.h"
 #include "hw/virtio/virtio-bus.h"
+#include "monitor/monitor.h" /* for object_add() */
 
 enum {
     SEG_MAX = 126,                  /* maximum number of I/O segments */
@@ -44,8 +45,6 @@
     bool started;
     bool starting;
     bool stopping;
-    QEMUBH *start_bh;
-    QemuThread thread;
 
     VirtIOBlkConf *blk;
     int fd;                         /* image file descriptor */
@@ -59,12 +58,14 @@
      * (because you don't own the file descriptor or handle; you just
      * use it).
      */
+    IOThread *iothread;
+    bool internal_iothread;
     AioContext *ctx;
     EventNotifier io_notifier;      /* Linux AIO completion */
     EventNotifier host_notifier;    /* doorbell */
 
     IOQueue ioqueue;                /* Linux AIO queue (should really be per
-                                       dataplane thread) */
+                                       IOThread) */
     VirtIOBlockRequest requests[REQ_MAX]; /* pool of requests, managed by the
                                              queue */
 
@@ -342,26 +343,7 @@
     }
 }
 
-static void *data_plane_thread(void *opaque)
-{
-    VirtIOBlockDataPlane *s = opaque;
-
-    while (!s->stopping || s->num_reqs > 0) {
-        aio_poll(s->ctx, true);
-    }
-    return NULL;
-}
-
-static void start_data_plane_bh(void *opaque)
-{
-    VirtIOBlockDataPlane *s = opaque;
-
-    qemu_bh_delete(s->start_bh);
-    s->start_bh = NULL;
-    qemu_thread_create(&s->thread, "data_plane", data_plane_thread,
-                       s, QEMU_THREAD_JOINABLE);
-}
-
+/* Context: QEMU global mutex held */
 void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
                                   VirtIOBlockDataPlane **dataplane,
                                   Error **errp)
@@ -408,12 +390,33 @@
     s->fd = fd;
     s->blk = blk;
 
+    if (blk->iothread) {
+        s->internal_iothread = false;
+        s->iothread = blk->iothread;
+        object_ref(OBJECT(s->iothread));
+    } else {
+        /* Create per-device IOThread if none specified */
+        Error *local_err = NULL;
+
+        s->internal_iothread = true;
+        object_add(TYPE_IOTHREAD, vdev->name, NULL, NULL, &local_err);
+        if (error_is_set(&local_err)) {
+            error_propagate(errp, local_err);
+            g_free(s);
+            return;
+        }
+        s->iothread = iothread_find(vdev->name);
+        assert(s->iothread);
+    }
+    s->ctx = iothread_get_aio_context(s->iothread);
+
     /* Prevent block operations that conflict with data plane thread */
     bdrv_set_in_use(blk->conf.bs, 1);
 
     *dataplane = s;
 }
 
+/* Context: QEMU global mutex held */
 void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
 {
     if (!s) {
@@ -422,9 +425,14 @@
 
     virtio_blk_data_plane_stop(s);
     bdrv_set_in_use(s->blk->conf.bs, 0);
+    object_unref(OBJECT(s->iothread));
+    if (s->internal_iothread) {
+        object_unparent(OBJECT(s->iothread));
+    }
     g_free(s);
 }
 
+/* Context: QEMU global mutex held */
 void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
 {
     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
@@ -448,8 +456,6 @@
         return;
     }
 
-    s->ctx = aio_context_new();
-
     /* Set up guest notifier (irq) */
     if (k->set_guest_notifiers(qbus->parent, 1, true) != 0) {
         fprintf(stderr, "virtio-blk failed to set guest notifier, "
@@ -464,7 +470,6 @@
         exit(1);
     }
     s->host_notifier = *virtio_queue_get_host_notifier(vq);
-    aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify);
 
     /* Set up ioqueue */
     ioq_init(&s->ioqueue, s->fd, REQ_MAX);
@@ -472,7 +477,6 @@
         ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb);
     }
     s->io_notifier = *ioq_get_notifier(&s->ioqueue);
-    aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io);
 
     s->starting = false;
     s->started = true;
@@ -481,11 +485,14 @@
     /* Kick right away to begin processing requests already in vring */
     event_notifier_set(virtio_queue_get_host_notifier(vq));
 
-    /* Spawn thread in BH so it inherits iothread cpusets */
-    s->start_bh = qemu_bh_new(start_data_plane_bh, s);
-    qemu_bh_schedule(s->start_bh);
+    /* Get this show started by hooking up our callbacks */
+    aio_context_acquire(s->ctx);
+    aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify);
+    aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io);
+    aio_context_release(s->ctx);
 }
 
+/* Context: QEMU global mutex held */
 void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
 {
     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
@@ -496,27 +503,32 @@
     s->stopping = true;
     trace_virtio_blk_data_plane_stop(s);
 
-    /* Stop thread or cancel pending thread creation BH */
-    if (s->start_bh) {
-        qemu_bh_delete(s->start_bh);
-        s->start_bh = NULL;
-    } else {
-        aio_notify(s->ctx);
-        qemu_thread_join(&s->thread);
+    aio_context_acquire(s->ctx);
+
+    /* Stop notifications for new requests from guest */
+    aio_set_event_notifier(s->ctx, &s->host_notifier, NULL);
+
+    /* Complete pending requests */
+    while (s->num_reqs > 0) {
+        aio_poll(s->ctx, true);
     }
 
+    /* Stop ioq callbacks (there are no pending requests left) */
     aio_set_event_notifier(s->ctx, &s->io_notifier, NULL);
+
+    aio_context_release(s->ctx);
+
+    /* Sync vring state back to virtqueue so that non-dataplane request
+     * processing can continue when we disable the host notifier below.
+     */
+    vring_teardown(&s->vring, s->vdev, 0);
+
     ioq_cleanup(&s->ioqueue);
-
-    aio_set_event_notifier(s->ctx, &s->host_notifier, NULL);
     k->set_host_notifier(qbus->parent, 0, false);
 
-    aio_context_unref(s->ctx);
-
     /* Clean up guest notifier (irq) */
     k->set_guest_notifiers(qbus->parent, 1, false);
 
-    vring_teardown(&s->vring, s->vdev, 0);
     s->started = false;
     s->stopping = false;
 }
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 02a1544..e29a738 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -241,7 +241,8 @@
 } CMDState;
 
 typedef struct Flash {
-    SSISlave ssidev;
+    SSISlave parent_obj;
+
     uint32_t r;
 
     BlockDriverState *bdrv;
@@ -545,7 +546,7 @@
 
 static int m25p80_cs(SSISlave *ss, bool select)
 {
-    Flash *s = FROM_SSI_SLAVE(Flash, ss);
+    Flash *s = M25P80(ss);
 
     if (select) {
         s->len = 0;
@@ -561,7 +562,7 @@
 
 static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
 {
-    Flash *s = FROM_SSI_SLAVE(Flash, ss);
+    Flash *s = M25P80(ss);
     uint32_t r = 0;
 
     switch (s->state) {
@@ -610,7 +611,7 @@
 static int m25p80_init(SSISlave *ss)
 {
     DriveInfo *dinfo;
-    Flash *s = FROM_SSI_SLAVE(Flash, ss);
+    Flash *s = M25P80(ss);
     M25P80Class *mc = M25P80_GET_CLASS(s);
 
     s->pi = mc->pi;
diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c
index 2e00ad2..ffd29a8 100644
--- a/hw/char/virtio-console.c
+++ b/hw/char/virtio-console.c
@@ -15,8 +15,13 @@
 #include "trace.h"
 #include "hw/virtio/virtio-serial.h"
 
+#define TYPE_VIRTIO_CONSOLE "virtconsole"
+#define VIRTIO_CONSOLE(obj) \
+    OBJECT_CHECK(VirtConsole, (obj), TYPE_VIRTIO_CONSOLE)
+
 typedef struct VirtConsole {
-    VirtIOSerialPort port;
+    VirtIOSerialPort parent_obj;
+
     CharDriverState *chr;
     guint watch;
 } VirtConsole;
@@ -31,7 +36,7 @@
     VirtConsole *vcon = opaque;
 
     vcon->watch = 0;
-    virtio_serial_throttle_port(&vcon->port, false);
+    virtio_serial_throttle_port(VIRTIO_SERIAL_PORT(vcon), false);
     return FALSE;
 }
 
@@ -39,7 +44,7 @@
 static ssize_t flush_buf(VirtIOSerialPort *port,
                          const uint8_t *buf, ssize_t len)
 {
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+    VirtConsole *vcon = VIRTIO_CONSOLE(port);
     ssize_t ret;
 
     if (!vcon->chr) {
@@ -75,7 +80,7 @@
 /* Callback function that's called when the guest opens/closes the port */
 static void set_guest_connected(VirtIOSerialPort *port, int guest_connected)
 {
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+    VirtConsole *vcon = VIRTIO_CONSOLE(port);
 
     if (!vcon->chr) {
         return;
@@ -88,45 +93,49 @@
 {
     VirtConsole *vcon = opaque;
 
-    return virtio_serial_guest_ready(&vcon->port);
+    return virtio_serial_guest_ready(VIRTIO_SERIAL_PORT(vcon));
 }
 
 /* Send data from a char device over to the guest */
 static void chr_read(void *opaque, const uint8_t *buf, int size)
 {
     VirtConsole *vcon = opaque;
+    VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon);
 
-    trace_virtio_console_chr_read(vcon->port.id, size);
-    virtio_serial_write(&vcon->port, buf, size);
+    trace_virtio_console_chr_read(port->id, size);
+    virtio_serial_write(port, buf, size);
 }
 
 static void chr_event(void *opaque, int event)
 {
     VirtConsole *vcon = opaque;
+    VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon);
 
-    trace_virtio_console_chr_event(vcon->port.id, event);
+    trace_virtio_console_chr_event(port->id, event);
     switch (event) {
     case CHR_EVENT_OPENED:
-        virtio_serial_open(&vcon->port);
+        virtio_serial_open(port);
         break;
     case CHR_EVENT_CLOSED:
         if (vcon->watch) {
             g_source_remove(vcon->watch);
             vcon->watch = 0;
         }
-        virtio_serial_close(&vcon->port);
+        virtio_serial_close(port);
         break;
     }
 }
 
-static int virtconsole_initfn(VirtIOSerialPort *port)
+static void virtconsole_realize(DeviceState *dev, Error **errp)
 {
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
-    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+    VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
+    VirtConsole *vcon = VIRTIO_CONSOLE(dev);
+    VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
 
     if (port->id == 0 && !k->is_console) {
-        error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
-        return -1;
+        error_setg(errp, "Port number 0 on virtio-serial devices reserved "
+                   "for virtconsole devices for backward compatibility.");
+        return;
     }
 
     if (vcon->chr) {
@@ -134,19 +143,15 @@
         qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
                               vcon);
     }
-
-    return 0;
 }
 
-static int virtconsole_exitfn(VirtIOSerialPort *port)
+static void virtconsole_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+    VirtConsole *vcon = VIRTIO_CONSOLE(dev);
 
     if (vcon->watch) {
         g_source_remove(vcon->watch);
     }
-
-    return 0;
 }
 
 static Property virtconsole_properties[] = {
@@ -160,15 +165,15 @@
     VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
 
     k->is_console = true;
-    k->init = virtconsole_initfn;
-    k->exit = virtconsole_exitfn;
+    k->realize = virtconsole_realize;
+    k->unrealize = virtconsole_unrealize;
     k->have_data = flush_buf;
     k->set_guest_connected = set_guest_connected;
     dc->props = virtconsole_properties;
 }
 
 static const TypeInfo virtconsole_info = {
-    .name          = "virtconsole",
+    .name          = TYPE_VIRTIO_CONSOLE,
     .parent        = TYPE_VIRTIO_SERIAL_PORT,
     .instance_size = sizeof(VirtConsole),
     .class_init    = virtconsole_class_init,
@@ -184,8 +189,8 @@
     DeviceClass *dc = DEVICE_CLASS(klass);
     VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
 
-    k->init = virtconsole_initfn;
-    k->exit = virtconsole_exitfn;
+    k->realize = virtconsole_realize;
+    k->unrealize = virtconsole_unrealize;
     k->have_data = flush_buf;
     k->set_guest_connected = set_guest_connected;
     dc->props = virtserialport_properties;
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 226e9f9..2b647b6 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -808,13 +808,14 @@
     send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1);
 }
 
-static int virtser_port_qdev_init(DeviceState *qdev)
+static void virtser_port_device_realize(DeviceState *dev, Error **errp)
 {
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
+    VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
     VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
-    VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
-    int ret, max_nr_ports;
+    VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev));
+    int max_nr_ports;
     bool plugging_port0;
+    Error *err = NULL;
 
     port->vser = bus->vser;
     port->bh = qemu_bh_new(flush_queued_data_bh, port);
@@ -829,9 +830,9 @@
     plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0);
 
     if (find_port_by_id(port->vser, port->id)) {
-        error_report("virtio-serial-bus: A port already exists at id %u",
-                     port->id);
-        return -1;
+        error_setg(errp, "virtio-serial-bus: A port already exists at id %u",
+                   port->id);
+        return;
     }
 
     if (port->id == VIRTIO_CONSOLE_BAD_ID) {
@@ -840,22 +841,24 @@
         } else {
             port->id = find_free_port_id(port->vser);
             if (port->id == VIRTIO_CONSOLE_BAD_ID) {
-                error_report("virtio-serial-bus: Maximum port limit for this device reached");
-                return -1;
+                error_setg(errp, "virtio-serial-bus: Maximum port limit for "
+                                 "this device reached");
+                return;
             }
         }
     }
 
     max_nr_ports = tswap32(port->vser->config.max_nr_ports);
     if (port->id >= max_nr_ports) {
-        error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u",
-                     max_nr_ports - 1);
-        return -1;
+        error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, "
+                         "max. allowed: %u", max_nr_ports - 1);
+        return;
     }
 
-    ret = vsc->init(port);
-    if (ret) {
-        return ret;
+    vsc->realize(dev, &err);
+    if (err != NULL) {
+        error_propagate(errp, err);
+        return;
     }
 
     port->elem.out_num = 0;
@@ -868,14 +871,12 @@
 
     /* Send an update to the guest about this new port added */
     virtio_notify_config(VIRTIO_DEVICE(port->vser));
-
-    return ret;
 }
 
-static int virtser_port_qdev_exit(DeviceState *qdev)
+static void virtser_port_device_unrealize(DeviceState *dev, Error **errp)
 {
-    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
-    VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
+    VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
+    VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(dev);
     VirtIOSerial *vser = port->vser;
 
     qemu_bh_delete(port->bh);
@@ -883,10 +884,9 @@
 
     QTAILQ_REMOVE(&vser->ports, port, next);
 
-    if (vsc->exit) {
-        vsc->exit(port);
+    if (vsc->unrealize) {
+        vsc->unrealize(dev, errp);
     }
-    return 0;
 }
 
 static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
@@ -971,10 +971,11 @@
 static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
-    k->init = virtser_port_qdev_init;
+
     set_bit(DEVICE_CATEGORY_INPUT, k->categories);
     k->bus_type = TYPE_VIRTIO_SERIAL_BUS;
-    k->exit = virtser_port_qdev_exit;
+    k->realize = virtser_port_device_realize;
+    k->unrealize = virtser_port_device_unrealize;
     k->unplug = qdev_simple_unplug_cb;
     k->props = virtser_props;
 }
diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index 9e324be..981593c 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -8,7 +8,7 @@
 common-obj-$(CONFIG_XILINX_AXI) += stream.o
 common-obj-$(CONFIG_PTIMER) += ptimer.o
 common-obj-$(CONFIG_SOFTMMU) += sysbus.o
+common-obj-$(CONFIG_SOFTMMU) += machine.o
 common-obj-$(CONFIG_SOFTMMU) += null-machine.o
 common-obj-$(CONFIG_SOFTMMU) += loader.o
 common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
-
diff --git a/hw/core/loader.c b/hw/core/loader.c
index b323c0c..2bf6b8f 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -54,7 +54,8 @@
 
 #include <zlib.h>
 
-bool rom_file_in_ram = true;
+bool option_rom_has_mr = false;
+bool rom_file_has_mr = true;
 
 static int roms_loaded;
 
@@ -642,7 +643,8 @@
 }
 
 int rom_add_file(const char *file, const char *fw_dir,
-                 hwaddr addr, int32_t bootindex)
+                 hwaddr addr, int32_t bootindex,
+                 bool option_rom)
 {
     Rom *rom;
     int rc, fd = -1;
@@ -694,7 +696,7 @@
                  basename);
         snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
 
-        if (rom_file_in_ram) {
+        if ((!option_rom || option_rom_has_mr) && rom_file_has_mr) {
             data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
         } else {
             data = rom->data;
@@ -738,7 +740,7 @@
 
         snprintf(devpath, sizeof(devpath), "/rom@%s", fw_file_name);
 
-        if (rom_file_in_ram) {
+        if (rom_file_has_mr) {
             data = rom_set_mr(rom, OBJECT(fw_cfg), devpath);
         } else {
             data = rom->data;
@@ -773,12 +775,12 @@
 
 int rom_add_vga(const char *file)
 {
-    return rom_add_file(file, "vgaroms", 0, -1);
+    return rom_add_file(file, "vgaroms", 0, -1, true);
 }
 
 int rom_add_option(const char *file, int32_t bootindex)
 {
-    return rom_add_file(file, "genroms", 0, bootindex);
+    return rom_add_file(file, "genroms", 0, bootindex, true);
 }
 
 static void rom_reset(void *unused)
diff --git a/hw/core/machine.c b/hw/core/machine.c
new file mode 100644
index 0000000..d3ffef7
--- /dev/null
+++ b/hw/core/machine.c
@@ -0,0 +1,28 @@
+/*
+ * QEMU Machine
+ *
+ * Copyright (C) 2014 Red Hat Inc
+ *
+ * Authors:
+ *   Marcel Apfelbaum <marcel.a@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/boards.h"
+
+static const TypeInfo machine_info = {
+    .name = TYPE_MACHINE,
+    .parent = TYPE_OBJECT,
+    .abstract = true,
+    .class_size = sizeof(MachineClass),
+    .instance_size = sizeof(MachineState),
+};
+
+static void machine_register_types(void)
+{
+    type_register_static(&machine_info);
+}
+
+type_init(machine_register_types)
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 5f5957e..de83561 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -18,17 +18,19 @@
 #include "net/hub.h"
 #include "qapi/visitor.h"
 #include "sysemu/char.h"
+#include "sysemu/iothread.h"
 
 static void get_pointer(Object *obj, Visitor *v, Property *prop,
-                        const char *(*print)(void *ptr),
+                        char *(*print)(void *ptr),
                         const char *name, Error **errp)
 {
     DeviceState *dev = DEVICE(obj);
     void **ptr = qdev_get_prop_ptr(dev, prop);
     char *p;
 
-    p = (char *) (*ptr ? print(*ptr) : "");
+    p = *ptr ? print(*ptr) : g_strdup("");
     visit_type_str(v, &p, name, errp);
+    g_free(p);
 }
 
 static void set_pointer(Object *obj, Visitor *v, Property *prop,
@@ -91,9 +93,9 @@
     }
 }
 
-static const char *print_drive(void *ptr)
+static char *print_drive(void *ptr)
 {
-    return bdrv_get_device_name(ptr);
+    return g_strdup(bdrv_get_device_name(ptr));
 }
 
 static void get_drive(Object *obj, Visitor *v, void *opaque,
@@ -145,11 +147,12 @@
 }
 
 
-static const char *print_chr(void *ptr)
+static char *print_chr(void *ptr)
 {
     CharDriverState *chr = ptr;
+    const char *val = chr->label ? chr->label : "";
 
-    return chr->label ? chr->label : "";
+    return g_strdup(val);
 }
 
 static void get_chr(Object *obj, Visitor *v, void *opaque,
@@ -224,11 +227,12 @@
     return ret;
 }
 
-static const char *print_netdev(void *ptr)
+static char *print_netdev(void *ptr)
 {
     NetClientState *netdev = ptr;
+    const char *val = netdev->name ? netdev->name : "";
 
-    return netdev->name ? netdev->name : "";
+    return g_strdup(val);
 }
 
 static void get_netdev(Object *obj, Visitor *v, void *opaque,
@@ -382,6 +386,56 @@
     nd->instantiated = 1;
 }
 
+/* --- iothread --- */
+
+static char *print_iothread(void *ptr)
+{
+    return iothread_get_id(ptr);
+}
+
+static int parse_iothread(DeviceState *dev, const char *str, void **ptr)
+{
+    IOThread *iothread;
+
+    iothread = iothread_find(str);
+    if (!iothread) {
+        return -ENOENT;
+    }
+    object_ref(OBJECT(iothread));
+    *ptr = iothread;
+    return 0;
+}
+
+static void get_iothread(Object *obj, struct Visitor *v, void *opaque,
+                         const char *name, Error **errp)
+{
+    get_pointer(obj, v, opaque, print_iothread, name, errp);
+}
+
+static void set_iothread(Object *obj, struct Visitor *v, void *opaque,
+                         const char *name, Error **errp)
+{
+    set_pointer(obj, v, opaque, parse_iothread, name, errp);
+}
+
+static void release_iothread(Object *obj, const char *name, void *opaque)
+{
+    DeviceState *dev = DEVICE(obj);
+    Property *prop = opaque;
+    IOThread **ptr = qdev_get_prop_ptr(dev, prop);
+
+    if (*ptr) {
+        object_unref(OBJECT(*ptr));
+    }
+}
+
+PropertyInfo qdev_prop_iothread = {
+    .name = "iothread",
+    .get = get_iothread,
+    .set = set_iothread,
+    .release = release_iothread,
+};
+
 static int qdev_add_one_global(QemuOpts *opts, void *opaque)
 {
     GlobalProperty *g;
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 380976a..9f0a522 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -501,6 +501,45 @@
     }
 }
 
+static bool bus_get_realized(Object *obj, Error **err)
+{
+    BusState *bus = BUS(obj);
+
+    return bus->realized;
+}
+
+static void bus_set_realized(Object *obj, bool value, Error **err)
+{
+    BusState *bus = BUS(obj);
+    BusClass *bc = BUS_GET_CLASS(bus);
+    Error *local_err = NULL;
+
+    if (value && !bus->realized) {
+        if (bc->realize) {
+            bc->realize(bus, &local_err);
+
+            if (local_err != NULL) {
+                goto error;
+            }
+
+        }
+    } else if (!value && bus->realized) {
+        if (bc->unrealize) {
+            bc->unrealize(bus, &local_err);
+
+            if (local_err != NULL) {
+                goto error;
+            }
+        }
+    }
+
+    bus->realized = value;
+    return;
+
+error:
+    error_propagate(err, local_err);
+}
+
 void qbus_create_inplace(void *bus, size_t size, const char *typename,
                          DeviceState *parent, const char *name)
 {
@@ -677,6 +716,7 @@
 {
     DeviceState *dev = DEVICE(obj);
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
+    BusState *bus;
     Error *local_err = NULL;
 
     if (dev->hotplugged && !dc->hotpluggable) {
@@ -710,14 +750,30 @@
                                            dev->instance_id_alias,
                                            dev->alias_required_for_version);
         }
+        if (local_err == NULL) {
+            QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+                object_property_set_bool(OBJECT(bus), true, "realized",
+                                         &local_err);
+                if (local_err != NULL) {
+                    break;
+                }
+            }
+        }
         if (dev->hotplugged && local_err == NULL) {
             device_reset(dev);
         }
     } else if (!value && dev->realized) {
-        if (qdev_get_vmsd(dev)) {
+        QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+            object_property_set_bool(OBJECT(bus), false, "realized",
+                                     &local_err);
+            if (local_err != NULL) {
+                break;
+            }
+        }
+        if (qdev_get_vmsd(dev) && local_err == NULL) {
             vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
         }
-        if (dc->unrealize) {
+        if (dc->unrealize && local_err == NULL) {
             dc->unrealize(dev, &local_err);
         }
     }
@@ -735,7 +791,8 @@
     DeviceClass *dc = DEVICE_GET_CLASS(obj);
     DeviceState *dev = DEVICE(obj);
 
-    return dc->hotpluggable && dev->parent_bus->allow_hotplug;
+    return dc->hotpluggable && (dev->parent_bus == NULL ||
+                                dev->parent_bus->allow_hotplug);
 }
 
 static void device_initfn(Object *obj)
@@ -792,14 +849,6 @@
      * so do not propagate them to the subclasses.
      */
     klass->props = NULL;
-
-    /* by default all devices were considered as hotpluggable,
-     * so with intent to check it in generic qdev_unplug() /
-     * device_set_realized() functions make every device
-     * hotpluggable. Devices that shouldn't be hotpluggable,
-     * should override it in their class_init()
-     */
-    klass->hotpluggable = true;
 }
 
 static void device_unparent(Object *obj)
@@ -809,13 +858,13 @@
     QObject *event_data;
     bool have_realized = dev->realized;
 
+    if (dev->realized) {
+        object_property_set_bool(obj, false, "realized", NULL);
+    }
     while (dev->num_child_bus) {
         bus = QLIST_FIRST(&dev->child_bus);
         object_unparent(OBJECT(bus));
     }
-    if (dev->realized) {
-        object_property_set_bool(obj, false, "realized", NULL);
-    }
     if (dev->parent_bus) {
         bus_remove_child(dev->parent_bus, dev);
         object_unref(OBJECT(dev->parent_bus));
@@ -845,6 +894,14 @@
     class->unparent = device_unparent;
     dc->realize = device_realize;
     dc->unrealize = device_unrealize;
+
+    /* by default all devices were considered as hotpluggable,
+     * so with intent to check it in generic qdev_unplug() /
+     * device_set_realized() functions make every device
+     * hotpluggable. Devices that shouldn't be hotpluggable,
+     * should override it in their class_init()
+     */
+    dc->hotpluggable = true;
 }
 
 void device_reset(DeviceState *dev)
@@ -888,6 +945,8 @@
     object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
                              TYPE_HOTPLUG_HANDLER,
                              (Object **)&bus->hotplug_handler, NULL);
+    object_property_add_bool(obj, "realized",
+                             bus_get_realized, bus_set_realized, NULL);
 }
 
 static char *default_bus_get_fw_dev_path(DeviceState *dev)
diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c
index 5da3dc5..85252a2 100644
--- a/hw/display/ads7846.c
+++ b/hw/display/ads7846.c
@@ -133,11 +133,12 @@
     }
 };
 
-static int ads7846_init(SSISlave *dev)
+static int ads7846_init(SSISlave *d)
 {
-    ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev);
+    DeviceState *dev = DEVICE(d);
+    ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d);
 
-    qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1);
+    qdev_init_gpio_out(dev, &s->interrupt, 1);
 
     s->input[0] = ADS_TEMP0;	/* TEMP0 */
     s->input[2] = ADS_VBAT;	/* VBAT */
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
index 46c3b40..971152e 100644
--- a/hw/display/ssd0323.c
+++ b/hw/display/ssd0323.c
@@ -336,18 +336,19 @@
     .gfx_update  = ssd0323_update_display,
 };
 
-static int ssd0323_init(SSISlave *dev)
+static int ssd0323_init(SSISlave *d)
 {
-    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev);
+    DeviceState *dev = DEVICE(d);
+    ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, d);
 
     s->col_end = 63;
     s->row_end = 79;
-    s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s);
+    s->con = graphic_console_init(dev, 0, &ssd0323_ops, s);
     qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
 
-    qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
+    qdev_init_gpio_in(dev, ssd0323_cd, 1);
 
-    register_savevm(&dev->qdev, "ssd0323_oled", -1, 1,
+    register_savevm(dev, "ssd0323_oled", -1, 1,
                     ssd0323_save, ssd0323_load, s);
     return 0;
 }
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b667d31..7ecfd70 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -466,9 +466,15 @@
     g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
 }
 
-/* Get pointer within table in a safe manner */
-#define ACPI_BUILD_PTR(table, size, off, type) \
-    ((type *)(acpi_data_get_ptr(table, size, off, sizeof(type))))
+/* Set a value within table in a safe manner */
+#define ACPI_BUILD_SET_LE(table, size, off, bits, val) \
+    do { \
+        uint64_t ACPI_BUILD_SET_LE_val = cpu_to_le64(val); \
+        memcpy(acpi_data_get_ptr(table, size, off, \
+                                 (bits) / BITS_PER_BYTE), \
+               &ACPI_BUILD_SET_LE_val, \
+               (bits) / BITS_PER_BYTE); \
+    } while (0)
 
 static inline void *acpi_data_get_ptr(uint8_t *table_data, unsigned table_size,
                                       unsigned off, unsigned size)
@@ -974,22 +980,17 @@
 
 static void patch_pci_windows(PcPciInfo *pci, uint8_t *start, unsigned size)
 {
-    *ACPI_BUILD_PTR(start, size, acpi_pci32_start[0], uint32_t) =
-        cpu_to_le32(pci->w32.begin);
+    ACPI_BUILD_SET_LE(start, size, acpi_pci32_start[0], 32, pci->w32.begin);
 
-    *ACPI_BUILD_PTR(start, size, acpi_pci32_end[0], uint32_t) =
-        cpu_to_le32(pci->w32.end - 1);
+    ACPI_BUILD_SET_LE(start, size, acpi_pci32_end[0], 32, pci->w32.end - 1);
 
     if (pci->w64.end || pci->w64.begin) {
-        *ACPI_BUILD_PTR(start, size, acpi_pci64_valid[0], uint8_t) = 1;
-        *ACPI_BUILD_PTR(start, size, acpi_pci64_start[0], uint64_t) =
-            cpu_to_le64(pci->w64.begin);
-        *ACPI_BUILD_PTR(start, size, acpi_pci64_end[0], uint64_t) =
-            cpu_to_le64(pci->w64.end - 1);
-        *ACPI_BUILD_PTR(start, size, acpi_pci64_length[0], uint64_t) =
-            cpu_to_le64(pci->w64.end - pci->w64.begin);
+        ACPI_BUILD_SET_LE(start, size, acpi_pci64_valid[0], 8, 1);
+        ACPI_BUILD_SET_LE(start, size, acpi_pci64_start[0], 64, pci->w64.begin);
+        ACPI_BUILD_SET_LE(start, size, acpi_pci64_end[0], 64, pci->w64.end - 1);
+        ACPI_BUILD_SET_LE(start, size, acpi_pci64_length[0], 64, pci->w64.end - pci->w64.begin);
     } else {
-        *ACPI_BUILD_PTR(start, size, acpi_pci64_valid[0], uint8_t) = 0;
+        ACPI_BUILD_SET_LE(start, size, acpi_pci64_valid[0], 8, 0);
     }
 }
 
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index ae1699d..5e1d2d3 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -266,13 +266,14 @@
 {
     smbios_type1_defaults = false;
     gigabyte_align = false;
+    option_rom_has_mr = true;
 }
 
 static void pc_compat_1_6(QEMUMachineInitArgs *args)
 {
     pc_compat_1_7(args);
     has_pci_info = false;
-    rom_file_in_ram = false;
+    rom_file_has_mr = false;
     has_acpi_build = false;
 }
 
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index a7f6260..4b0456a 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -244,13 +244,14 @@
 {
     smbios_type1_defaults = false;
     gigabyte_align = false;
+    option_rom_has_mr = true;
 }
 
 static void pc_compat_1_6(QEMUMachineInitArgs *args)
 {
     pc_compat_1_7(args);
     has_pci_info = false;
-    rom_file_in_ram = false;
+    rom_file_has_mr = false;
     has_acpi_build = false;
 }
 
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index a5bbc24..c93dae0 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -269,7 +269,16 @@
 
 static void ics_kvm_reset(DeviceState *dev)
 {
-    ics_set_kvm_state(ICS(dev), 1);
+    ICSState *ics = ICS(dev);
+    int i;
+
+    memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs);
+    for (i = 0; i < ics->nr_irqs; i++) {
+        ics->irqs[i].priority = 0xff;
+        ics->irqs[i].saved_priority = 0xff;
+    }
+
+    ics_set_kvm_state(ics, 1);
 }
 
 static void ics_kvm_realize(DeviceState *dev, Error **errp)
diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c
index d477ecd..bba87c2 100644
--- a/hw/misc/max111x.c
+++ b/hw/misc/max111x.c
@@ -13,7 +13,8 @@
 #include "hw/ssi.h"
 
 typedef struct {
-    SSISlave ssidev;
+    SSISlave parent_obj;
+
     qemu_irq interrupt;
     uint8_t tb1, rb2, rb3;
     int cycle;
@@ -22,6 +23,14 @@
     int inputs, com;
 } MAX111xState;
 
+#define TYPE_MAX_111X "max111x"
+
+#define MAX_111X(obj) \
+    OBJECT_CHECK(MAX111xState, (obj), TYPE_MAX_111X)
+
+#define TYPE_MAX_1110 "max1110"
+#define TYPE_MAX_1111 "max1111"
+
 /* Control-byte bitfields */
 #define CB_PD0		(1 << 0)
 #define CB_PD1		(1 << 1)
@@ -92,7 +101,7 @@
 
 static uint32_t max111x_transfer(SSISlave *dev, uint32_t value)
 {
-    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev);
+    MAX111xState *s = MAX_111X(dev);
     max111x_write(s, value);
     return max111x_read(s);
 }
@@ -103,7 +112,7 @@
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields      = (VMStateField[]) {
-        VMSTATE_SSI_SLAVE(ssidev, MAX111xState),
+        VMSTATE_SSI_SLAVE(parent_obj, MAX111xState),
         VMSTATE_UINT8(tb1, MAX111xState),
         VMSTATE_UINT8(rb2, MAX111xState),
         VMSTATE_UINT8(rb3, MAX111xState),
@@ -115,11 +124,12 @@
     }
 };
 
-static int max111x_init(SSISlave *dev, int inputs)
+static int max111x_init(SSISlave *d, int inputs)
 {
-    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev);
+    DeviceState *dev = DEVICE(d);
+    MAX111xState *s = MAX_111X(dev);
 
-    qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1);
+    qdev_init_gpio_out(dev, &s->interrupt, 1);
 
     s->inputs = inputs;
     /* TODO: add a user interface for setting these */
@@ -133,7 +143,7 @@
     s->input[7] = 0x80;
     s->com = 0;
 
-    vmstate_register(&dev->qdev, -1, &vmstate_max111x, s);
+    vmstate_register(dev, -1, &vmstate_max111x, s);
     return 0;
 }
 
@@ -149,23 +159,36 @@
 
 void max111x_set_input(DeviceState *dev, int line, uint8_t value)
 {
-    MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, SSI_SLAVE_FROM_QDEV(dev));
+    MAX111xState *s = MAX_111X(dev);
     assert(line >= 0 && line < s->inputs);
     s->input[line] = value;
 }
 
+static void max111x_class_init(ObjectClass *klass, void *data)
+{
+    SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+    k->transfer = max111x_transfer;
+}
+
+static const TypeInfo max111x_info = {
+    .name          = TYPE_MAX_111X,
+    .parent        = TYPE_SSI_SLAVE,
+    .instance_size = sizeof(MAX111xState),
+    .class_init    = max111x_class_init,
+    .abstract      = true,
+};
+
 static void max1110_class_init(ObjectClass *klass, void *data)
 {
     SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
 
     k->init = max1110_init;
-    k->transfer = max111x_transfer;
 }
 
 static const TypeInfo max1110_info = {
-    .name          = "max1110",
-    .parent        = TYPE_SSI_SLAVE,
-    .instance_size = sizeof(MAX111xState),
+    .name          = TYPE_MAX_1110,
+    .parent        = TYPE_MAX_111X,
     .class_init    = max1110_class_init,
 };
 
@@ -174,18 +197,17 @@
     SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
 
     k->init = max1111_init;
-    k->transfer = max111x_transfer;
 }
 
 static const TypeInfo max1111_info = {
-    .name          = "max1111",
-    .parent        = TYPE_SSI_SLAVE,
-    .instance_size = sizeof(MAX111xState),
+    .name          = TYPE_MAX_1111,
+    .parent        = TYPE_MAX_111X,
     .class_init    = max1111_class_init,
 };
 
 static void max111x_register_types(void)
 {
+    type_register_static(&max111x_info);
     type_register_static(&max1110_info);
     type_register_static(&max1111_info);
 }
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 4bc2e01..8b8cc4e 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -272,7 +272,7 @@
     PCIDevice *pd = PCI_DEVICE(mch);
 
     memory_region_transaction_begin();
-    smram_update(&mch->smram_region, pd->config[MCH_HOST_BRDIGE_SMRAM],
+    smram_update(&mch->smram_region, pd->config[MCH_HOST_BRIDGE_SMRAM],
                     mch->smm_enabled);
     memory_region_transaction_commit();
 }
@@ -283,7 +283,7 @@
     PCIDevice *pd = PCI_DEVICE(mch);
 
     memory_region_transaction_begin();
-    smram_set_smm(&mch->smm_enabled, smm, pd->config[MCH_HOST_BRDIGE_SMRAM],
+    smram_set_smm(&mch->smm_enabled, smm, pd->config[MCH_HOST_BRIDGE_SMRAM],
                     &mch->smram_region);
     memory_region_transaction_commit();
 }
@@ -306,8 +306,8 @@
         mch_update_pciexbar(mch);
     }
 
-    if (ranges_overlap(address, len, MCH_HOST_BRDIGE_SMRAM,
-                       MCH_HOST_BRDIGE_SMRAM_SIZE)) {
+    if (ranges_overlap(address, len, MCH_HOST_BRIDGE_SMRAM,
+                       MCH_HOST_BRIDGE_SMRAM_SIZE)) {
         mch_update_smram(mch);
     }
 }
@@ -347,7 +347,7 @@
     pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR,
                  MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT);
 
-    d->config[MCH_HOST_BRDIGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
+    d->config[MCH_HOST_BRIDGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT;
 
     mch_update(mch);
 }
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 4e0701d..8f722dd 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -48,7 +48,6 @@
 static char *pcibus_get_dev_path(DeviceState *dev);
 static char *pcibus_get_fw_dev_path(DeviceState *dev);
 static void pcibus_reset(BusState *qbus);
-static void pci_bus_finalize(Object *obj);
 
 static Property pci_props[] = {
     DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
@@ -61,6 +60,34 @@
     DEFINE_PROP_END_OF_LIST()
 };
 
+static const VMStateDescription vmstate_pcibus = {
+    .name = "PCIBUS",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32_EQUAL(nirq, PCIBus),
+        VMSTATE_VARRAY_INT32(irq_count, PCIBus,
+                             nirq, 0, vmstate_info_int32,
+                             int32_t),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pci_bus_realize(BusState *qbus, Error **errp)
+{
+    PCIBus *bus = PCI_BUS(qbus);
+
+    vmstate_register(NULL, -1, &vmstate_pcibus, bus);
+}
+
+static void pci_bus_unrealize(BusState *qbus, Error **errp)
+{
+    PCIBus *bus = PCI_BUS(qbus);
+
+    vmstate_unregister(NULL, &vmstate_pcibus, bus);
+}
+
 static void pci_bus_class_init(ObjectClass *klass, void *data)
 {
     BusClass *k = BUS_CLASS(klass);
@@ -68,6 +95,8 @@
     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->realize = pci_bus_realize;
+    k->unrealize = pci_bus_unrealize;
     k->reset = pcibus_reset;
 }
 
@@ -75,7 +104,6 @@
     .name = TYPE_PCI_BUS,
     .parent = TYPE_BUS,
     .instance_size = sizeof(PCIBus),
-    .instance_finalize = pci_bus_finalize,
     .class_init = pci_bus_class_init,
 };
 
@@ -95,17 +123,6 @@
 
 static QLIST_HEAD(, PCIHostState) pci_host_bridges;
 
-static const VMStateDescription vmstate_pcibus = {
-    .name = "PCIBUS",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32_EQUAL(nirq, PCIBus),
-        VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t),
-        VMSTATE_END_OF_LIST()
-    }
-};
 static int pci_bar(PCIDevice *d, int reg)
 {
     uint8_t type;
@@ -299,8 +316,6 @@
     QLIST_INIT(&bus->child);
 
     pci_host_bus_register(bus, parent);
-
-    vmstate_register(NULL, -1, &vmstate_pcibus, bus);
 }
 
 bool pci_bus_is_express(PCIBus *bus)
@@ -369,12 +384,6 @@
     return s->parent_dev->config[PCI_SECONDARY_BUS];
 }
 
-static void pci_bus_finalize(Object *obj)
-{
-    PCIBus *bus = PCI_BUS(obj);
-    vmstate_unregister(NULL, &vmstate_pcibus, bus);
-}
-
 static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
 {
     PCIDevice *s = container_of(pv, PCIDevice, config);
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index cea9469..cbef095 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -32,6 +32,7 @@
 #include "exec/address-spaces.h"
 #include <libfdt.h>
 #include "trace.h"
+#include "qemu/error-report.h"
 
 #include "hw/pci/pci_bus.h"
 
@@ -292,7 +293,7 @@
         ret_intr_type = RTAS_TYPE_MSIX;
         break;
     default:
-        fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func);
+        error_report("rtas_ibm_change_msi(%u) is not implemented", func);
         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
         return;
     }
@@ -326,7 +327,7 @@
     /* Find a device number in the map to add or reuse the existing one */
     ndev = spapr_msicfg_find(phb, config_addr, true);
     if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) {
-        fprintf(stderr, "No free entry for a new MSI device\n");
+        error_report("No free entry for a new MSI device");
         rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
         return;
     }
@@ -335,7 +336,7 @@
     /* Check if there is an old config and MSI number has not changed */
     if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
         /* Unexpected behaviour */
-        fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev);
+        error_report("Cannot reuse MSI config for device#%d", ndev);
         rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
         return;
     }
@@ -345,7 +346,7 @@
         irq = spapr_allocate_irq_block(req_num, false,
                                        ret_intr_type == RTAS_TYPE_MSI);
         if (irq < 0) {
-            fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
+            error_report("Cannot allocate MSIs for device#%d", ndev);
             rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
             return;
         }
@@ -505,12 +506,11 @@
     return &phb->iommu_as;
 }
 
-static int spapr_phb_init(SysBusDevice *s)
+static void spapr_phb_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *dev = DEVICE(s);
+    SysBusDevice *s = SYS_BUS_DEVICE(dev);
     sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
     PCIHostState *phb = PCI_HOST_BRIDGE(s);
-    const char *busname;
     char *namebuf;
     int i;
     PCIBus *bus;
@@ -521,9 +521,9 @@
         if ((sphb->buid != -1) || (sphb->dma_liobn != -1)
             || (sphb->mem_win_addr != -1)
             || (sphb->io_win_addr != -1)) {
-            fprintf(stderr, "Either \"index\" or other parameters must"
-                    " be specified for PAPR PHB, not both\n");
-            return -1;
+            error_setg(errp, "Either \"index\" or other parameters must"
+                       " be specified for PAPR PHB, not both");
+            return;
         }
 
         sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index;
@@ -536,28 +536,28 @@
     }
 
     if (sphb->buid == -1) {
-        fprintf(stderr, "BUID not specified for PHB\n");
-        return -1;
+        error_setg(errp, "BUID not specified for PHB");
+        return;
     }
 
     if (sphb->dma_liobn == -1) {
-        fprintf(stderr, "LIOBN not specified for PHB\n");
-        return -1;
+        error_setg(errp, "LIOBN not specified for PHB");
+        return;
     }
 
     if (sphb->mem_win_addr == -1) {
-        fprintf(stderr, "Memory window address not specified for PHB\n");
-        return -1;
+        error_setg(errp, "Memory window address not specified for PHB");
+        return;
     }
 
     if (sphb->io_win_addr == -1) {
-        fprintf(stderr, "IO window address not specified for PHB\n");
-        return -1;
+        error_setg(errp, "IO window address not specified for PHB");
+        return;
     }
 
     if (find_phb(spapr, sphb->buid)) {
-        fprintf(stderr, "PCI host bridges must have unique BUIDs\n");
-        return -1;
+        error_setg(errp, "PCI host bridges must have unique BUIDs");
+        return;
     }
 
     sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
@@ -594,26 +594,8 @@
                              get_system_io(), 0, SPAPR_PCI_IO_WIN_SIZE);
     memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
                                 &sphb->iowindow);
-    /*
-     * Selecting a busname is more complex than you'd think, due to
-     * interacting constraints.  If the user has specified an id
-     * explicitly for the phb , then we want to use the qdev default
-     * of naming the bus based on the bridge device (so the user can
-     * then assign devices to it in the way they expect).  For the
-     * first / default PCI bus (index=0) we want to use just "pci"
-     * because libvirt expects there to be a bus called, simply,
-     * "pci".  Otherwise, we use the same name as in the device tree,
-     * since it's unique by construction, and makes the guest visible
-     * BUID clear.
-     */
-    if (dev->id) {
-        busname = NULL;
-    } else if (sphb->index == 0) {
-        busname = "pci";
-    } else {
-        busname = sphb->dtbusname;
-    }
-    bus = pci_register_bus(dev, busname,
+
+    bus = pci_register_bus(dev, NULL,
                            pci_spapr_set_irq, pci_spapr_map_irq, sphb,
                            &sphb->memspace, &sphb->iospace,
                            PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
@@ -624,8 +606,9 @@
     sphb->tcet = spapr_tce_new_table(dev, sphb->dma_liobn,
                                      sphb->dma_window_size);
     if (!sphb->tcet) {
-        fprintf(stderr, "Unable to create TCE table for %s\n", sphb->dtbusname);
-        return -1;
+        error_setg(errp, "Unable to create TCE table for %s",
+                   sphb->dtbusname);
+        return;
     }
     address_space_init(&sphb->iommu_as, spapr_tce_get_iommu(sphb->tcet),
                        sphb->dtbusname);
@@ -642,13 +625,12 @@
 
         irq = spapr_allocate_lsi(0);
         if (!irq) {
-            return -1;
+            error_setg(errp, "spapr_allocate_lsi failed");
+            return;
         }
 
         sphb->lsi_table[i].irq = irq;
     }
-
-    return 0;
 }
 
 static void spapr_phb_reset(DeviceState *qdev)
@@ -731,11 +713,10 @@
 static void spapr_phb_class_init(ObjectClass *klass, void *data)
 {
     PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     hc->root_bus_path = spapr_phb_root_bus_path;
-    sdc->init = spapr_phb_init;
+    dc->realize = spapr_phb_realize;
     dc->props = spapr_phb_properties;
     dc->reset = spapr_phb_reset;
     dc->vmsd = &vmstate_spapr_pci;
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 1bb56c4..3273c8a 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -238,9 +238,10 @@
     return 0;
 }
 
-static int ssi_sd_init(SSISlave *dev)
+static int ssi_sd_init(SSISlave *d)
 {
-    ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev);
+    DeviceState *dev = DEVICE(d);
+    ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d);
     DriveInfo *dinfo;
 
     s->mode = SSI_SD_CMD;
@@ -249,7 +250,7 @@
     if (s->sd == NULL) {
         return -1;
     }
-    register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
+    register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
     return 0;
 }
 
diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c
index 2c25260..017f022 100644
--- a/hw/ssi/ssi.c
+++ b/hw/ssi/ssi.c
@@ -15,7 +15,7 @@
 #include "hw/ssi.h"
 
 struct SSIBus {
-    BusState qbus;
+    BusState parent_obj;
 };
 
 #define TYPE_SSI_BUS "SSI"
@@ -60,7 +60,7 @@
 
     if (ssc->transfer_raw == ssi_transfer_raw_default &&
             ssc->cs_polarity != SSI_CS_NONE) {
-        qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1);
+        qdev_init_gpio_in(dev, ssi_cs_default, 1);
     }
 
     return ssc->init(s);
@@ -88,7 +88,7 @@
 
 DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name)
 {
-    return qdev_create(&bus->qbus, name);
+    return qdev_create(BUS(bus), name);
 }
 
 DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
@@ -108,11 +108,12 @@
 
 uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
 {
+    BusState *b = BUS(bus);
     BusChild *kid;
     SSISlaveClass *ssc;
     uint32_t r = 0;
 
-    QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
+    QTAILQ_FOREACH(kid, &b->children, sibling) {
         SSISlave *slave = SSI_SLAVE(kid->child);
         ssc = SSI_SLAVE_GET_CLASS(slave);
         r |= ssc->transfer_raw(slave, val);
@@ -156,7 +157,7 @@
     }
 
     cs_line = qdev_get_gpio_in(DEVICE(dev), 0);
-    qdev_set_parent_bus(DEVICE(dev), &arg->bus->qbus);
+    qdev_set_parent_bus(DEVICE(dev), BUS(arg->bus));
     **arg->cs_linep = cs_line;
     (*arg->cs_linep)++;
     return 0;
diff --git a/include/block/aio.h b/include/block/aio.h
index 2efdf41..a92511b 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -19,6 +19,7 @@
 #include "qemu/queue.h"
 #include "qemu/event_notifier.h"
 #include "qemu/thread.h"
+#include "qemu/rfifolock.h"
 #include "qemu/timer.h"
 
 typedef struct BlockDriverAIOCB BlockDriverAIOCB;
@@ -47,6 +48,9 @@
 struct AioContext {
     GSource source;
 
+    /* Protects all fields from multi-threaded access */
+    RFifoLock lock;
+
     /* The list of registered AIO handlers */
     QLIST_HEAD(, AioHandler) aio_handlers;
 
@@ -104,6 +108,20 @@
  */
 void aio_context_unref(AioContext *ctx);
 
+/* Take ownership of the AioContext.  If the AioContext will be shared between
+ * threads, a thread must have ownership when calling aio_poll().
+ *
+ * Note that multiple threads calling aio_poll() means timers, BHs, and
+ * callbacks may be invoked from a different thread than they were registered
+ * from.  Therefore, code must use AioContext acquire/release or use
+ * fine-grained synchronization to protect shared state if other threads will
+ * be accessing it simultaneously.
+ */
+void aio_context_acquire(AioContext *ctx);
+
+/* Relinquish ownership of the AioContext. */
+void aio_context_release(AioContext *ctx);
+
 /**
  * aio_bh_new: Allocate a new bottom half structure.
  *
diff --git a/include/block/block.h b/include/block/block.h
index 780f48b..bd34d14 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -286,15 +286,6 @@
 int bdrv_amend_options(BlockDriverState *bs_new, QEMUOptionParameter *options);
 
 /* external snapshots */
-
-typedef enum {
-    BS_IS_A_FILTER,
-    BS_FILTER_PASS_DOWN,
-    BS_AUTHORIZATION_COUNT,
-} BsAuthorization;
-
-bool bdrv_generic_is_first_non_filter(BlockDriverState *bs,
-                                      BlockDriverState *candidate);
 bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs,
                                       BlockDriverState *candidate);
 bool bdrv_is_first_non_filter(BlockDriverState *candidate);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 0bcf1c9..4fc5ea8 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -76,10 +76,10 @@
     const char *format_name;
     int instance_size;
 
-    /* this table of boolean contains authorizations for the block operations */
-    bool authorizations[BS_AUTHORIZATION_COUNT];
-    /* for snapshots complex block filter like Quorum can implement the
-     * following recursive callback instead of BS_IS_A_FILTER.
+    /* set to true if the BlockDriver is a block filter */
+    bool is_filter;
+    /* for snapshots block filter like Quorum can implement the
+     * following recursive callback.
      * It's purpose is to recurse on the filter children while calling
      * bdrv_recurse_is_first_non_filter on them.
      * For a sample implementation look in the future Quorum block filter.
diff --git a/include/hw/boards.h b/include/hw/boards.h
index c2096e6..7bd2ea7 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -4,8 +4,8 @@
 #define HW_BOARDS_H
 
 #include "sysemu/blockdev.h"
-#include "sysemu/qemumachine.h"
 #include "hw/qdev.h"
+#include "qom/object.h"
 
 typedef struct QEMUMachineInitArgs {
     const QEMUMachine *machine;
@@ -50,9 +50,59 @@
     const char *hw_version;
 };
 
+#define TYPE_MACHINE_SUFFIX "-machine"
 int qemu_register_machine(QEMUMachine *m);
-QEMUMachine *find_default_machine(void);
 
-extern QEMUMachine *current_machine;
+#define TYPE_MACHINE "machine"
+#define MACHINE(obj) \
+    OBJECT_CHECK(MachineState, (obj), TYPE_MACHINE)
+#define MACHINE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(MachineClass, (obj), TYPE_MACHINE)
+#define MACHINE_CLASS(klass) \
+    OBJECT_CLASS_CHECK(MachineClass, (klass), TYPE_MACHINE)
+
+typedef struct MachineState MachineState;
+typedef struct MachineClass MachineClass;
+
+MachineClass *find_default_machine(void);
+extern MachineState *current_machine;
+
+/**
+ * MachineClass:
+ * @qemu_machine: #QEMUMachine
+ */
+struct MachineClass {
+    /*< private >*/
+    ObjectClass parent_class;
+    /*< public >*/
+
+    QEMUMachine *qemu_machine;
+};
+
+/**
+ * MachineState:
+ */
+struct MachineState {
+    /*< private >*/
+    Object parent_obj;
+    /*< public >*/
+
+    char *accel;
+    bool kernel_irqchip;
+    int kvm_shadow_mem;
+    char *kernel;
+    char *initrd;
+    char *append;
+    char *dtb;
+    char *dumpdtb;
+    int phandle_start;
+    char *dt_compatible;
+    bool dump_guest_core;
+    bool mem_merge;
+    bool usb;
+    char *firmware;
+
+    QEMUMachineInitArgs init_args;
+};
 
 #endif
diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
index 9e4a0e4..e191435 100644
--- a/include/hw/i386/ich9.h
+++ b/include/hw/i386/ich9.h
@@ -102,7 +102,7 @@
 #define ICH9_USB_UHCI1_DEV                      29
 #define ICH9_USB_UHCI1_FUNC                     0
 
-/* D30:F0 DMI-to-PCI brdige */
+/* D30:F0 DMI-to-PCI bridge */
 #define ICH9_D2P_BRIDGE                         "ICH9 D2P BRIDGE"
 #define ICH9_D2P_BRIDGE_SAVEVM_VERSION          0
 
diff --git a/include/hw/loader.h b/include/hw/loader.h
index aaf08c3..796cbf9 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -49,10 +49,12 @@
                       hwaddr dest, int buf_size,
                       const char *source);
 
-extern bool rom_file_in_ram;
+extern bool option_rom_has_mr;
+extern bool rom_file_has_mr;
 
 int rom_add_file(const char *file, const char *fw_dir,
-                 hwaddr addr, int32_t bootindex);
+                 hwaddr addr, int32_t bootindex,
+                 bool option_rom);
 void *rom_add_blob(const char *name, const void *blob, size_t len,
                    hwaddr addr, const char *fw_file_name,
                    FWCfgReadCallback fw_callback, void *callback_opaque);
@@ -66,7 +68,7 @@
 void do_info_roms(Monitor *mon, const QDict *qdict);
 
 #define rom_add_file_fixed(_f, _a, _i)          \
-    rom_add_file(_f, NULL, _a, _i)
+    rom_add_file(_f, NULL, _a, _i, false)
 #define rom_add_blob_fixed(_f, _b, _l, _a)      \
     rom_add_blob(_f, _b, _l, _a, NULL, NULL, NULL)
 
diff --git a/include/hw/pci-host/q35.h b/include/hw/pci-host/q35.h
index d0355b7..d9ee978 100644
--- a/include/hw/pci-host/q35.h
+++ b/include/hw/pci-host/q35.h
@@ -125,8 +125,8 @@
 #define MCH_HOST_BRIDGE_PAM_RE                 ((uint8_t)0x1)
 #define MCH_HOST_BRIDGE_PAM_MASK               ((uint8_t)0x3)
 
-#define MCH_HOST_BRDIGE_SMRAM                  0x9d
-#define MCH_HOST_BRDIGE_SMRAM_SIZE             1
+#define MCH_HOST_BRIDGE_SMRAM                  0x9d
+#define MCH_HOST_BRIDGE_SMRAM_SIZE             1
 #define MCH_HOST_BRIDGE_SMRAM_DEFAULT          ((uint8_t)0x2)
 #define MCH_HOST_BRIDGE_SMRAM_D_OPEN           ((uint8_t)(1 << 6))
 #define MCH_HOST_BRIDGE_SMRAM_D_CLS            ((uint8_t)(1 << 5))
@@ -140,16 +140,16 @@
 #define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END  0x100000
 
 #define MCH_HOST_BRIDGE_ESMRAMC                0x9e
-#define MCH_HOST_BRDIGE_ESMRAMC_H_SMRAME       ((uint8_t)(1 << 6))
-#define MCH_HOST_BRDIGE_ESMRAMC_E_SMERR        ((uint8_t)(1 << 5))
-#define MCH_HOST_BRDIGE_ESMRAMC_SM_CACHE       ((uint8_t)(1 << 4))
-#define MCH_HOST_BRDIGE_ESMRAMC_SM_L1          ((uint8_t)(1 << 3))
-#define MCH_HOST_BRDIGE_ESMRAMC_SM_L2          ((uint8_t)(1 << 2))
-#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_MASK   ((uint8_t)(0x3 << 1))
-#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_1MB    ((uint8_t)(0x0 << 1))
-#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_2MB    ((uint8_t)(0x1 << 1))
-#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_8MB    ((uint8_t)(0x2 << 1))
-#define MCH_HOST_BRDIGE_ESMRAMC_T_EN           ((uint8_t)1)
+#define MCH_HOST_BRIDGE_ESMRAMC_H_SMRAME       ((uint8_t)(1 << 6))
+#define MCH_HOST_BRIDGE_ESMRAMC_E_SMERR        ((uint8_t)(1 << 5))
+#define MCH_HOST_BRIDGE_ESMRAMC_SM_CACHE       ((uint8_t)(1 << 4))
+#define MCH_HOST_BRIDGE_ESMRAMC_SM_L1          ((uint8_t)(1 << 3))
+#define MCH_HOST_BRIDGE_ESMRAMC_SM_L2          ((uint8_t)(1 << 2))
+#define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_MASK   ((uint8_t)(0x3 << 1))
+#define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_1MB    ((uint8_t)(0x0 << 1))
+#define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_2MB    ((uint8_t)(0x1 << 1))
+#define MCH_HOST_BRIDGE_ESMRAMC_TSEG_SZ_8MB    ((uint8_t)(0x2 << 1))
+#define MCH_HOST_BRIDGE_ESMRAMC_T_EN           ((uint8_t)1)
 
 /* D1:F0 PCIE* port*/
 #define MCH_PCIE_DEV                           1
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 1ed0691..dbe473c 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -36,6 +36,8 @@
 typedef void (*qdev_resetfn)(DeviceState *dev);
 typedef void (*DeviceRealize)(DeviceState *dev, Error **errp);
 typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp);
+typedef void (*BusRealize)(BusState *bus, Error **errp);
+typedef void (*BusUnrealize)(BusState *bus, Error **errp);
 
 struct VMStateDescription;
 
@@ -174,6 +176,9 @@
      */
     char *(*get_fw_dev_path)(DeviceState *dev);
     void (*reset)(BusState *bus);
+    BusRealize realize;
+    BusUnrealize unrealize;
+
     /* maximum devices allowed on the bus, 0: no limit. */
     int max_dev;
     /* number of automatically allocated bus ids (e.g. ide.0) */
@@ -199,6 +204,7 @@
     int allow_hotplug;
     HotplugHandler *hotplug_handler;
     int max_index;
+    bool realized;
     QTAILQ_HEAD(ChildrenHead, BusChild) children;
     QLIST_ENTRY(BusState) sibling;
 };
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 0c0babf..3c000ee 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -22,6 +22,7 @@
 extern PropertyInfo qdev_prop_drive;
 extern PropertyInfo qdev_prop_netdev;
 extern PropertyInfo qdev_prop_vlan;
+extern PropertyInfo qdev_prop_iothread;
 extern PropertyInfo qdev_prop_pci_devfn;
 extern PropertyInfo qdev_prop_blocksize;
 extern PropertyInfo qdev_prop_pci_host_devaddr;
@@ -142,6 +143,8 @@
     DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NICPeers)
 #define DEFINE_PROP_DRIVE(_n, _s, _f) \
     DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
+#define DEFINE_PROP_IOTHREAD(_n, _s, _f)             \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_iothread, IOThread *)
 #define DEFINE_PROP_MACADDR(_n, _s, _f)         \
     DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
 #define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
diff --git a/include/hw/ssi.h b/include/hw/ssi.h
index fdae317..6c13fb2 100644
--- a/include/hw/ssi.h
+++ b/include/hw/ssi.h
@@ -56,13 +56,12 @@
 } SSISlaveClass;
 
 struct SSISlave {
-    DeviceState qdev;
+    DeviceState parent_obj;
 
     /* Chip select state */
     bool cs;
 };
 
-#define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev)
 #define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev)
 
 extern const VMStateDescription vmstate_ssi_slave;
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
index 41885da..e4c41ff 100644
--- a/include/hw/virtio/virtio-blk.h
+++ b/include/hw/virtio/virtio-blk.h
@@ -16,6 +16,7 @@
 
 #include "hw/virtio/virtio.h"
 #include "hw/block/block.h"
+#include "sysemu/iothread.h"
 
 #define TYPE_VIRTIO_BLK "virtio-blk-device"
 #define VIRTIO_BLK(obj) \
@@ -106,6 +107,7 @@
 struct VirtIOBlkConf
 {
     BlockConf conf;
+    IOThread *iothread;
     char *serial;
     uint32_t scsi;
     uint32_t config_wce;
@@ -140,13 +142,15 @@
         DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf),                     \
         DEFINE_PROP_STRING("serial", _state, _field.serial),                  \
         DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true),    \
-        DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true)
+        DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true),                \
+        DEFINE_PROP_IOTHREAD("x-iothread", _state, _field.iothread)
 #else
 #define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field)                          \
         DEFINE_BLOCK_PROPERTIES(_state, _field.conf),                         \
         DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf),                     \
         DEFINE_PROP_STRING("serial", _state, _field.serial),                  \
-        DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true)
+        DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true),    \
+        DEFINE_PROP_IOTHREAD("x-iothread", _state, _field.iothread)
 #endif /* __linux__ */
 
 void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk);
diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h
index 1d2040b..4746312 100644
--- a/include/hw/virtio/virtio-serial.h
+++ b/include/hw/virtio/virtio-serial.h
@@ -81,15 +81,15 @@
     bool is_console;
 
     /*
-     * The per-port (or per-app) init function that's called when a
+     * The per-port (or per-app) realize function that's called when a
      * new device is found on the bus.
      */
-    int (*init)(VirtIOSerialPort *port);
+    DeviceRealize realize;
     /*
-     * Per-port exit function that's called when a port gets
+     * Per-port unrealize function that's called when a port gets
      * hot-unplugged or removed.
      */
-    int (*exit)(VirtIOSerialPort *port);
+    DeviceUnrealize unrealize;
 
     /* Callbacks for guest events */
         /* Guest opened/closed device. */
diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h
index e181821..9d549fc 100644
--- a/include/hw/xen/xen.h
+++ b/include/hw/xen/xen.h
@@ -10,7 +10,6 @@
 
 #include "hw/irq.h"
 #include "qemu-common.h"
-#include "sysemu/qemumachine.h"
 
 /* xen-machine.c */
 enum xen_mode {
diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h
index 25193c9..da75abf 100644
--- a/include/qapi/qmp/qerror.h
+++ b/include/qapi/qmp/qerror.h
@@ -159,7 +159,7 @@
     ERROR_CLASS_GENERIC_ERROR, "Invalid JSON syntax"
 
 #define QERR_KVM_MISSING_CAP \
-    ERROR_CLASS_K_V_M_MISSING_CAP, "Using KVM without %s, %s unavailable"
+    ERROR_CLASS_KVM_MISSING_CAP, "Using KVM without %s, %s unavailable"
 
 #define QERR_MIGRATION_ACTIVE \
     ERROR_CLASS_GENERIC_ERROR, "There's a migration process in progress"
diff --git a/include/qemu-io.h b/include/qemu-io.h
index 7e7c07c..5d6006f 100644
--- a/include/qemu-io.h
+++ b/include/qemu-io.h
@@ -38,6 +38,8 @@
     helpfunc_t  help;
 } cmdinfo_t;
 
+extern bool qemuio_misalign;
+
 bool qemuio_command(BlockDriverState *bs, const char *cmd);
 
 void qemuio_add_command(const cmdinfo_t *ci);
diff --git a/include/qemu/rfifolock.h b/include/qemu/rfifolock.h
new file mode 100644
index 0000000..b23ab53
--- /dev/null
+++ b/include/qemu/rfifolock.h
@@ -0,0 +1,54 @@
+/*
+ * Recursive FIFO lock
+ *
+ * Copyright Red Hat, Inc. 2013
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMU_RFIFOLOCK_H
+#define QEMU_RFIFOLOCK_H
+
+#include "qemu/thread.h"
+
+/* Recursive FIFO lock
+ *
+ * This lock provides more features than a plain mutex:
+ *
+ * 1. Fairness - enforces FIFO order.
+ * 2. Nesting - can be taken recursively.
+ * 3. Contention callback - optional, called when thread must wait.
+ *
+ * The recursive FIFO lock is heavyweight so prefer other synchronization
+ * primitives if you do not need its features.
+ */
+typedef struct {
+    QemuMutex lock;             /* protects all fields */
+
+    /* FIFO order */
+    unsigned int head;          /* active ticket number */
+    unsigned int tail;          /* waiting ticket number */
+    QemuCond cond;              /* used to wait for our ticket number */
+
+    /* Nesting */
+    QemuThread owner_thread;    /* thread that currently has ownership */
+    unsigned int nesting;       /* amount of nesting levels */
+
+    /* Contention callback */
+    void (*cb)(void *);         /* called when thread must wait, with ->lock
+                                 * held so it may not recursively lock/unlock
+                                 */
+    void *cb_opaque;
+} RFifoLock;
+
+void rfifolock_init(RFifoLock *r, void (*cb)(void *), void *opaque);
+void rfifolock_destroy(RFifoLock *r);
+void rfifolock_lock(RFifoLock *r);
+void rfifolock_unlock(RFifoLock *r);
+
+#endif /* QEMU_RFIFOLOCK_H */
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 83c9b16..bf8daac 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -30,6 +30,7 @@
 
 typedef struct MemoryMappingList MemoryMappingList;
 
+typedef struct QEMUMachine QEMUMachine;
 typedef struct NICInfo NICInfo;
 typedef struct HCIInfo HCIInfo;
 typedef struct AudioState AudioState;
diff --git a/include/qom/object.h b/include/qom/object.h
index 9c7c361..4cd7704 100644
--- a/include/qom/object.h
+++ b/include/qom/object.h
@@ -974,6 +974,14 @@
 Object *object_get_root(void);
 
 /**
+ * object_get_canonical_path_component:
+ *
+ * Returns: The final component in the object's canonical path.  The canonical
+ * path is the path within the composition tree starting from the root.
+ */
+gchar *object_get_canonical_path_component(Object *obj);
+
+/**
  * object_get_canonical_path:
  *
  * Returns: The canonical path for a object.  This is the path within the
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
new file mode 100644
index 0000000..a32214a
--- /dev/null
+++ b/include/sysemu/iothread.h
@@ -0,0 +1,30 @@
+/*
+ * Event loop thread
+ *
+ * Copyright Red Hat Inc., 2013
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef IOTHREAD_H
+#define IOTHREAD_H
+
+#include "block/aio.h"
+
+#define TYPE_IOTHREAD "iothread"
+
+typedef struct IOThread IOThread;
+
+#define IOTHREAD(obj) \
+   OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD)
+
+IOThread *iothread_find(const char *id);
+char *iothread_get_id(IOThread *iothread);
+AioContext *iothread_get_aio_context(IOThread *iothread);
+
+#endif /* IOTHREAD_H */
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index ed01998..0bee1e8 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -18,7 +18,6 @@
 #include "config-host.h"
 #include "qemu/queue.h"
 #include "qom/cpu.h"
-#include "sysemu/qemumachine.h"
 
 #ifdef CONFIG_KVM
 #include <linux/kvm.h>
diff --git a/include/sysemu/qemumachine.h b/include/sysemu/qemumachine.h
deleted file mode 100644
index 4cefd56..0000000
--- a/include/sysemu/qemumachine.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * QEMU Machine typedef
- *
- * Copyright Alexander Graf <agraf@suse.de>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#ifndef QEMUMACHINE_H
-#define QEMUMACHINE_H
-
-typedef struct QEMUMachine QEMUMachine;
-
-#endif /* !QEMUMACHINE_H */
diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
index e62281d..224131f 100644
--- a/include/sysemu/qtest.h
+++ b/include/sysemu/qtest.h
@@ -16,7 +16,6 @@
 
 #include "qemu-common.h"
 #include "qapi/error.h"
-#include "sysemu/qemumachine.h"
 
 extern bool qtest_allowed;
 
diff --git a/iothread.c b/iothread.c
new file mode 100644
index 0000000..cb5986b
--- /dev/null
+++ b/iothread.c
@@ -0,0 +1,178 @@
+/*
+ * Event loop thread
+ *
+ * Copyright Red Hat Inc., 2013
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qom/object.h"
+#include "qom/object_interfaces.h"
+#include "qemu/module.h"
+#include "qemu/thread.h"
+#include "block/aio.h"
+#include "sysemu/iothread.h"
+#include "qmp-commands.h"
+
+#define IOTHREADS_PATH "/objects"
+
+typedef ObjectClass IOThreadClass;
+struct IOThread {
+    Object parent_obj;
+
+    QemuThread thread;
+    AioContext *ctx;
+    QemuMutex init_done_lock;
+    QemuCond init_done_cond;    /* is thread initialization done? */
+    bool stopping;
+    int thread_id;
+};
+
+#define IOTHREAD_GET_CLASS(obj) \
+   OBJECT_GET_CLASS(IOThreadClass, obj, TYPE_IOTHREAD)
+#define IOTHREAD_CLASS(klass) \
+   OBJECT_CLASS_CHECK(IOThreadClass, klass, TYPE_IOTHREAD)
+
+static void *iothread_run(void *opaque)
+{
+    IOThread *iothread = opaque;
+
+    qemu_mutex_lock(&iothread->init_done_lock);
+    iothread->thread_id = qemu_get_thread_id();
+    qemu_cond_signal(&iothread->init_done_cond);
+    qemu_mutex_unlock(&iothread->init_done_lock);
+
+    while (!iothread->stopping) {
+        aio_context_acquire(iothread->ctx);
+        while (!iothread->stopping && aio_poll(iothread->ctx, true)) {
+            /* Progress was made, keep going */
+        }
+        aio_context_release(iothread->ctx);
+    }
+    return NULL;
+}
+
+static void iothread_instance_finalize(Object *obj)
+{
+    IOThread *iothread = IOTHREAD(obj);
+
+    iothread->stopping = true;
+    aio_notify(iothread->ctx);
+    qemu_thread_join(&iothread->thread);
+    qemu_cond_destroy(&iothread->init_done_cond);
+    qemu_mutex_destroy(&iothread->init_done_lock);
+    aio_context_unref(iothread->ctx);
+}
+
+static void iothread_complete(UserCreatable *obj, Error **errp)
+{
+    IOThread *iothread = IOTHREAD(obj);
+
+    iothread->stopping = false;
+    iothread->ctx = aio_context_new();
+    iothread->thread_id = -1;
+
+    qemu_mutex_init(&iothread->init_done_lock);
+    qemu_cond_init(&iothread->init_done_cond);
+
+    /* This assumes we are called from a thread with useful CPU affinity for us
+     * to inherit.
+     */
+    qemu_thread_create(&iothread->thread, "iothread", iothread_run,
+                       iothread, QEMU_THREAD_JOINABLE);
+
+    /* Wait for initialization to complete */
+    qemu_mutex_lock(&iothread->init_done_lock);
+    while (iothread->thread_id == -1) {
+        qemu_cond_wait(&iothread->init_done_cond,
+                       &iothread->init_done_lock);
+    }
+    qemu_mutex_unlock(&iothread->init_done_lock);
+}
+
+static void iothread_class_init(ObjectClass *klass, void *class_data)
+{
+    UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
+    ucc->complete = iothread_complete;
+}
+
+static const TypeInfo iothread_info = {
+    .name = TYPE_IOTHREAD,
+    .parent = TYPE_OBJECT,
+    .class_init = iothread_class_init,
+    .instance_size = sizeof(IOThread),
+    .instance_finalize = iothread_instance_finalize,
+    .interfaces = (InterfaceInfo[]) {
+        {TYPE_USER_CREATABLE},
+        {}
+    },
+};
+
+static void iothread_register_types(void)
+{
+    type_register_static(&iothread_info);
+}
+
+type_init(iothread_register_types)
+
+IOThread *iothread_find(const char *id)
+{
+    Object *container = container_get(object_get_root(), IOTHREADS_PATH);
+    Object *child;
+
+    child = object_property_get_link(container, id, NULL);
+    if (!child) {
+        return NULL;
+    }
+    return (IOThread *)object_dynamic_cast(child, TYPE_IOTHREAD);
+}
+
+char *iothread_get_id(IOThread *iothread)
+{
+    return object_get_canonical_path_component(OBJECT(iothread));
+}
+
+AioContext *iothread_get_aio_context(IOThread *iothread)
+{
+    return iothread->ctx;
+}
+
+static int query_one_iothread(Object *object, void *opaque)
+{
+    IOThreadInfoList ***prev = opaque;
+    IOThreadInfoList *elem;
+    IOThreadInfo *info;
+    IOThread *iothread;
+
+    iothread = (IOThread *)object_dynamic_cast(object, TYPE_IOTHREAD);
+    if (!iothread) {
+        return 0;
+    }
+
+    info = g_new0(IOThreadInfo, 1);
+    info->id = iothread_get_id(iothread);
+    info->thread_id = iothread->thread_id;
+
+    elem = g_new0(IOThreadInfoList, 1);
+    elem->value = info;
+    elem->next = NULL;
+
+    **prev = elem;
+    *prev = &elem->next;
+    return 0;
+}
+
+IOThreadInfoList *qmp_query_iothreads(Error **errp)
+{
+    IOThreadInfoList *head = NULL;
+    IOThreadInfoList **prev = &head;
+    Object *container = container_get(object_get_root(), IOTHREADS_PATH);
+
+    object_child_foreach(container, query_one_iothread, &prev);
+    return head;
+}
diff --git a/kvm-stub.c b/kvm-stub.c
index 4ef084e..ccdba62 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -14,7 +14,6 @@
 #include "hw/hw.h"
 #include "cpu.h"
 #include "sysemu/kvm.h"
-#include "sysemu/qemumachine.h"
 
 #ifndef CONFIG_USER_ONLY
 #include "hw/pci/msi.h"
diff --git a/net/slirp.c b/net/slirp.c
index 124e953..cce026b 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -529,7 +529,8 @@
             "state directory=%s\n"
             "log file=%s/log.smbd\n"
             "smb passwd file=%s/smbpasswd\n"
-            "security = share\n"
+            "security = user\n"
+            "map to guest = Bad User\n"
             "[qemu]\n"
             "path=%s\n"
             "read only=no\n"
@@ -549,7 +550,8 @@
     snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
              CONFIG_SMBD_COMMAND, smb_conf);
 
-    if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) {
+    if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0 ||
+        slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 445) < 0) {
         slirp_smb_cleanup(s);
         error_report("conflicting/invalid smbserver address");
         return -1;
diff --git a/net/tap.c b/net/tap.c
index 2d5099b..8847ce1 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -190,7 +190,7 @@
     TAPState *s = opaque;
     int size;
 
-    do {
+    while (qemu_can_send_packet(&s->nc)) {
         uint8_t *buf = s->buf;
 
         size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
@@ -206,8 +206,11 @@
         size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed);
         if (size == 0) {
             tap_read_poll(s, false);
+            break;
+        } else if (size < 0) {
+            break;
         }
-    } while (size > 0 && qemu_can_send_packet(&s->nc));
+    }
 }
 
 static bool tap_has_ufo(NetClientState *nc)
diff --git a/os-posix.c b/os-posix.c
index 6187301..cb2a7f7 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -44,10 +44,6 @@
 #include <sys/prctl.h>
 #endif
 
-#ifdef __FreeBSD__
-#include <sys/sysctl.h>
-#endif
-
 static struct passwd *user_pwd;
 static const char *chroot_dir;
 static int daemonize;
diff --git a/pc-bios/README b/pc-bios/README
index 2bb6357..ef6008d 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -5,7 +5,7 @@
   project (http://www.nongnu.org/vgabios/).
 
 - The PowerPC Open Hack'Ware Open Firmware Compatible BIOS is
-  available at http://perso.magic.fr/l_indien/OpenHackWare/index.htm.
+  available at http://repo.or.cz/w/openhackware.git.
 
 - OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
   firmware implementation. The goal is to implement a 100% IEEE
@@ -17,7 +17,7 @@
 - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
   implementation for certain IBM POWER hardware.  The sources are at
   https://github.com/aik/SLOF, and the image currently in qemu is
-  built from git tag qemu-slof-20131015.
+  built from git tag qemu-slof-20140304.
 
 - sgabios (the Serial Graphics Adapter option ROM) provides a means for
   legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/ohw.diff b/pc-bios/ohw.diff
deleted file mode 100644
index c6b6623..0000000
--- a/pc-bios/ohw.diff
+++ /dev/null
@@ -1,1843 +0,0 @@
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bios.h OpenHackWare-release-0.4/src/bios.h
---- OpenHackWare-release-0.4.org/src/bios.h	2005-04-06 23:20:22.000000000 +0200
-+++ OpenHackWare-release-0.4/src/bios.h	2005-07-07 01:10:20.000000000 +0200
-@@ -64,6 +64,7 @@
-     ARCH_CHRP,
-     ARCH_MAC99,
-     ARCH_POP,
-+    ARCH_HEATHROW,
- };
- 
- /* Hardware definition(s) */
-@@ -174,6 +175,7 @@
- int bd_ioctl (bloc_device_t *bd, int func, void *args);
- uint32_t bd_seclen (bloc_device_t *bd);
- void bd_close (bloc_device_t *bd);
-+void bd_reset_all(void);
- uint32_t bd_seclen (bloc_device_t *bd);
- uint32_t bd_maxbloc (bloc_device_t *bd);
- void bd_sect2CHS (bloc_device_t *bd, uint32_t secnum,
-@@ -183,12 +185,12 @@
- part_t *bd_probe (int boot_device);
- bloc_device_t *bd_get (int device);
- void bd_put (bloc_device_t *bd);
--void bd_set_boot_part (bloc_device_t *bd, part_t *partition);
-+void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum);
- part_t **_bd_parts (bloc_device_t *bd);
- 
- void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1,
-                           uint32_t io_base2, uint32_t io_base3,
--                          void *OF_private);
-+                          void *OF_private0, void *OF_private1);
- void ide_pci_pmac_register (uint32_t io_base0, uint32_t io_base1,
-                             void *OF_private);
- 
-@@ -399,17 +401,23 @@
-                               uint16_t min_grant, uint16_t max_latency);
- void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses);
- void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn,
--                             uint32_t *regions, uint32_t *sizes);
-+                             uint32_t *regions, uint32_t *sizes,
-+                             int irq_line);
- void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size,
-                             void *private_data);
-+void OF_finalize_pci_ide (void *dev, 
-+                          uint32_t io_base0, uint32_t io_base1,
-+                          uint32_t io_base2, uint32_t io_base3);
- int OF_register_bus (const unsigned char *name, uint32_t address,
-                      const unsigned char *type);
- int OF_register_serial (const unsigned char *bus, const unsigned char *name,
-                         uint32_t io_base, int irq);
- int OF_register_stdio (const unsigned char *dev_in,
-                        const unsigned char *dev_out);
--void OF_vga_register (const unsigned char *name, uint32_t address,
--                      int width, int height, int depth);
-+void OF_vga_register (const unsigned char *name, unused uint32_t address,
-+                      int width, int height, int depth,
-+                      unsigned long vga_bios_addr, 
-+                      unsigned long vga_bios_size);
- void *OF_blockdev_register (void *parent, void *private,
-                             const unsigned char *type,
-                             const unsigned char *name, int devnum,
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/bloc.c OpenHackWare-release-0.4/src/bloc.c
---- OpenHackWare-release-0.4.org/src/bloc.c	2005-04-06 23:21:00.000000000 +0200
-+++ OpenHackWare-release-0.4/src/bloc.c	2005-07-08 00:28:26.000000000 +0200
-@@ -55,6 +55,7 @@
-     /* Partitions */
-     part_t *parts, *bparts;
-     part_t *boot_part;
-+    int bpartnum;
-     /* Chain */
-     bloc_device_t *next;
- };
-@@ -66,6 +67,7 @@
- 
- static int ide_initialize (bloc_device_t *bd, int device);
- static int ide_read_sector (bloc_device_t *bd, void *buffer, int secnum);
-+static int ide_reset (bloc_device_t *bd);
- 
- static int mem_initialize (bloc_device_t *bd, int device);
- static int mem_read_sector (bloc_device_t *bd, void *buffer, int secnum);
-@@ -212,6 +214,17 @@
- {
- }
- 
-+void bd_reset_all(void)
-+{
-+    bloc_device_t *bd;
-+    for (bd = bd_list; bd != NULL; bd = bd->next) {
-+        if (bd->init == &ide_initialize) {
-+            /* reset IDE drive because Darwin wants all IDE devices to be reset */
-+            ide_reset(bd);
-+        }
-+    }
-+}
-+
- uint32_t bd_seclen (bloc_device_t *bd)
- {
-     return bd->seclen;
-@@ -223,10 +236,12 @@
- }
- 
- /* XXX: to be suppressed */
--void bd_set_boot_part (bloc_device_t *bd, part_t *partition)
-+void bd_set_boot_part (bloc_device_t *bd, part_t *partition, int partnum)
- {
-+    dprintf("%s: part %p (%p) %d\n", __func__, partition, bd->boot_part, partnum);
-     if (bd->boot_part == NULL) {
-         bd->boot_part = partition;
-+        bd->bpartnum = partnum;
-     }
- }
- 
-@@ -240,6 +255,13 @@
-     return &bd->bparts;
- }
- 
-+void bd_set_boot_device (bloc_device_t *bd)
-+{
-+#if defined (USE_OPENFIRMWARE)
-+    OF_blockdev_set_boot_device(bd->OF_private, bd->bpartnum, "\\\\ofwboot");
-+#endif
-+}
-+
- part_t *bd_probe (int boot_device)
- {
-     char devices[] = { /*'a', 'b',*/ 'c', 'd', 'e', 'f', 'm', '\0', };
-@@ -272,9 +294,7 @@
-         tmp = part_probe(bd, force_raw);
-         if (boot_device == bd->device) {
-             boot_part = tmp;
--#if defined (USE_OPENFIRMWARE)
--            OF_blockdev_set_boot_device(bd->OF_private, 2, "\\\\ofwboot");
--#endif
-+            bd_set_boot_device(bd);
-         }
-     }
- 
-@@ -717,34 +737,29 @@
- /* IDE PCI access for pc */
- static uint8_t ide_pci_port_read (bloc_device_t *bd, int port)
- {
--    eieio();
--
--    return *(uint8_t *)(bd->io_base + port);
-+    uint8_t value;
-+    value = inb(bd->io_base + port);
-+    return value;
- }
- 
- static void ide_pci_port_write (bloc_device_t *bd, int port, uint8_t value)
- {
--    *(uint8_t *)(bd->io_base + port) = value;
--    eieio();
-+    outb(bd->io_base + port, value);
- }
- 
- static uint32_t ide_pci_data_readl (bloc_device_t *bd)
- {
--    eieio();
--
--    return *((uint32_t *)bd->io_base);
-+    return inl(bd->io_base);
- }
- 
- static void ide_pci_data_writel (bloc_device_t *bd, uint32_t val)
- {
--    *(uint32_t *)(bd->io_base) = val;
--    eieio();
-+    outl(bd->io_base, val);
- }
- 
- static void ide_pci_control_write (bloc_device_t *bd, uint32_t val)
- {
--    *((uint8_t *)bd->tmp) = val;
--    eieio();
-+    outb(bd->tmp + 2, val);
- }
- 
- static ide_ops_t ide_pci_pc_ops = {
-@@ -761,7 +776,7 @@
- 
- void ide_pci_pc_register (uint32_t io_base0, uint32_t io_base1,
-                           uint32_t io_base2, uint32_t io_base3,
--                          unused void *OF_private)
-+                          void *OF_private0, void *OF_private1)
- {
-     if (ide_pci_ops == NULL) {
-         ide_pci_ops = malloc(sizeof(ide_ops_t));
-@@ -770,19 +785,19 @@
-         memcpy(ide_pci_ops, &ide_pci_pc_ops, sizeof(ide_ops_t));
-     }
-     if ((io_base0 != 0 || io_base1 != 0) &&
--        ide_pci_ops->base[0] == 0 && ide_pci_ops->base[1] == 0) {
-+        ide_pci_ops->base[0] == 0 && ide_pci_ops->base[2] == 0) {
-         ide_pci_ops->base[0] = io_base0;
--        ide_pci_ops->base[1] = io_base1;
-+        ide_pci_ops->base[2] = io_base1;
- #ifdef USE_OPENFIRMWARE
--        ide_pci_ops->OF_private[0] = OF_private;
-+        ide_pci_ops->OF_private[0] = OF_private0;
- #endif
-     }
-     if ((io_base2 != 0 || io_base3 != 0) &&
--        ide_pci_ops->base[2] == 0 && ide_pci_ops->base[3] == 0) {
--        ide_pci_ops->base[2] = io_base2;
-+        ide_pci_ops->base[1] == 0 && ide_pci_ops->base[3] == 0) {
-+        ide_pci_ops->base[1] = io_base2;
-         ide_pci_ops->base[3] = io_base3;
- #ifdef USE_OPENFIRMWARE
--        ide_pci_ops->OF_private[1] = OF_private;
-+        ide_pci_ops->OF_private[1] = OF_private1;
- #endif
-     }
- }
-@@ -935,6 +950,8 @@
- }
- 
- static void atapi_pad_req (void *buffer, int len);
-+static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer,
-+                            int maxlen);
- static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum);
- 
- static int ide_initialize (bloc_device_t *bd, int device)
-@@ -1035,9 +1052,7 @@
-         DPRINTF("INQUIRY\n");
-         len = spc_inquiry_req(&atapi_buffer, 36);
-         atapi_pad_req(&atapi_buffer, len);
--        ide_port_write(bd, 0x07, 0xA0);
--        for (i = 0; i < 3; i++)
--            ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
-+        atapi_make_req(bd, atapi_buffer, 36);
-         status = ide_port_read(bd, 0x07);
-         if (status != 0x48) {
-             ERROR("ATAPI INQUIRY : status %0x != 0x48\n", status);
-@@ -1053,9 +1068,7 @@
-         DPRINTF("READ_CAPACITY\n");
-         len = mmc_read_capacity_req(&atapi_buffer);
-         atapi_pad_req(&atapi_buffer, len);
--        ide_port_write(bd, 0x07, 0xA0);
--        for (i = 0; i < 3; i++)
--            ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
-+        atapi_make_req(bd, atapi_buffer, 8);
-         status = ide_port_read(bd, 0x07);
-         if (status != 0x48) {
-             ERROR("ATAPI READ_CAPACITY : status %0x != 0x48\n", status);
-@@ -1105,6 +1118,22 @@
-     memset(p + len, 0, 12 - len);
- }
- 
-+static void atapi_make_req (bloc_device_t *bd, uint32_t *buffer,
-+                            int maxlen)
-+{
-+    int i;
-+    /* select drive */
-+    if (bd->drv == 0)
-+        ide_port_write(bd, 0x06, 0x40);
-+    else
-+        ide_port_write(bd, 0x06, 0x50);
-+    ide_port_write(bd, 0x04, maxlen & 0xff);
-+    ide_port_write(bd, 0x05, (maxlen >> 8) & 0xff);
-+    ide_port_write(bd, 0x07, 0xA0);
-+    for (i = 0; i < 3; i++)
-+        ide_data_writel(bd, ldswap32(&buffer[i]));
-+}
-+
- static int atapi_read_sector (bloc_device_t *bd, void *buffer, int secnum)
- {
-     uint32_t atapi_buffer[4];
-@@ -1112,16 +1141,9 @@
-     uint32_t status, value;
-     int i, len;
- 
--    /* select drive */
--    if (bd->drv == 0)
--        ide_port_write(bd, 0x06, 0x40);
--    else
--        ide_port_write(bd, 0x06, 0x50);
-     len = mmc_read12_req(atapi_buffer, secnum, 1);
-     atapi_pad_req(&atapi_buffer, len);
--    ide_port_write(bd, 0x07, 0xA0);
--    for (i = 0; i < 3; i++)
--        ide_data_writel(bd, ldswap32(&atapi_buffer[i]));
-+    atapi_make_req(bd, atapi_buffer, bd->seclen);
-     status = ide_port_read(bd, 0x07);
-     if (status != 0x48) {
-         ERROR("ATAPI READ12 : status %0x != 0x48\n", status);
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/apple.c OpenHackWare-release-0.4/src/libpart/apple.c
---- OpenHackWare-release-0.4.org/src/libpart/apple.c	2005-03-31 09:23:33.000000000 +0200
-+++ OpenHackWare-release-0.4/src/libpart/apple.c	2005-07-03 16:17:41.000000000 +0200
-@@ -199,14 +199,18 @@
-         if (len == 0) {
-             /* Place holder. Skip it */
-             DPRINTF("%s placeholder part\t%d\n", __func__, i);
-+            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
-+            part_register(bd, part, name, i);
-         } else if (strncmp("Apple_Void", type, 32) == 0) {
-             /* Void partition. Skip it */
-             DPRINTF("%s Void part\t%d [%s]\n", __func__, i, type);
-+            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
-+            part_register(bd, part, name, i);
-         } else if (strncmp("Apple_Free", type, 32) == 0) {
-             /* Free space. Skip it */
-             DPRINTF("%s Free part (%d)\n", __func__, i);
-             part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
--            part_register(bd, part, name);
-+            part_register(bd, part, name, i);
-         } else if (strncmp("Apple_partition_map", type, 32) == 0 ||
-                    strncmp("Apple_Partition_Map", type, 32) == 0
- #if 0 // Is this really used or is it just a mistake ?
-@@ -226,7 +230,7 @@
-                  */
-             }
-             part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
--            part_register(bd, part, name);
-+            part_register(bd, part, name, i);
-         } else if (strncmp("Apple_Driver", type, 32) == 0 ||
-                    strncmp("Apple_Driver43", type, 32) == 0 ||
-                    strncmp("Apple_Driver43_CD", type, 32) == 0 ||
-@@ -236,8 +240,12 @@
-                    strncmp("Apple_Driver_IOKit", type, 32) == 0) {
-             /* Drivers. don't care for now */
-             DPRINTF("%s Drivers part\t%d [%s]\n", __func__, i, type);
-+            part->flags = PART_TYPE_APPLE | PART_FLAG_DRIVER;
-+            part_register(bd, part, name, i);
-         } else if (strncmp("Apple_Patches", type, 32) == 0) {
-             /* Patches: don't care for now */
-+            part->flags = PART_TYPE_APPLE | PART_FLAG_PATCH;
-+            part_register(bd, part, name, i);
-             DPRINTF("%s Patches part\t%d [%s]\n", __func__, i, type);
-         } else if (strncmp("Apple_HFS", type, 32) == 0 ||
-                    strncmp("Apple_MFS", type, 32) == 0 ||
-@@ -256,9 +264,8 @@
-             count = partmap->bloc_cnt * HFS_BLOCSIZE;
-             if (partmap->boot_size == 0 || partmap->boot_load == 0) {
-                 printf("Not a bootable partition %d %d (%p %p)\n",
--                       partmap->boot_size, partmap->boot_load,boot_part, part);
--                if (boot_part == NULL)
--                    boot_part = part;
-+                       partmap->boot_size, partmap->boot_load,
-+                       boot_part, part);
-                 part->flags = PART_TYPE_APPLE | PART_FLAG_FS;
-             } else {
-                 part->boot_start.bloc = partmap->boot_start;
-@@ -278,8 +285,8 @@
-                 boot_part = part;
-                 part->flags = PART_TYPE_APPLE | PART_FLAG_FS | PART_FLAG_BOOT;
-             }
--            printf("Partition: %d %s st %0x size %0x",
--                    i, name, partmap->start_bloc, partmap->bloc_cnt);
-+            printf("Partition: %d '%s' '%s' st %0x size %0x",
-+                    i, name, type, partmap->start_bloc, partmap->bloc_cnt);
- #ifndef DEBUG
-             printf("\n");
- #endif
-@@ -290,11 +297,13 @@
-                     part->boot_load, part->boot_entry);
-             DPRINTF("                           load %0x entry %0x %0x\n",
-                     partmap->boot_load2, partmap->boot_entry2, HFS_BLOCSIZE);
--            part_register(bd, part, name);
-+            part_register(bd, part, name, i);
-         } else {
-             memcpy(tmp, type, 32);
-             tmp[32] = '\0';
-             ERROR("Unknown partition type [%s]\n", tmp);
-+            part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
-+            part_register(bd, part, name, i);
-         }
-     }
-  error:
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/core.c OpenHackWare-release-0.4/src/libpart/core.c
---- OpenHackWare-release-0.4.org/src/libpart/core.c	2005-03-31 09:23:33.000000000 +0200
-+++ OpenHackWare-release-0.4/src/libpart/core.c	2005-07-03 16:17:41.000000000 +0200
-@@ -126,7 +126,7 @@
- }
- 
- int part_register (bloc_device_t *bd, part_t *partition,
--                   const unsigned char *name)
-+                   const unsigned char *name, int partnum)
- {
-     part_t **cur;
- 
-@@ -134,6 +134,7 @@
-     partition->bd = bd;
-     partition->next = NULL;
-     partition->name = strdup(name);
-+    partition->partnum = partnum;
-     for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next)
-         continue;
-     *cur = partition;
-@@ -141,29 +142,15 @@
-     return 0;
- }
- 
--static inline int set_boot_part (bloc_device_t *bd, int partnum)
--{
--    part_t *cur;
--
--    cur = part_get(bd, partnum);
--    if (cur == NULL)
--        return -1;
--    bd_set_boot_part(bd, cur);
--
--    return 0;
--}
--
- part_t *part_get (bloc_device_t *bd, int partnum)
- {
-     part_t **listp, *cur;
--    int i;
- 
-     listp = _bd_parts(bd);
--    cur = *listp;
--    for (i = 0; i != partnum; i++) {
--        if (cur == NULL)
-+    
-+    for (cur = *listp; cur != NULL; cur = cur->next) {
-+        if (cur->partnum == partnum)
-             break;
--        cur = cur->next;
-     }
-     
-     return cur;
-@@ -192,17 +179,20 @@
-     part_set_blocsize(bd, part, 512);
-     part->bd = bd;
-     part->flags = PART_TYPE_RAW | PART_FLAG_BOOT;
--    part_register(bd, part, "Raw");
-+    part_register(bd, part, "Raw", 0);
- 
-     return part;
- }
- 
-+bloc_device_t *part_get_bd (part_t *part)
-+{
-+    return part->bd;
-+}
-+
- part_t *part_probe (bloc_device_t *bd, int set_raw)
- {
--    part_t *part0, *boot_part, **cur;
-+    part_t *part0 = NULL, *boot_part, **cur;
- 
--    /* Register the 0 partition: raw partition containing the whole disk */
--    part0 = part_get_raw(bd);
-     /* Try to find a valid boot partition */
-     boot_part = Apple_probe_partitions(bd);
-     if (boot_part == NULL) {
-@@ -210,10 +200,13 @@
-         if (boot_part == NULL && arch == ARCH_PREP)
-             boot_part = PREP_find_partition(bd);
-         if (boot_part == NULL && set_raw != 0) {
--            boot_part = part0;
--            set_boot_part(bd, 0);
-+            dprintf("Use bloc device as raw partition\n");
-         }
-     }
-+    if (_bd_parts(bd) == NULL) {
-+        /* Register the 0 partition: raw partition containing the whole disk */
-+        part0 = part_get_raw(bd);
-+    }
-     /* Probe filesystem on each found partition */
-     for (cur = _bd_parts(bd); *cur != NULL; cur = &(*cur)->next) {
-         const unsigned char *map, *type;
-@@ -248,23 +241,28 @@
-             type = "unknown";
-             break;
-         }
--        DPRINTF("Probe filesystem on %s %s partition '%s' %s\n",
-+        dprintf("Probe filesystem on %s %s partition '%s' %s %p\n",
-                 type, map, (*cur)->name,
--                ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : "");
-+                ((*cur)->flags) & PART_FLAG_BOOT ? "(bootable)" : "", *cur);
-         if (((*cur)->flags) & PART_FLAG_FS) {
-             if (((*cur)->flags) & PART_FLAG_BOOT)
-                 (*cur)->fs = fs_probe(*cur, 1);
-             else
-                 (*cur)->fs = fs_probe(*cur, 0);
-+        } else if (((*cur)->flags) & PART_TYPE_RAW) {
-+            (*cur)->fs = fs_probe(*cur, 2);
-         } else {
-             (*cur)->fs = fs_probe(*cur, 2);
-         }
--        if (((*cur)->flags) & PART_FLAG_BOOT) {
--            bd_set_boot_part(bd, *cur);
-             fs_get_bootfile((*cur)->fs);
-+        if (((*cur)->flags) & PART_FLAG_BOOT) {
-+            dprintf("Partition is bootable (%d)\n", (*cur)->partnum);
-+            bd_set_boot_part(bd, *cur, (*cur)->partnum);
-+            if (boot_part == NULL)
-+                boot_part = *cur;
-         }
-     }
--    DPRINTF("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs,
-+    dprintf("Boot partition: %p %p %p %p\n", boot_part, boot_part->fs,
-             part_fs(boot_part), part0);
- 
-     return boot_part;
-@@ -279,6 +277,7 @@
-     part->boot_size.offset = 0;
-     part->boot_load = 0;
-     part->boot_entry = 0;
-+    part->flags |= PART_FLAG_BOOT;
- 
-     return 0;
- }
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/isofs.c OpenHackWare-release-0.4/src/libpart/isofs.c
---- OpenHackWare-release-0.4.org/src/libpart/isofs.c	2005-03-31 09:23:33.000000000 +0200
-+++ OpenHackWare-release-0.4/src/libpart/isofs.c	2005-07-03 16:17:41.000000000 +0200
-@@ -242,7 +242,7 @@
-                    part->boot_start.bloc, part->boot_size.bloc,
-                    part->boot_load, part->boot_entry);
-             part->flags = PART_TYPE_ISO9660 | PART_FLAG_BOOT;
--            part_register(bd, part, name);
-+            part_register(bd, part, name, i + 1);
-             fs_raw_set_bootfile(part, part->boot_start.bloc,
-                                 part->boot_start.offset,
-                                 part->boot_size.bloc,
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/libpart.h OpenHackWare-release-0.4/src/libpart/libpart.h
---- OpenHackWare-release-0.4.org/src/libpart/libpart.h	2005-03-31 09:23:33.000000000 +0200
-+++ OpenHackWare-release-0.4/src/libpart/libpart.h	2005-07-03 16:17:41.000000000 +0200
-@@ -30,6 +30,7 @@
- 
- struct part_t {
-     bloc_device_t *bd;
-+    int partnum;
-     uint32_t start;      /* Partition first bloc             */
-     uint32_t size;       /* Partition size, in blocs         */
-     uint32_t spb;
-@@ -54,7 +55,7 @@
- };
- 
- int part_register (bloc_device_t *bd, part_t *partition,
--                   const unsigned char *name);
-+                   const unsigned char *name, int partnum);
- void part_set_blocsize (bloc_device_t *bd, part_t *part, uint32_t blocsize);
- void part_private_set (part_t *part, void *private);
- void *part_private_get (part_t *part);
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/libpart/prep.c OpenHackWare-release-0.4/src/libpart/prep.c
---- OpenHackWare-release-0.4.org/src/libpart/prep.c	2005-03-31 09:23:33.000000000 +0200
-+++ OpenHackWare-release-0.4/src/libpart/prep.c	2005-07-03 16:17:41.000000000 +0200
-@@ -164,7 +164,7 @@
-             part->boot_load = 0;
-             part->boot_entry = boot_offset - part->bloc_size;
-             part->flags = PART_TYPE_PREP | PART_FLAG_BOOT;
--            part_register(bd, part, "PREP boot");
-+            part_register(bd, part, "PREP boot", i);
-             fs_raw_set_bootfile(part, part->boot_start.bloc,
-                                 part->boot_start.offset,
-                                 part->boot_size.bloc,
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/main.c OpenHackWare-release-0.4/src/main.c
---- OpenHackWare-release-0.4.org/src/main.c	2005-03-31 09:23:33.000000000 +0200
-+++ OpenHackWare-release-0.4/src/main.c	2005-06-07 23:48:39.000000000 +0200
-@@ -364,20 +364,24 @@
-     void *load_base, *load_entry, *last_alloc, *load_end;
-     uint32_t memsize, boot_image_size, cmdline_size, ramdisk_size;
-     uint32_t boot_base, boot_nb;
--    int boot_device;
-+    int boot_device, i;
-+    static const uint32_t isa_base_tab[3] = {
-+        0x80000000, /* PREP */
-+        0xFE000000, /* Grackle (Heathrow) */
-+        0xF2000000, /* UniNorth (Mac99)  */
-+    };
- 
-     /* Retrieve NVRAM configuration */
-- nvram_retry:
-+    for(i = 0; i < 3; i++) {
-+        isa_io_base = isa_base_tab[i];
-     nvram = NVRAM_get_config(&memsize, &boot_device,
-                              &boot_image, &boot_image_size,
-                              &cmdline, &cmdline_size,
-                              &ramdisk, &ramdisk_size);
--    if (nvram == NULL) {
--        /* Retry with another isa_io_base */
--        if (isa_io_base == 0x80000000) {
--            isa_io_base = 0xF2000000;
--            goto nvram_retry;
-+        if (nvram)
-+            break;
-         }
-+    if (i == 3) {
-         ERROR("Unable to load configuration from NVRAM. Aborting...\n");
-         return -1;
-     }
-@@ -402,7 +406,7 @@
-         cpu_name = CPU_get_name(pvr);
-         OF_register_cpu(cpu_name, 0, pvr,
-                         200 * 1000 * 1000, 200 * 1000 * 1000,
--                        100 * 1000 * 1000, 10 * 1000 * 1000,
-+                        100 * 1000 * 1000, 100 * 1000 * 1000,
-                         0x0092);
-     }
-     OF_register_memory(memsize, 512 * 1024 /* TOFIX */);
-@@ -433,9 +437,12 @@
-     vga_puts(copyright);
-     vga_puts("\n");
- 
-+#if 0
-     /* QEMU is quite incoherent: d is cdrom, not second drive */
-+    /* XXX: should probe CD-ROM position */
-     if (boot_device == 'd')
-         boot_device = 'e';
-+#endif
-     /* Open boot device */
-     boot_part = bd_probe(boot_device);
-     if (boot_device == 'm') {
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/nvram.c OpenHackWare-release-0.4/src/nvram.c
---- OpenHackWare-release-0.4.org/src/nvram.c	2005-03-31 09:23:33.000000000 +0200
-+++ OpenHackWare-release-0.4/src/nvram.c	2005-06-04 23:44:03.000000000 +0200
-@@ -334,6 +334,7 @@
-         ret = NVRAM_chrp_format(nvram);
-         break;
-     case ARCH_MAC99:
-+    case ARCH_HEATHROW: /* XXX: may be incorrect */
-         ret = NVRAM_mac99_format(nvram);
-         break;
-     case ARCH_POP:
-@@ -409,13 +410,12 @@
-         arch = ARCH_MAC99;
-     } else if (strcmp(sign, "POP") == 0) {
-         arch = ARCH_POP;
-+    } else if (strcmp(sign, "HEATHROW") == 0) {
-+        arch = ARCH_HEATHROW;
-     } else {
-         ERROR("Unknown PPC architecture: '%s'\n", sign);
-         return NULL;
-     }
--    /* HACK */
--    if (arch == ARCH_CHRP)
--        arch = ARCH_MAC99;
-     lword = NVRAM_get_lword(nvram, 0x30);
-     *RAM_size = lword;
-     byte = NVRAM_get_byte(nvram, 0x34);
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/of.c OpenHackWare-release-0.4/src/of.c
---- OpenHackWare-release-0.4.org/src/of.c	2005-04-06 23:17:26.000000000 +0200
-+++ OpenHackWare-release-0.4/src/of.c	2005-07-07 23:30:08.000000000 +0200
-@@ -489,7 +489,7 @@
-         ERROR("%s can't alloc new node '%s' name\n", __func__, name);
-         return NULL;
-     }
--    new->prop_address = OF_prop_int_new(env, new, "address", address);
-+    new->prop_address = OF_prop_int_new(env, new, "unit-address", address);
-     if (new->prop_address == NULL) {
-         free(new->prop_name->value);
-         free(new->prop_name);
-@@ -1017,6 +1017,33 @@
-                            string, strlen(string) + 1);
- }
- 
-+/* convert '\1' char to '\0' */
-+static OF_prop_t *OF_prop_string_new1 (OF_env_t *env, OF_node_t *node,
-+                                       const unsigned char *name,
-+                                       const unsigned char *string)
-+{
-+    int len, i;
-+    OF_prop_t *ret;
-+    unsigned char *str;
-+
-+    if (strchr(string, '\1') == NULL) {
-+        return OF_prop_string_new(env, node, name, string);
-+    } else {
-+        len = strlen(string) + 1;
-+        str = malloc(len);
-+        if (!str)
-+            return NULL;
-+        memcpy(str, string, len);
-+        for(i = 0; i < len; i++)
-+            if (str[i] == '\1')
-+                str[i] = '\0';
-+        ret = OF_property_new(env, node, name,
-+                              str, len);
-+        free(str);
-+        return ret;
-+    }
-+}
-+
- __attribute__ (( section (".OpenFirmware") ))
- static OF_prop_t *OF_prop_int_new (OF_env_t *env, OF_node_t *node,
-                                    const unsigned char *name, uint32_t value)
-@@ -1421,15 +1448,12 @@
- __attribute__ (( section (".OpenFirmware") ))
- int OF_init (void)
- {
--    const unsigned char compat_str[] =
- #if 0
-         "PowerMac3,1\0MacRISC\0Power Macintosh\0";
-         "PowerMac1,2\0MacRISC\0Power Macintosh\0";
-         "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0";
-         "AAPL,PowerMac3,0\0MacRISC\0Power Macintosh\0";
-         "AAPL,Gossamer\0MacRISC\0Power Macintosh\0";
--#else
--        "AAPL,PowerMac G3\0PowerMac G3\0MacRISC\0Power Macintosh\0";
- #endif
-     OF_env_t *OF_env;
-     OF_node_t *als, *opt, *chs, *pks;
-@@ -1455,15 +1479,21 @@
-         return -1;
-     }
-     OF_prop_string_new(OF_env, OF_node_root, "device_type", "bootrom");
--#if 0
--    OF_prop_string_new(OF_env, OF_node_root,
--                       "model", "PPC Open Hack'Ware " BIOS_VERSION);
--#else
-+    if (arch == ARCH_HEATHROW) {
-+        const unsigned char compat_str[] =
-+            "PowerMac1,1\0MacRISC\0Power Macintosh";
-+        OF_property_new(OF_env, OF_node_root, "compatible",
-+                        compat_str, sizeof(compat_str));
-     OF_prop_string_new(OF_env, OF_node_root,
--                       "model", compat_str);
--#endif
-+                           "model", "Power Macintosh");
-+    } else {
-+        const unsigned char compat_str[] =
-+            "PowerMac3,1\0MacRISC\0Power Macintosh";
-     OF_property_new(OF_env, OF_node_root, "compatible",
-                     compat_str, sizeof(compat_str));
-+        OF_prop_string_new(OF_env, OF_node_root,
-+                           "model", "PowerMac3,1");
-+    }
- #if 0
-     OF_prop_string_new(OF_env, OF_node_root, "copyright", copyright);
- #else
-@@ -1561,14 +1591,15 @@
-         range.size = 0x00800000;
-         OF_property_new(OF_env, rom, "ranges", &range, sizeof(OF_range_t));
-         OF_prop_int_new(OF_env, rom, "#address-cells", 1);
-+
-         /* "/rom/boot-rom@fff00000" node */
--        brom = OF_node_new(OF_env, OF_node_root, "boot-rom", 0xfff00000);
-+        brom = OF_node_new(OF_env, rom, "boot-rom", 0xfff00000);
-         if (brom == NULL) {
-             ERROR("Cannot create 'boot-rom'\n");
-             return -1;
-         }
-         regs.address = 0xFFF00000;
--        regs.size = 0x00010000;
-+        regs.size = 0x00100000;
-         OF_property_new(OF_env, brom, "reg", &regs, sizeof(OF_regprop_t));
-         OF_prop_string_new(OF_env, brom, "write-characteristic", "flash");
-         OF_prop_string_new(OF_env, brom, "BootROM-build-date",
-@@ -1577,7 +1608,7 @@
-         OF_prop_string_new(OF_env, brom, "copyright", copyright);
-         OF_prop_string_new(OF_env, brom, "model", BIOS_str);
-         OF_prop_int_new(OF_env, brom, "result", 0);
--#if 0
-+#if 1
-         {
-             /* Hack taken 'as-is' from PearPC */
-             unsigned char info[] = {
-@@ -1596,7 +1627,9 @@
-         OF_node_put(OF_env, brom);
-         OF_node_put(OF_env, rom);
-     }
-+#if 0
-     /* From here, hardcoded hacks to get a Mac-like machine */
-+    /* XXX: Core99 does not seem to like this NVRAM tree */
-     /* "/nvram@fff04000" node */
-     {
-         OF_regprop_t regs;
-@@ -1617,6 +1650,7 @@
-         OF_prop_int_new(OF_env, chs, "nvram", OF_pack_handle(OF_env, nvr));
-         OF_node_put(OF_env, nvr);
-     }
-+#endif
-     /* "/pseudo-hid" : hid emulation as Apple does */
-     {
-         OF_node_t *hid;
-@@ -1663,7 +1697,27 @@
-         }
-         OF_node_put(OF_env, hid);
-     }
-+    if (arch == ARCH_MAC99) {
-+        OF_node_t *unin;
-+        OF_regprop_t regs;
- 
-+        unin = OF_node_new(OF_env, OF_node_root,
-+                           "uni-n", 0xf8000000);
-+        if (unin == NULL) {
-+            ERROR("Cannot create 'uni-n'\n");
-+            return -1;
-+        }
-+        OF_prop_string_new(OF_env, unin, "device-type", "memory-controller");
-+        OF_prop_string_new(OF_env, unin, "model", "AAPL,UniNorth");
-+        OF_prop_string_new(OF_env, unin, "compatible", "uni-north");
-+        regs.address = 0xf8000000;
-+        regs.size = 0x01000000;
-+        OF_property_new(OF_env, unin, "reg", &regs, sizeof(regs));
-+        OF_prop_int_new(OF_env, unin, "#address-cells", 1);
-+        OF_prop_int_new(OF_env, unin, "#size-cells", 1);
-+        OF_prop_int_new(OF_env, unin, "device-rev", 3);
-+        OF_node_put(OF_env, unin);
-+    }
-     
- #if 1 /* This is mandatory for claim to work
-        * but I don't know where it should really be (in cpu ?)
-@@ -1693,7 +1747,9 @@
- 
-     /* "/options/boot-args" node */
-     {
--        const unsigned char *args = "-v rootdev cdrom";
-+        //        const unsigned char *args = "-v rootdev cdrom";
-+        //const unsigned char *args = "-v io=0xffffffff";
-+        const unsigned char *args = "-v";
-         /* Ask MacOS X to print debug messages */
-         //        OF_prop_string_new(OF_env, chs, "machargs", args);
-         //        OF_prop_string_new(OF_env, opt, "boot-command", args);
-@@ -2013,17 +2069,17 @@
-     OF_prop_int_new(OF_env, node, "min-grant", min_grant);
-     OF_prop_int_new(OF_env, node, "max-latency", max_latency);
-     if (dev->type != NULL)
--        OF_prop_string_new(OF_env, node, "device_type", dev->type);
-+        OF_prop_string_new1(OF_env, node, "device_type", dev->type);
-     if (dev->compat != NULL)
--        OF_prop_string_new(OF_env, node, "compatible", dev->compat);
-+        OF_prop_string_new1(OF_env, node, "compatible", dev->compat);
-     if (dev->model != NULL)
--        OF_prop_string_new(OF_env, node, "model", dev->model);
-+        OF_prop_string_new1(OF_env, node, "model", dev->model);
-     if (dev->acells != 0)
-         OF_prop_int_new(OF_env, node, "#address-cells", dev->acells);
-     if (dev->scells != 0)
--        OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->acells);
-+        OF_prop_int_new(OF_env, node, "#size-cells", dev->scells);
-     if (dev->icells != 0)
--        OF_prop_int_new(OF_env, node, "#size-cells", dev->acells);
-+        OF_prop_int_new(OF_env, node, "#interrupt-cells", dev->icells);
-     dprintf("Done %p %p\n", parent, node);
-     
-     return node;
-@@ -2040,8 +2096,9 @@
-     OF_env_t *OF_env;
-     pci_range_t ranges[3];
-     OF_regprop_t regs[1];
--    OF_node_t *pci_host;
-+    OF_node_t *pci_host, *als;
-     int nranges;
-+    unsigned char buffer[OF_NAMELEN_MAX];
- 
-     OF_env = OF_env_main;
-     dprintf("register PCI host '%s' '%s' '%s' '%s'\n",
-@@ -2052,6 +2109,17 @@
-         ERROR("Cannot create pci host\n");
-         return NULL;
-     }
-+    
-+    als = OF_node_get(OF_env, "aliases");
-+    if (als == NULL) {
-+        ERROR("Cannot get 'aliases'\n");
-+        return NULL;
-+    }
-+    sprintf(buffer, "/%s", dev->name);
-+    OF_prop_string_set(OF_env, als, "pci", buffer);
-+    OF_node_put(OF_env, als);
-+    
-+
-     regs[0].address = cfg_base;
-     regs[0].size = cfg_len;
-     OF_property_new(OF_env, pci_host, "reg", regs, sizeof(OF_regprop_t));
-@@ -2136,6 +2204,11 @@
-     return pci_dev;
- }
- 
-+/* XXX: suppress that, used for interrupt map init */
-+OF_node_t *pci_host_node;
-+uint32_t pci_host_interrupt_map[7 * 32];
-+int pci_host_interrupt_map_len = 0;
-+
- void OF_finalize_pci_host (void *dev, int first_bus, int nb_busses)
- {
-     OF_env_t *OF_env;
-@@ -2145,10 +2218,12 @@
-     regs[0].address = first_bus;
-     regs[0].size = nb_busses;
-     OF_property_new(OF_env, dev, "bus-range", regs, sizeof(OF_regprop_t));
-+    pci_host_node = dev;
- }
- 
- void OF_finalize_pci_device (void *dev, uint8_t bus, uint8_t devfn,
--                             uint32_t *regions, uint32_t *sizes)
-+                             uint32_t *regions, uint32_t *sizes,
-+                             int irq_line)
- {
-     OF_env_t *OF_env;
-     pci_reg_prop_t pregs[6], rregs[6];
-@@ -2156,6 +2231,7 @@
-     int i, j, k;
- 
-     OF_env = OF_env_main;
-+    /* XXX: only useful for VGA card in fact */
-     if (regions[0] != 0x00000000)
-         OF_prop_int_set(OF_env, dev, "address", regions[0] & ~0x0000000F);
-     for (i = 0, j = 0, k = 0; i < 6; i++) {
-@@ -2222,7 +2298,22 @@
-     } else {
-         OF_property_new(OF_env, dev, "assigned-addresses", NULL, 0);
-     }
--#if 0
-+    if (irq_line >= 0) {
-+        int i;
-+        OF_prop_int_new(OF_env, dev, "interrupts", 1);
-+        i = pci_host_interrupt_map_len;
-+        pci_host_interrupt_map[i++] = (devfn << 8) & 0xf800;
-+        pci_host_interrupt_map[i++] = 0;
-+        pci_host_interrupt_map[i++] = 0;
-+        pci_host_interrupt_map[i++] = 0;
-+        pci_host_interrupt_map[i++] = 0; /* pic handle will be patched later */
-+        pci_host_interrupt_map[i++] = irq_line;
-+        if (arch != ARCH_HEATHROW) {
-+            pci_host_interrupt_map[i++] = 1;
-+        }
-+        pci_host_interrupt_map_len = i;
-+    }
-+#if 1
-     {
-         OF_prop_t *prop_name = ((OF_node_t *)dev)->prop_name;
- 
-@@ -2390,6 +2481,54 @@
-     return 0;
- }
- 
-+static void keylargo_ata(OF_node_t *mio, uint32_t base_address,
-+                         uint32_t base, int irq1, int irq2, 
-+                         uint16_t pic_phandle)
-+{
-+    OF_env_t *OF_env = OF_env_main;
-+    OF_node_t *ata;
-+    OF_regprop_t regs[2];
-+
-+    ata = OF_node_new(OF_env, mio, "ata-4", base);
-+    if (ata == NULL) {
-+        ERROR("Cannot create 'ata-4'\n");
-+        return;
-+    }
-+    OF_prop_string_new(OF_env, ata, "device_type", "ata");
-+#if 1
-+    OF_prop_string_new(OF_env, ata, "compatible", "key2largo-ata");
-+    OF_prop_string_new(OF_env, ata, "model", "ata-4");
-+    OF_prop_string_new(OF_env, ata, "cable-type", "80-conductor");
-+#else
-+    OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
-+    OF_prop_string_new(OF_env, ata, "model", "ata-4");
-+#endif
-+    OF_prop_int_new(OF_env, ata, "#address-cells", 1);
-+    OF_prop_int_new(OF_env, ata, "#size-cells", 0);
-+    regs[0].address = base;
-+    regs[0].size = 0x00001000;
-+#if 0 // HACK: Don't set up DMA registers
-+    regs[1].address = 0x00008A00;
-+    regs[1].size = 0x00001000;
-+    OF_property_new(OF_env, ata, "reg",
-+                    regs, 2 * sizeof(OF_regprop_t));
-+#else
-+    OF_property_new(OF_env, ata, "reg",
-+                    regs, sizeof(OF_regprop_t));
-+#endif
-+    OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle);
-+    regs[0].address = irq1;
-+    regs[0].size = 0x00000001;
-+    regs[1].address = irq2;
-+    regs[1].size = 0x00000000;
-+    OF_property_new(OF_env, ata, "interrupts",
-+                    regs, 2 * sizeof(OF_regprop_t));
-+    if (base == 0x1f000)
-+        ide_pci_pmac_register(base_address + base, 0x00000000, ata);
-+    else
-+        ide_pci_pmac_register(0x00000000, base_address + base, ata);
-+}
-+
- void OF_finalize_pci_macio (void *dev, uint32_t base_address, uint32_t size,
-                             void *private_data)
- {
-@@ -2398,6 +2537,8 @@
-     pci_reg_prop_t pregs[2];
-     OF_node_t *mio, *chs, *als;
-     uint16_t pic_phandle;
-+    int rec_len;
-+    OF_prop_t *mio_reg;
- 
-     OF_DPRINTF("mac-io: %p\n", dev);
-     OF_env = OF_env_main;
-@@ -2416,10 +2557,14 @@
-     mio = dev;
-     mio->private_data = private_data;
-     pregs[0].addr.hi = 0x00000000;
--    pregs[0].addr.mid = 0x82013810;
-+    pregs[0].addr.mid = 0x00000000;
-     pregs[0].addr.lo = 0x00000000;
-     pregs[0].size_hi = base_address;
-     pregs[0].size_lo = size;
-+    mio_reg = OF_property_get(OF_env, mio, "reg");
-+    if (mio_reg && mio_reg->vlen >= 5 * 4) {
-+        pregs[0].addr.mid = ((pci_reg_prop_t *)mio_reg->value)->addr.hi;
-+    }
-     OF_property_new(OF_env, mio, "ranges",
-                     &pregs, sizeof(pci_reg_prop_t));
- #if 0
-@@ -2431,8 +2576,32 @@
-     OF_property_new(OF_env, mio, "assigned-addresses",
-                     &pregs, sizeof(pci_reg_prop_t));
- #endif
-+
-+    if (arch == ARCH_HEATHROW) {
-+        /* Heathrow PIC */
-+        OF_regprop_t regs;
-+        OF_node_t *mpic;
-+        const char compat_str[] = "heathrow\0mac-risc";
-+
-+        mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x10);
-+        if (mpic == NULL) {
-+            ERROR("Cannot create 'mpic'\n");
-+            goto out;
-+        }
-+        OF_prop_string_new(OF_env, mpic, "device_type", "interrupt-controller");
-+        OF_property_new(OF_env, mpic, "compatible", compat_str, sizeof(compat_str));
-+        OF_prop_int_new(OF_env, mpic, "#interrupt-cells", 1);
-+        regs.address = 0x10;
-+        regs.size = 0x20;
-+        OF_property_new(OF_env, mpic, "reg",
-+                        &regs, sizeof(regs));
-+        OF_property_new(OF_env, mpic, "interrupt-controller", NULL, 0);
-+        pic_phandle = OF_pack_handle(OF_env, mpic);
-+        OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle);
-+        OF_node_put(OF_env, mpic);
-+        rec_len = 6;
-+    } else {
-     /* OpenPIC */
--    {
-         OF_regprop_t regs[4];
-         OF_node_t *mpic;
-         mpic = OF_node_new(OF_env, mio, "interrupt-controller", 0x40000);
-@@ -2455,8 +2624,37 @@
-         pic_phandle = OF_pack_handle(OF_env, mpic);
-         OF_prop_int_new(OF_env, chs, "interrupt-controller", pic_phandle);
-         OF_node_put(OF_env, mpic);
-+        rec_len = 7;
-     }
--#if 1
-+
-+    /* patch pci host table */
-+    /* XXX: do it after the PCI init */
-+    {
-+        int i;
-+        uint32_t tab[4];
-+
-+        for(i = 0; i < pci_host_interrupt_map_len; i += rec_len)
-+            pci_host_interrupt_map[i + 4] = pic_phandle;
-+#if 0
-+        dprintf("interrupt-map:\n");
-+        for(i = 0; i < pci_host_interrupt_map_len; i++) {
-+            dprintf(" %08x", pci_host_interrupt_map[i]);
-+            if ((i % rec_len) == (rec_len - 1))
-+                dprintf("\n");
-+        }
-+        dprintf("\n");
-+#endif
-+        OF_property_new(OF_env, pci_host_node, "interrupt-map", 
-+                        pci_host_interrupt_map, 
-+                        pci_host_interrupt_map_len * sizeof(uint32_t));
-+        tab[0] = 0xf800;
-+        tab[1] = 0;
-+        tab[2] = 0;
-+        tab[3] = 0;
-+        OF_property_new(OF_env, pci_host_node, "interrupt-map-mask", 
-+                        tab, 4 * sizeof(uint32_t));
-+    }
-+#if 0
-     /* escc is useful to get MacOS X debug messages */
-     {
-         OF_regprop_t regs[8];
-@@ -2645,85 +2843,12 @@
-         OF_node_put(OF_env, scc);
-     }
- #endif
--    /* IDE controller */
--    {
--        OF_node_t *ata;
--        OF_regprop_t regs[2];
--        ata = OF_node_new(OF_env, mio, "ata-4", 0x1f000);
--        if (ata == NULL) {
--            ERROR("Cannot create 'ata-4'\n");
--            goto out;
--        }
--        OF_prop_string_new(OF_env, ata, "device_type", "ata");
--#if 1
--        OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata");
--        OF_prop_string_new(OF_env, ata, "model", "ata-4");
--#else
--        OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
--        OF_prop_string_new(OF_env, ata, "model", "ata-4");
--#endif
--        OF_prop_int_new(OF_env, ata, "#address-cells", 1);
--        OF_prop_int_new(OF_env, ata, "#size-cells", 0);
--        regs[0].address = 0x0001F000;
--        regs[0].size = 0x00001000;
--#if 0 // HACK: Don't set up DMA registers
--        regs[1].address = 0x00008A00;
--        regs[1].size = 0x00001000;
--        OF_property_new(OF_env, ata, "reg",
--                        regs, 2 * sizeof(OF_regprop_t));
--#else
--        OF_property_new(OF_env, ata, "reg",
--                        regs, sizeof(OF_regprop_t));
--#endif
--        OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle);
--        regs[0].address = 0x00000013;
--        regs[0].size = 0x00000001;
--        regs[1].address = 0x0000000B;
--        regs[1].size = 0x00000000;
--        OF_property_new(OF_env, ata, "interrupts",
--                        regs, 2 * sizeof(OF_regprop_t));
--        ide_pci_pmac_register(base_address + 0x1f000, 0x00000000, ata);
--
--    }
--    {
--        OF_node_t *ata;
--        OF_regprop_t regs[2];
--        ata = OF_node_new(OF_env, mio, "ata-4", 0x20000);
--        if (ata == NULL) {
--            ERROR("Cannot create 'ata-4'\n");
--            goto out;
--        }
--        OF_prop_string_new(OF_env, ata, "device_type", "ata");
--#if 1
--        OF_prop_string_new(OF_env, ata, "compatible", "keylargo-ata");
--        OF_prop_string_new(OF_env, ata, "model", "ata-4");
--#else
--        OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
--        OF_prop_string_new(OF_env, ata, "model", "ata-4");
--#endif
--        OF_prop_int_new(OF_env, ata, "#address-cells", 1);
--        OF_prop_int_new(OF_env, ata, "#size-cells", 0);
--        regs[0].address = 0x00020000;
--        regs[0].size = 0x00001000;
--#if 0 // HACK: Don't set up DMA registers
--        regs[1].address = 0x00008A00;
--        regs[1].size = 0x00001000;
--        OF_property_new(OF_env, ata, "reg",
--                        regs, 2 * sizeof(OF_regprop_t));
--#else
--        OF_property_new(OF_env, ata, "reg",
--                        regs, sizeof(OF_regprop_t));
--#endif
--        OF_prop_int_new(OF_env, ata, "interrupt-parent", pic_phandle);
--        regs[0].address = 0x00000014;
--        regs[0].size = 0x00000001;
--        regs[1].address = 0x0000000B;
--        regs[1].size = 0x00000000;
--        OF_property_new(OF_env, ata, "interrupts",
--                        regs, 2 * sizeof(OF_regprop_t));
--        ide_pci_pmac_register(0x00000000, base_address + 0x20000, ata);
--
-+    /* Keylargo IDE controller: need some work (DMA problem ?) */
-+    if (arch == ARCH_MAC99) {
-+        keylargo_ata(mio, base_address, 0x1f000, 0x13, 0xb, pic_phandle);
-+        keylargo_ata(mio, base_address, 0x20000, 0x14, 0xb, pic_phandle);
-     }
-+#if 0
-     /* Timer */
-     {
-         OF_node_t *tmr;
-@@ -2746,10 +2871,11 @@
-                         regs, sizeof(OF_regprop_t));
-         OF_node_put(OF_env, tmr);
-     }
-+#endif
-     /* VIA-PMU */
-     {
-         /* Controls adb, RTC and power-mgt (forget it !) */
--        OF_node_t *via, *adb, *rtc;
-+        OF_node_t *via, *adb;
-         OF_regprop_t regs[1];
- #if 0 // THIS IS A HACK AND IS COMPLETELY ABSURD !
-       // (but needed has Qemu doesn't emulate via-pmu).
-@@ -2773,14 +2899,21 @@
-         regs[0].size = 0x00002000;
-         OF_property_new(OF_env, via, "reg", regs, sizeof(OF_regprop_t));
-         OF_prop_int_new(OF_env, via, "interrupt-parent", pic_phandle);
-+        if (arch == ARCH_HEATHROW) {
-+            OF_prop_int_new(OF_env, via, "interrupts", 0x12);
-+        } else {
-         regs[0].address = 0x00000019;
-         regs[0].size = 0x00000001;
-         OF_property_new(OF_env, via, "interrupts",
-                         regs, sizeof(OF_regprop_t));
-+        }
-+        /* force usage of OF bus speeds */
-+        OF_prop_int_new(OF_env, via, "BusSpeedCorrect", 1);
- #if 0
-         OF_prop_int_new(OF_env, via, "pmu-version", 0x00D0740C);
- #endif
--#if 1
-+        {
-+            OF_node_t *kbd, *mouse;
-         /* ADB pseudo-device */
-         adb = OF_node_new(OF_env, via, "adb", OF_ADDRESS_NONE);
-         if (adb == NULL) {
-@@ -2797,9 +2930,26 @@
-         OF_prop_int_new(OF_env, adb, "#size-cells", 0);
-         OF_pack_get_path(OF_env, tmp, 512, adb);
-         OF_prop_string_new(OF_env, als, "adb", tmp);
--        /* XXX: add "keyboard@2" and "mouse@3" */
--        OF_node_put(OF_env, adb);
--#endif
-+
-+            kbd = OF_node_new(OF_env, adb, "keyboard", 2);
-+            if (kbd == NULL) {
-+                ERROR("Cannot create 'kbd'\n");
-+                goto out;
-+            }
-+            OF_prop_string_new(OF_env, kbd, "device_type", "keyboard");
-+            OF_prop_int_new(OF_env, kbd, "reg", 2);
-+
-+            mouse = OF_node_new(OF_env, adb, "mouse", 3);
-+            if (mouse == NULL) {
-+                ERROR("Cannot create 'mouse'\n");
-+                goto out;
-+            }
-+            OF_prop_string_new(OF_env, mouse, "device_type", "mouse");
-+            OF_prop_int_new(OF_env, mouse, "reg", 3);
-+            OF_prop_int_new(OF_env, mouse, "#buttons", 3);
-+        }
-+        {
-+            OF_node_t *rtc;
-         
-         rtc = OF_node_new(OF_env, via, "rtc", OF_ADDRESS_NONE);
-         if (rtc == NULL) {
-@@ -2813,14 +2963,68 @@
-         OF_prop_string_new(OF_env, rtc, "compatible", "rtc");
- #endif
-         OF_node_put(OF_env, rtc);
--        OF_node_put(OF_env, via);
-     }
-+        //        OF_node_put(OF_env, via);
-+    }
-+    {
-+        OF_node_t *pmgt;
-+        pmgt = OF_node_new(OF_env, mio, "power-mgt", OF_ADDRESS_NONE);
-+        OF_prop_string_new(OF_env, pmgt, "device_type", "power-mgt");
-+        OF_prop_string_new(OF_env, pmgt, "compatible", "cuda");
-+        OF_prop_string_new(OF_env, pmgt, "mgt-kind", "min-consumption-pwm-led");
-+        OF_node_put(OF_env, pmgt);
-+    }
-+
-+    if (arch == ARCH_HEATHROW) {
-+        /* NVRAM */
-+        OF_node_t *nvr;
-+        OF_regprop_t regs;
-+        nvr = OF_node_new(OF_env, mio, "nvram", 0x60000);
-+        OF_prop_string_new(OF_env, nvr, "device_type", "nvram");
-+        regs.address = 0x60000;
-+        regs.size = 0x00020000;
-+        OF_property_new(OF_env, nvr, "reg", &regs, sizeof(regs));
-+        OF_prop_int_new(OF_env, nvr, "#bytes", 0x2000);
-+        OF_node_put(OF_env, nvr);
-+    }
-+
-  out:
-     //    OF_node_put(OF_env, mio);
-     OF_node_put(OF_env, chs);
-     OF_node_put(OF_env, als);
- }
- 
-+void OF_finalize_pci_ide (void *dev, 
-+                          uint32_t io_base0, uint32_t io_base1,
-+                          uint32_t io_base2, uint32_t io_base3)
-+{
-+    OF_env_t *OF_env = OF_env_main;
-+    OF_node_t *pci_ata = dev;
-+    OF_node_t *ata, *atas[2];
-+    int i;
-+
-+    OF_prop_int_new(OF_env, pci_ata, "#address-cells", 1);
-+    OF_prop_int_new(OF_env, pci_ata, "#size-cells", 0);
-+
-+    /* XXX: Darwin handles only one device */
-+    for(i = 0; i < 1; i++) {
-+        ata = OF_node_new(OF_env, pci_ata, "ata-4", i);
-+        if (ata == NULL) {
-+            ERROR("Cannot create 'ata-4'\n");
-+            return;
-+        }
-+        OF_prop_string_new(OF_env, ata, "device_type", "ata");
-+        OF_prop_string_new(OF_env, ata, "compatible", "cmd646-ata");
-+        OF_prop_string_new(OF_env, ata, "model", "ata-4");
-+        OF_prop_int_new(OF_env, ata, "#address-cells", 1);
-+        OF_prop_int_new(OF_env, ata, "#size-cells", 0);
-+        OF_prop_int_new(OF_env, ata, "reg", i);
-+        atas[i] = ata;
-+    }
-+    ide_pci_pc_register(io_base0, io_base1, io_base2, io_base3,
-+                        atas[0], atas[1]);
-+}
-+
- /*****************************************************************************/
- /* Fake package */
- static void OF_method_fake (OF_env_t *OF_env)
-@@ -2862,11 +3066,11 @@
-     /* As we get a 1:1 mapping, do nothing */
-     ihandle = popd(OF_env);
-     args = (void *)popd(OF_env);
--    address = popd(OF_env);
--    virt = popd(OF_env);
--    size = popd(OF_env);
-     popd(OF_env);
--    OF_DPRINTF("Translate address %0x %0x %0x %0x\n", ihandle, address,
-+    size = popd(OF_env);
-+    virt = popd(OF_env);
-+    address = popd(OF_env);
-+    OF_DPRINTF("Map %0x %0x %0x %0x\n", ihandle, address,
-                virt, size);
-     pushd(OF_env, 0);
- }
-@@ -3270,7 +3474,7 @@
-     OF_prop_string_new(OF_env, dsk, "device_type", "block");
-     OF_prop_string_new(OF_env, dsk, "category", type);
-     OF_prop_int_new(OF_env, dsk, "device_id", devnum);
--    OF_prop_int_new(OF_env, dsk, "reg", 0);
-+    OF_prop_int_new(OF_env, dsk, "reg", devnum);
-     OF_method_new(OF_env, dsk, "open", &OF_blockdev_open);
-     OF_method_new(OF_env, dsk, "seek", &OF_blockdev_seek);
-     OF_method_new(OF_env, dsk, "read", &OF_blockdev_read);
-@@ -3432,7 +3636,8 @@
- }
- 
- void OF_vga_register (const unsigned char *name, unused uint32_t address,
--                      int width, int height, int depth)
-+                      int width, int height, int depth,
-+                      unsigned long vga_bios_addr, unsigned long vga_bios_size)
- {
-     OF_env_t *OF_env;
-     unsigned char tmp[OF_NAMELEN_MAX];
-@@ -3504,6 +3709,18 @@
-     OF_prop_string_new(OF_env, als, "display", tmp);
-     OF_node_put(OF_env, als);
-     /* XXX: may also need read-rectangle */
-+
-+    if (vga_bios_size >= 8) {
-+        const uint8_t *p;
-+        int size;
-+        /* check the QEMU VGA BIOS header */
-+        p = (const uint8_t *)vga_bios_addr;
-+        if (p[0] == 'N' && p[1] == 'D' && p[2] == 'R' && p[3] == 'V') {
-+            size = *(uint32_t *)(p + 4);
-+            OF_property_new(OF_env, disp, "driver,AAPL,MacOS,PowerPC", 
-+                            p + 8, size);
-+        }
-+    }
-  out:
-     OF_node_put(OF_env, disp);
- }
-@@ -4451,7 +4668,10 @@
-         break;
-     case 0x233441d3: /* MacOS X 10.2 and OpenDarwin 1.41 */
-         /* Create "memory-map" pseudo device */
--        popd(OF_env);
-+        {
-+            OF_node_t *map;
-+            uint32_t phandle;
-+
-         /* Find "/packages" */
-         chs = OF_pack_find_by_name(OF_env, OF_node_root, "/chosen");
-         if (chs == NULL) {
-@@ -4459,10 +4679,6 @@
-             ERROR("Cannot get '/chosen'\n");
-             break;
-         }
--        {
--#if 1
--            OF_node_t *map;
--            uint32_t phandle;
-             map = OF_node_new(OF_env, chs, "memory-map", OF_ADDRESS_NONE);
-             if (map == NULL) {
-                 pushd(OF_env, -1);
-@@ -4473,11 +4689,8 @@
-             OF_node_put(OF_env, map);
-             OF_node_put(OF_env, chs);
-             pushd(OF_env, phandle);
--        }
--#else
--        pushd(OF_env, 0);
--#endif
-         pushd(OF_env, 0);
-+        }
-         break;
-     case 0x32a2d18e: /* MacOS X 10.2 and OpenDarwin 6.02 */
-         /* Return screen ihandle */
-@@ -4540,9 +4753,10 @@
-     case 0x4ad41f2d:
-         /* Yaboot: wait 10 ms: sure ! */
-         break;
-+
-     default:
-         /* ERROR */
--        printf("Script:\n%s\n", FString);
-+        printf("Script: len=%d\n%s\n", (int)strlen(FString), FString);
-         printf("Call %0x NOT IMPLEMENTED !\n", crc);
-         bug();
-         break;
-@@ -4581,6 +4795,7 @@
- {
-     OF_CHECK_NBARGS(OF_env, 0);
-     /* Should free all OF resources */
-+    bd_reset_all();
- #if defined (DEBUG_BIOS)
-     {
-         uint16_t loglevel = 0x02 | 0x10 | 0x80;
-diff -wruN --exclude '*~' --exclude '*.o' --exclude '*.bin' --exclude '*.out' --exclude mkdiff OpenHackWare-release-0.4.org/src/pci.c OpenHackWare-release-0.4/src/pci.c
---- OpenHackWare-release-0.4.org/src/pci.c	2005-03-31 09:23:33.000000000 +0200
-+++ OpenHackWare-release-0.4/src/pci.c	2005-07-07 23:27:37.000000000 +0200
-@@ -99,8 +99,8 @@
-     uint16_t min_grant;
-     uint16_t max_latency;
-     uint8_t  irq_line;
--    uint32_t regions[6];
--    uint32_t sizes[6];
-+    uint32_t regions[7]; /* the region 6 is the PCI ROM */
-+    uint32_t sizes[7];
-     pci_device_t *next;
- };
- 
-@@ -158,6 +158,7 @@
- 
- /* IRQ numbers assigned to PCI IRQs */
- static uint8_t prep_pci_irqs[4] = { 9, 11, 9, 11 };
-+static uint8_t heathrow_pci_irqs[4] = { 0x15, 0x16, 0x17, 0x18 };
- static uint8_t pmac_pci_irqs[4] = { 8, 9, 10, 11 };
- 
- /* PREP PCI host */
-@@ -399,6 +400,79 @@
-     &uninorth_config_readl, &uninorth_config_writel,
- };
- 
-+/* Grackle PCI host */
-+
-+static uint32_t grackle_cfg_address (pci_bridge_t *bridge,
-+                                     uint8_t bus, uint8_t devfn,
-+                                     uint8_t offset)
-+{
-+    uint32_t addr;
-+    addr = 0x80000000 | (bus << 16) | (devfn << 8) | (offset & 0xfc);
-+    stswap32((uint32_t *)bridge->cfg_addr, addr);
-+    return bridge->cfg_data + (offset & 3);
-+}
-+
-+static uint8_t grackle_config_readb (pci_bridge_t *bridge,
-+                                      uint8_t bus, uint8_t devfn,
-+                                      uint8_t offset)
-+{
-+    uint32_t addr;
-+    addr = grackle_cfg_address(bridge, bus, devfn, offset);
-+    return *((uint8_t *)addr);
-+}
-+
-+static void grackle_config_writeb (pci_bridge_t *bridge,
-+                                    uint8_t bus, uint8_t devfn,
-+                                    uint8_t offset, uint8_t val)
-+{
-+    uint32_t addr;
-+    addr = grackle_cfg_address(bridge, bus, devfn, offset);
-+    *((uint8_t *)addr) = val;
-+}
-+
-+static uint16_t grackle_config_readw (pci_bridge_t *bridge,
-+                                       uint8_t bus, uint8_t devfn,
-+                                       uint8_t offset)
-+{
-+    uint32_t addr;
-+    addr = grackle_cfg_address(bridge, bus, devfn, offset);
-+    return ldswap16((uint16_t *)addr);
-+}
-+
-+static void grackle_config_writew (pci_bridge_t *bridge,
-+                                    uint8_t bus, uint8_t devfn,
-+                                    uint8_t offset, uint16_t val)
-+{
-+    uint32_t addr;
-+    addr = grackle_cfg_address(bridge, bus, devfn, offset);
-+    stswap16((uint16_t *)addr, val);
-+}
-+
-+static uint32_t grackle_config_readl (pci_bridge_t *bridge,
-+                                       uint8_t bus, uint8_t devfn,
-+                                       uint8_t offset)
-+{
-+    uint32_t addr;
-+    addr = grackle_cfg_address(bridge, bus, devfn, offset);
-+    return ldswap32((uint32_t *)addr);
-+}
-+
-+static void grackle_config_writel (pci_bridge_t *bridge,
-+                                    uint8_t bus, uint8_t devfn,
-+                                    uint8_t offset, uint32_t val)
-+{
-+    uint32_t addr;
-+
-+    addr = grackle_cfg_address(bridge, bus, devfn, offset);
-+    stswap32((uint32_t *)addr, val);
-+}
-+
-+static pci_ops_t grackle_pci_ops = {
-+    &grackle_config_readb, &grackle_config_writeb,
-+    &grackle_config_readw, &grackle_config_writew,
-+    &grackle_config_readl, &grackle_config_writel,
-+};
-+
- static inline uint8_t pci_config_readb (pci_bridge_t *bridge,
-                                         uint8_t bus, uint8_t devfn,
-                                         uint8_t offset)
-@@ -466,12 +540,22 @@
-     },
- };
- 
-+static int ide_config_cb2 (pci_device_t *device)
-+{
-+    OF_finalize_pci_ide(device->common.OF_private,
-+                        device->regions[0] & ~0x0000000F,
-+                        device->regions[1] & ~0x0000000F,
-+                        device->regions[2] & ~0x0000000F,
-+                        device->regions[3] & ~0x0000000F);
-+    return 0;
-+}
-+
- static pci_dev_t ide_devices[] = {
-     {
--        0x8086, 0x0100,
--        NULL, "Qemu IDE", "Qemu IDE",    "ide",
-+        0x1095, 0x0646, /* CMD646 IDE controller */
-+        "pci-ide", "pci-ata", NULL, NULL,
-         0, 0, 0,
--        NULL, NULL,
-+        ide_config_cb2, NULL,
-     },
-     {
-         0xFFFF, 0xFFFF,
-@@ -481,7 +565,9 @@
-     },
- };
- 
--static int ide_config_cb (pci_device_t *device)
-+#if 0
-+/* should base it on PCI ID, not on arch */
-+static int ide_config_cb (unused pci_device_t *device)
- {
-     printf("Register IDE controller\n");
-     switch (arch) {
-@@ -491,14 +577,8 @@
-                               device->common.OF_private);
-         break;
-     default:
--        ide_pci_pc_register(device->regions[0] & ~0x0000000F,
--                            device->regions[1] & ~0x0000000F,
--                            device->regions[2] & ~0x0000000F,
--                            device->regions[3] & ~0x0000000F,
--                            device->common.OF_private);
-         break;
-     }
--
-     return 0;
- }
- 
-@@ -512,16 +592,12 @@
-                               device->common.OF_private);
-         break;
-     default:
--        ide_pci_pc_register(device->regions[0] & ~0x0000000F,
--                            device->regions[1] & ~0x0000000F,
--                            device->regions[2] & ~0x0000000F,
--                            device->regions[3] & ~0x0000000F,
--                            device->common.OF_private);
-         break;
-     }
- 
-     return 0;
- }
-+#endif
- 
- static pci_subclass_t mass_subclass[] = {
-     {
-@@ -530,7 +606,7 @@
-     },
-     {
-         0x01, "IDE controller",             "ide", ide_devices, NULL,
--        &ide_config_cb, NULL,
-+        NULL, NULL,
-     },
-     {
-         0x02, "Floppy disk controller",     NULL,  NULL, NULL,
-@@ -546,7 +622,7 @@
-     },
-     {
-         0x05, "ATA controller",             "ata", NULL, NULL,
--        &ata_config_cb, NULL,
-+        NULL, NULL,
-     },
-     {
-         0x80, "misc mass-storage controller", NULL, NULL, NULL,
-@@ -646,7 +722,9 @@
-         /* VGA 640x480x16 */
-         OF_vga_register(device->common.device->name,
-                         device->regions[0] & ~0x0000000F,
--                        vga_width, vga_height, vga_depth);
-+                        vga_width, vga_height, vga_depth,
-+                        device->regions[6] & ~0x0000000F,
-+                        device->sizes[6]);
-     }
-     vga_console_register();
- 
-@@ -750,6 +828,13 @@
-     NULL, &PREP_pci_ops,
- };
- 
-+pci_dev_t grackle_fake_bridge = {
-+    0xFFFF, 0xFFFF,
-+    "pci", "pci-bridge", "DEC,21154", "DEC,21154.pci-bridge",
-+    -1, -1, -1,
-+    NULL, &grackle_pci_ops,
-+};
-+
- static pci_dev_t hbrg_devices[] = {
-     {
-         0x106B, 0x0020, NULL,
-@@ -758,8 +843,8 @@
-         NULL, &uninorth_agp_fake_bridge,
-     },
-     {
--        0x106B, 0x001F,
--        NULL, "pci", "AAPL,UniNorth", "uni-north",
-+        0x106B, 0x001F, NULL, 
-+        "pci", "AAPL,UniNorth", "uni-north",
-         3, 2, 1,
-         NULL, &uninorth_fake_bridge,
-     },
-@@ -770,10 +855,10 @@
-         NULL, &uninorth_fake_bridge,
-     },
-     {
--        0x1011, 0x0026, NULL,
--        "pci-bridge", NULL, NULL,
-+        0x1057, 0x0002, "pci",
-+        "pci", "MOT,MPC106", "grackle",
-         3, 2, 1,
--        NULL, &PREP_pci_ops,
-+        NULL, &grackle_fake_bridge,
-     },
-     {
-         0x1057, 0x4801, NULL,
-@@ -1443,7 +1528,14 @@
- }
- 
- static const pci_dev_t misc_pci[] = {
--    /* Apple Mac-io controller */
-+    /* Paddington Mac I/O */
-+    { 
-+        0x106B, 0x0017,
-+        "mac-io", "mac-io", "AAPL,343S1211", "paddington\1heathrow",
-+        1, 1, 1,
-+        &macio_config_cb, NULL,
-+    },
-+    /* KeyLargo Mac I/O */
-     { 
-         0x106B, 0x0022,
-         "mac-io", "mac-io", "AAPL,Keylargo", "Keylargo",
-@@ -1599,7 +1691,7 @@
-                                       uint8_t min_grant, uint8_t max_latency,
-                                       int irq_line)
- {
--    uint32_t cmd;
-+    uint32_t cmd, addr;
-     int i;
- 
-     device->min_grant = min_grant;
-@@ -1611,22 +1703,28 @@
-         printf("MAP PCI device %d:%d to IRQ %d\n",
-                device->bus, device->devfn, irq_line);
-     }
--    for (i = 0; i < 6; i++) {
-+    for (i = 0; i < 7; i++) {
-         if ((device->regions[i] & ~0xF) != 0x00000000 &&
-             (device->regions[i] & ~0xF) != 0xFFFFFFF0) {
-             printf("Map PCI device %d:%d %d to %0x %0x (%s)\n",
-                    device->bus, device->devfn, i,
-                    device->regions[i], device->sizes[i],
--                   device->regions[i] & 0x00000001 ? "I/O" : "memory");
-+                   (device->regions[i] & 0x00000001) && i != 6 ? "I/O" : 
-+                    "memory");
-+            if (i != 6) {
-             cmd = pci_config_readl(bridge, device->bus, device->devfn, 0x04);
-             if (device->regions[i] & 0x00000001)
-                 cmd |= 0x00000001;
-             else
-                 cmd |= 0x00000002;
-             pci_config_writel(bridge, device->bus, device->devfn, 0x04, cmd);
-+            }
-+            if (i == 6)
-+                addr = 0x30; /* PCI ROM */
-+            else
-+                addr = 0x10 + (i * sizeof(uint32_t));
-             pci_config_writel(bridge, device->bus, device->devfn,
--                              0x10 + (i * sizeof(uint32_t)),
--                              device->regions[i]);
-+                              addr, device->regions[i]);
-         }
-     }
- }
-@@ -1900,7 +1998,7 @@
-         goto out;
-     }
-     ret = (pci_u_t *)newd;
--    max_areas = 6;
-+    max_areas = 7;
-     /* register PCI device in OF tree */
-     if (bridge->dev.common.type == PCI_FAKE_BRIDGE) {
-         newd->common.OF_private =
-@@ -1927,6 +2025,9 @@
-             /* Handle 64 bits memory mapping */
-             continue;
-         }
-+        if (i == 6)
-+            addr = 0x30; /* PCI ROM */
-+        else
-         addr = 0x10 + (i * sizeof(uint32_t));
-         /* Get region size
-          * Note: we assume it's always a power of 2
-@@ -1935,7 +2036,7 @@
-         smask = pci_config_readl(bridge, bus, devfn, addr);
-         if (smask == 0x00000000 || smask == 0xFFFFFFFF)
-             continue;
--        if (smask & 0x00000001) {
-+        if ((smask & 0x00000001) != 0 && i != 6) {
-             /* I/O space */
-             base = io_base;
-             /* Align to a minimum of 256 bytes (arbitrary) */
-@@ -1947,6 +2048,8 @@
-             /* Align to a minimum of 64 kB (arbitrary) */
-             min_align = 1 << 16;
-             amask = 0x0000000F;
-+            if (i == 6)
-+                smask |= 1; /* PCI ROM enable */
-         }
-         omask = smask & amask;
-         smask &= ~amask;
-@@ -1980,7 +2083,10 @@
-     if (irq_pin > 0) {
-         /* assign the IRQ */
-         irq_pin = ((devfn >> 3) + irq_pin - 1) & 3;
--        if (arch == ARCH_PREP) {
-+        /* XXX: should base it on the PCI bridge type, not the arch */
-+        switch(arch) {
-+        case ARCH_PREP:
-+            {
-             int elcr_port, val;
-             irq_line = prep_pci_irqs[irq_pin];
-             /* set the IRQ to level-sensitive */
-@@ -1988,14 +2094,22 @@
-             val = inb(elcr_port);
-             val |= 1 << (irq_line & 7);
-             outb(elcr_port, val);
--        } else {
-+            }
-+            break;
-+        case ARCH_MAC99:
-             irq_line = pmac_pci_irqs[irq_pin];
-+            break;
-+        case ARCH_HEATHROW:
-+            irq_line = heathrow_pci_irqs[irq_pin];
-+            break;
-+        default:
-+            break;
-         }
-     }
-  update_device:
-     pci_update_device(bridge, newd, min_grant, max_latency, irq_line);
-     OF_finalize_pci_device(newd->common.OF_private, bus, devfn,
--                           newd->regions, newd->sizes);
-+                           newd->regions, newd->sizes, irq_line);
-     /* Call special inits if needed */
-     if (dev->config_cb != NULL)
-         (*dev->config_cb)(newd);
-@@ -2049,6 +2163,32 @@
-     case ARCH_CHRP:
-         /* TODO */
-         break;
-+    case ARCH_HEATHROW:
-+        dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp);
-+        if (dev == NULL)
-+            return -1;
-+        fake_host = pci_add_host(hostp, dev,
-+                                 (0x06 << 24) | (0x00 << 16) | (0xFF << 8));
-+        if (fake_host == NULL)
-+            return -1;
-+        fake_host->dev.common.type = PCI_FAKE_HOST;
-+        dev = &grackle_fake_bridge;
-+        if (dev == NULL)
-+            goto free_fake_host;
-+        fake_bridge = pci_add_bridge(fake_host, 0, 0, dev,
-+                                     (0x06 << 24) | (0x04 << 16) | (0xFF << 8),
-+                                     cfg_base, cfg_len,
-+                                     cfg_base + 0x7ec00000,
-+                                     cfg_base + 0x7ee00000,
-+                                     mem_base, mem_len,
-+                                     io_base, io_len,
-+                                     rbase, rlen,
-+                                     0,
-+                                     &grackle_pci_ops);
-+        if (fake_bridge == NULL)
-+            goto free_fake_host;
-+        fake_bridge->dev.common.type = PCI_FAKE_BRIDGE;
-+        break;
-     case ARCH_MAC99:
-         dev = pci_find_device(0x06, 0x00, 0xFF, checkv, checkp);
-         if (dev == NULL)
-@@ -2167,6 +2307,30 @@
-     case ARCH_CHRP:
-         /* TODO */
-         break;
-+    case ARCH_HEATHROW:
-+        cfg_base = 0x80000000;
-+        cfg_len  = 0x7f000000;
-+        mem_base = 0x80000000;
-+        mem_len  = 0x01000000;
-+        io_base  = 0xfe000000;
-+        io_len   = 0x00800000;
-+#if 1
-+        rbase    = 0xfd000000;
-+        rlen     = 0x01000000;
-+#else
-+        rbase    = 0x00000000;
-+        rlen     = 0x01000000;
-+#endif
-+        if (pci_check_host(&pci_main, cfg_base, cfg_len,
-+                           mem_base, mem_len, io_base, io_len, rbase, rlen,
-+                           0x1057, 0x0002) == 0) {
-+            isa_io_base = io_base;
-+            busnum++;
-+        }
-+        for (curh = pci_main; curh->next != NULL; curh = curh->next)
-+            continue;
-+        pci_check_devices(curh);
-+        break;
-     case ARCH_MAC99:
-         /* We are supposed to have 3 host bridges:
-          * - the uninorth AGP bridge at 0xF0000000
diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin
index 0ad0282..d378d9a 100644
--- a/pc-bios/ppc_rom.bin
+++ b/pc-bios/ppc_rom.bin
Binary files differ
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 92a9831..a742bff 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/qapi-schema.json b/qapi-schema.json
index 6c381b7..b68cd44 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -883,6 +883,35 @@
 { 'command': 'query-cpus', 'returns': ['CpuInfo'] }
 
 ##
+# @IOThreadInfo:
+#
+# Information about an iothread
+#
+# @id: the identifier of the iothread
+#
+# @thread-id: ID of the underlying host thread
+#
+# Since: 2.0
+##
+{ 'type': 'IOThreadInfo',
+  'data': {'id': 'str', 'thread-id': 'int'} }
+
+##
+# @query-iothreads:
+#
+# Returns a list of information about each iothread.
+#
+# Note this list excludes the QEMU main loop thread, which is not declared
+# using the -object iothread command-line option.  It is always the main thread
+# of the process.
+#
+# Returns: a list of @IOThreadInfo for each iothread
+#
+# Since: 2.0
+##
+{ 'command': 'query-iothreads', 'returns': ['IOThreadInfo'] }
+
+##
 # @BlockDeviceInfo:
 #
 # Information about the backing device for a block device.
@@ -4249,6 +4278,18 @@
             '*no-flush': 'bool' } }
 
 ##
+# @BlockdevDriver
+#
+# Drivers that are supported in block device operations.
+#
+# Since: 2.0
+##
+{ 'enum': 'BlockdevDriver',
+  'data': [ 'file', 'http', 'https', 'ftp', 'ftps', 'tftp', 'vvfat', 'blkdebug',
+            'blkverify', 'bochs', 'cloop', 'cow', 'dmg', 'parallels', 'qcow',
+            'qcow2', 'qed', 'raw', 'vdi', 'vhdx', 'vmdk', 'vpc', 'quorum' ] }
+
+##
 # @BlockdevOptionsBase
 #
 # Options that are available for all block devices, independent of the block
@@ -4272,7 +4313,7 @@
 # Since: 1.7
 ##
 { 'type': 'BlockdevOptionsBase',
-  'data': { 'driver': 'str',
+  'data': { 'driver': 'BlockdevDriver',
             '*id': 'str',
             '*node-name': 'str',
             '*discard': 'BlockdevDiscardOptions',
diff --git a/qdev-monitor.c b/qdev-monitor.c
index 6673e3c..9268c87 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -522,7 +522,7 @@
         return NULL;
     }
 
-    /* create device, set properties */
+    /* create device */
     dev = DEVICE(object_new(driver));
 
     if (bus) {
@@ -533,11 +533,7 @@
     if (id) {
         dev->id = id;
     }
-    if (qemu_opt_foreach(opts, set_property, dev, 1) != 0) {
-        object_unparent(OBJECT(dev));
-        object_unref(OBJECT(dev));
-        return NULL;
-    }
+
     if (dev->id) {
         object_property_add_child(qdev_get_peripheral(), dev->id,
                                   OBJECT(dev), NULL);
@@ -549,6 +545,13 @@
         g_free(name);
     }
 
+    /* set properties */
+    if (qemu_opt_foreach(opts, set_property, dev, 1) != 0) {
+        object_unparent(OBJECT(dev));
+        object_unref(OBJECT(dev));
+        return NULL;
+    }
+
     dev->opts = opts;
     object_property_set_bool(OBJECT(dev), true, "realized", &err);
     if (err != NULL) {
diff --git a/qemu-char.c b/qemu-char.c
index 4d50838..54ed244 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -213,7 +213,7 @@
     s->chr_read = fd_read;
     s->chr_event = fd_event;
     s->handler_opaque = opaque;
-    if (s->chr_update_read_handler)
+    if (fe_open && s->chr_update_read_handler)
         s->chr_update_read_handler(s);
 
     if (!s->explicit_fe_open) {
@@ -1136,13 +1136,14 @@
         if (!s->connected) {
             s->connected = 1;
             qemu_chr_be_generic_open(chr);
+        }
+        if (!chr->fd_in_tag) {
             chr->fd_in_tag = io_add_watch_poll(s->fd, pty_chr_read_poll,
                                                pty_chr_read, chr);
         }
     }
 }
 
-
 static void pty_chr_close(struct CharDriverState *chr)
 {
     PtyCharDriver *s = chr->opaque;
@@ -2509,6 +2510,17 @@
     qemu_chr_be_generic_open(chr);
 }
 
+static void tcp_chr_update_read_handler(CharDriverState *chr)
+{
+    TCPCharDriver *s = chr->opaque;
+
+    remove_fd_in_watch(chr);
+    if (s->chan) {
+        chr->fd_in_tag = io_add_watch_poll(s->chan, tcp_chr_read_poll,
+                                           tcp_chr_read, chr);
+    }
+}
+
 #define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
 static void tcp_chr_telnet_init(int fd)
 {
@@ -2664,6 +2676,7 @@
     chr->get_msgfd = tcp_get_msgfd;
     chr->chr_add_client = tcp_chr_add_client;
     chr->chr_add_watch = tcp_chr_add_watch;
+    chr->chr_update_read_handler = tcp_chr_update_read_handler;
     /* be isn't opened until we get a connection */
     chr->explicit_be_open = true;
 
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index f1de24c..fb1db53 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -16,7 +16,7 @@
 
 #define CMD_NOFILE_OK   0x01
 
-int qemuio_misalign;
+bool qemuio_misalign;
 
 static cmdinfo_t *cmdtab;
 static int ncmds;
diff --git a/qemu-io.c b/qemu-io.c
index fc38608..2d119c2 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -24,10 +24,9 @@
 
 #define CMD_NOFILE_OK   0x01
 
-char *progname;
+static char *progname;
 
-BlockDriverState *qemuio_bs;
-extern int qemuio_misalign;
+static BlockDriverState *qemuio_bs;
 
 /* qemu-io commands passed using -c */
 static int ncmdline;
@@ -408,7 +407,7 @@
             readonly = 1;
             break;
         case 'm':
-            qemuio_misalign = 1;
+            qemuio_misalign = true;
             break;
         case 'g':
             growable = 1;
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d982cd6..a22621f 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2327,6 +2327,45 @@
     },
 
 SQMP
+query-iothreads
+---------------
+
+Returns a list of information about each iothread.
+
+Note this list excludes the QEMU main loop thread, which is not declared
+using the -object iothread command-line option.  It is always the main thread
+of the process.
+
+Return a json-array. Each iothread is represented by a json-object, which contains:
+
+- "id": name of iothread (json-str)
+- "thread-id": ID of the underlying host thread (json-int)
+
+Example:
+
+-> { "execute": "query-iothreads" }
+<- {
+      "return":[
+         {
+            "id":"iothread0",
+            "thread-id":3134
+         },
+         {
+            "id":"iothread1",
+            "thread-id":3135
+         }
+      ]
+   }
+
+EQMP
+
+    {
+        .name       = "query-iothreads",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_input_query_iothreads,
+    },
+
+SQMP
 query-pci
 ---------
 
diff --git a/qmp.c b/qmp.c
index f556a04..87a28f7 100644
--- a/qmp.c
+++ b/qmp.c
@@ -114,8 +114,11 @@
 
 void qmp_cpu_add(int64_t id, Error **errp)
 {
-    if (current_machine->hot_add_cpu) {
-        current_machine->hot_add_cpu(id, errp);
+    MachineClass *mc;
+
+    mc = MACHINE_GET_CLASS(current_machine);
+    if (mc->qemu_machine->hot_add_cpu) {
+        mc->qemu_machine->hot_add_cpu(id, errp);
     } else {
         error_setg(errp, "Not supported");
     }
diff --git a/qom/object.c b/qom/object.c
index 660859c..a2a1ffa 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -1102,39 +1102,49 @@
     g_free(full_type);
 }
 
+gchar *object_get_canonical_path_component(Object *obj)
+{
+    ObjectProperty *prop = NULL;
+
+    g_assert(obj);
+    g_assert(obj->parent != NULL);
+
+    QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
+        if (!object_property_is_child(prop)) {
+            continue;
+        }
+
+        if (prop->opaque == obj) {
+            return g_strdup(prop->name);
+        }
+    }
+
+    /* obj had a parent but was not a child, should never happen */
+    g_assert_not_reached();
+    return NULL;
+}
+
 gchar *object_get_canonical_path(Object *obj)
 {
     Object *root = object_get_root();
-    char *newpath = NULL, *path = NULL;
+    char *newpath, *path = NULL;
 
     while (obj != root) {
-        ObjectProperty *prop = NULL;
+        char *component = object_get_canonical_path_component(obj);
 
-        g_assert(obj->parent != NULL);
-
-        QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
-            if (!object_property_is_child(prop)) {
-                continue;
-            }
-
-            if (prop->opaque == obj) {
-                if (path) {
-                    newpath = g_strdup_printf("%s/%s", prop->name, path);
-                    g_free(path);
-                    path = newpath;
-                } else {
-                    path = g_strdup(prop->name);
-                }
-                break;
-            }
+        if (path) {
+            newpath = g_strdup_printf("%s/%s", component, path);
+            g_free(component);
+            g_free(path);
+            path = newpath;
+        } else {
+            path = component;
         }
 
-        g_assert(prop != NULL);
-
         obj = obj->parent;
     }
 
-    newpath = g_strdup_printf("/%s", path);
+    newpath = g_strdup_printf("/%s", path ? path : "");
     g_free(path);
 
     return newpath;
@@ -1293,6 +1303,7 @@
                            void (*set)(Object *, const char *, Error **),
                            Error **errp)
 {
+    Error *local_err = NULL;
     StringProperty *prop = g_malloc0(sizeof(*prop));
 
     prop->get = get;
@@ -1302,7 +1313,11 @@
                         get ? property_get_str : NULL,
                         set ? property_set_str : NULL,
                         property_release_str,
-                        prop, errp);
+                        prop, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        g_free(prop);
+    }
 }
 
 typedef struct BoolProperty
@@ -1349,6 +1364,7 @@
                               void (*set)(Object *, bool, Error **),
                               Error **errp)
 {
+    Error *local_err = NULL;
     BoolProperty *prop = g_malloc0(sizeof(*prop));
 
     prop->get = get;
@@ -1358,7 +1374,11 @@
                         get ? property_get_bool : NULL,
                         set ? property_set_bool : NULL,
                         property_release_bool,
-                        prop, errp);
+                        prop, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        g_free(prop);
+    }
 }
 
 static char *qdev_get_type(Object *obj, Error **errp)
diff --git a/roms/SLOF b/roms/SLOF
index e2e8ac9..af6b7bf 160000
--- a/roms/SLOF
+++ b/roms/SLOF
@@ -1 +1 @@
-Subproject commit e2e8ac901e617573ea383f9cffd136146d0675a4
+Subproject commit af6b7bf5879b6cd6825de2a107cb0e3219fb1df5
diff --git a/roms/openhackware b/roms/openhackware
new file mode 160000
index 0000000..e9829b5
--- /dev/null
+++ b/roms/openhackware
@@ -0,0 +1 @@
+Subproject commit e9829b5584169ad14df2ca8776b87f4985aa9f06
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index 2c6e0dc..10864ef 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -127,16 +127,6 @@
 ''')
     return ret
 
-def generate_enum_name(name):
-    if name.isupper():
-        return c_fun(name, False)
-    new_name = ''
-    for c in c_fun(name, False):
-        if c.isupper():
-            new_name += '_'
-        new_name += c
-    return new_name.lstrip('_').upper()
-
 def generate_enum(name, values):
     lookup_decl = mcgen('''
 extern const char *%(name)s_lookup[];
@@ -154,11 +144,11 @@
 
     i = 0
     for value in enum_values:
+        enum_full_value = generate_enum_full_value(name, value)
         enum_decl += mcgen('''
-    %(abbrev)s_%(value)s = %(i)d,
+    %(enum_full_value)s = %(i)d,
 ''',
-                     abbrev=de_camel_case(name).upper(),
-                     value=generate_enum_name(value),
+                     enum_full_value = enum_full_value,
                      i=i)
         i += 1
 
@@ -211,14 +201,21 @@
     base = expr.get('base')
     discriminator = expr.get('discriminator')
 
+    enum_define = discriminator_find_enum_define(expr)
+    if enum_define:
+        discriminator_type_name = enum_define['enum_name']
+    else:
+        discriminator_type_name = '%sKind' % (name)
+
     ret = mcgen('''
 struct %(name)s
 {
-    %(name)sKind kind;
+    %(discriminator_type_name)s kind;
     union {
         void *data;
 ''',
-                name=name)
+                name=name,
+                discriminator_type_name=discriminator_type_name)
 
     for key in typeinfo:
         ret += mcgen('''
@@ -399,8 +396,11 @@
         fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
     elif expr.has_key('union'):
         ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
-        ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
-        fdef.write(generate_enum_lookup('%sKind' % expr['union'], expr['data'].keys()))
+        enum_define = discriminator_find_enum_define(expr)
+        if not enum_define:
+            ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
+            fdef.write(generate_enum_lookup('%sKind' % expr['union'],
+                                            expr['data'].keys()))
         if expr.get('discriminator') == {}:
             fdef.write(generate_anon_union_qtypes(expr))
     else:
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index c6de9ae..45ce3a9 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -214,18 +214,22 @@
 ''',
     name=name)
 
+    # For anon union, always use the default enum type automatically generated
+    # as "'%sKind' % (name)"
+    disc_type = '%sKind' % (name)
+
     for key in members:
         assert (members[key] in builtin_types
             or find_struct(members[key])
             or find_union(members[key])), "Invalid anonymous union member"
 
+        enum_full_value = generate_enum_full_value(disc_type, key)
         ret += mcgen('''
-        case %(abbrev)s_KIND_%(enum)s:
+        case %(enum_full_value)s:
             visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
             break;
 ''',
-                abbrev = de_camel_case(name).upper(),
-                enum = c_fun(de_camel_case(key),False).upper(),
+                enum_full_value = enum_full_value,
                 c_type = type_name(members[key]),
                 c_name = c_fun(key))
 
@@ -255,7 +259,16 @@
         assert not base
         return generate_visit_anon_union(name, members)
 
-    ret = generate_visit_enum('%sKind' % name, members.keys())
+    enum_define = discriminator_find_enum_define(expr)
+    if enum_define:
+        # Use the enum type as discriminator
+        ret = ""
+        disc_type = enum_define['enum_name']
+    else:
+        # There will always be a discriminator in the C switch code, by default it
+        # is an enum type generated silently as "'%sKind' % (name)"
+        ret = generate_visit_enum('%sKind' % name, members.keys())
+        disc_type = '%sKind' % (name)
 
     if base:
         base_fields = find_struct(base)['data']
@@ -291,15 +304,16 @@
     pop_indent()
 
     if not discriminator:
-        desc_type = "type"
+        disc_key = "type"
     else:
-        desc_type = discriminator
+        disc_key = discriminator
     ret += mcgen('''
-        visit_type_%(name)sKind(m, &(*obj)->kind, "%(type)s", &err);
+        visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
         if (!err) {
             switch ((*obj)->kind) {
 ''',
-                 name=name, type=desc_type)
+                 disc_type = disc_type,
+                 disc_key = disc_key)
 
     for key in members:
         if not discriminator:
@@ -313,13 +327,13 @@
                     visit_end_implicit_struct(m, &err);
                 }'''
 
+        enum_full_value = generate_enum_full_value(disc_type, key)
         ret += mcgen('''
-            case %(abbrev)s_KIND_%(enum)s:
+            case %(enum_full_value)s:
                 ''' + fmt + '''
                 break;
 ''',
-                abbrev = de_camel_case(name).upper(),
-                enum = c_fun(de_camel_case(key),False).upper(),
+                enum_full_value = enum_full_value,
                 c_type=type_name(members[key]),
                 c_name=c_fun(key))
 
@@ -510,7 +524,11 @@
         ret += generate_visit_list(expr['union'], expr['data'])
         fdef.write(ret)
 
-        ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys())
+        enum_define = discriminator_find_enum_define(expr)
+        ret = ""
+        if not enum_define:
+            ret = generate_decl_enum('%sKind' % expr['union'],
+                                     expr['data'].keys())
         ret += generate_declaration(expr['union'], expr['data'])
         fdecl.write(ret)
     elif expr.has_key('enum'):
diff --git a/scripts/qapi.py b/scripts/qapi.py
index f3c2a20..b474c39 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -39,12 +39,10 @@
     def __init__(self, schema, msg):
         self.fp = schema.fp
         self.msg = msg
-        self.line = self.col = 1
-        for ch in schema.src[0:schema.pos]:
-            if ch == '\n':
-                self.line += 1
-                self.col = 1
-            elif ch == '\t':
+        self.col = 1
+        self.line = schema.line
+        for ch in schema.src[schema.line_pos:schema.pos]:
+            if ch == '\t':
                 self.col = (self.col + 7) % 8 + 1
             else:
                 self.col += 1
@@ -52,6 +50,15 @@
     def __str__(self):
         return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg)
 
+class QAPIExprError(Exception):
+    def __init__(self, expr_info, msg):
+        self.fp = expr_info['fp']
+        self.line = expr_info['line']
+        self.msg = msg
+
+    def __str__(self):
+        return "%s:%s: %s" % (self.fp.name, self.line, self.msg)
+
 class QAPISchema:
 
     def __init__(self, fp):
@@ -60,11 +67,16 @@
         if self.src == '' or self.src[-1] != '\n':
             self.src += '\n'
         self.cursor = 0
+        self.line = 1
+        self.line_pos = 0
         self.exprs = []
         self.accept()
 
         while self.tok != None:
-            self.exprs.append(self.get_expr(False))
+            expr_info = {'fp': fp, 'line': self.line}
+            expr_elem = {'expr': self.get_expr(False),
+                         'info': expr_info}
+            self.exprs.append(expr_elem)
 
     def accept(self):
         while True:
@@ -100,6 +112,8 @@
                 if self.cursor == len(self.src):
                     self.tok = None
                     return
+                self.line += 1
+                self.line_pos = self.cursor
             elif not self.tok.isspace():
                 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
 
@@ -116,6 +130,8 @@
             if self.tok != ':':
                 raise QAPISchemaError(self, 'Expected ":"')
             self.accept()
+            if key in expr:
+                raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
             expr[key] = self.get_expr(True)
             if self.tok == '}':
                 self.accept()
@@ -158,6 +174,95 @@
             raise QAPISchemaError(self, 'Expected "{", "[" or string')
         return expr
 
+def find_base_fields(base):
+    base_struct_define = find_struct(base)
+    if not base_struct_define:
+        return None
+    return base_struct_define['data']
+
+# Return the discriminator enum define if discriminator is specified as an
+# enum type, otherwise return None.
+def discriminator_find_enum_define(expr):
+    base = expr.get('base')
+    discriminator = expr.get('discriminator')
+
+    if not (discriminator and base):
+        return None
+
+    base_fields = find_base_fields(base)
+    if not base_fields:
+        return None
+
+    discriminator_type = base_fields.get(discriminator)
+    if not discriminator_type:
+        return None
+
+    return find_enum(discriminator_type)
+
+def check_union(expr, expr_info):
+    name = expr['union']
+    base = expr.get('base')
+    discriminator = expr.get('discriminator')
+    members = expr['data']
+
+    # If the object has a member 'base', its value must name a complex type.
+    if base:
+        base_fields = find_base_fields(base)
+        if not base_fields:
+            raise QAPIExprError(expr_info,
+                                "Base '%s' is not a valid type"
+                                % base)
+
+    # If the union object has no member 'discriminator', it's an
+    # ordinary union.
+    if not discriminator:
+        enum_define = None
+
+    # Else if the value of member 'discriminator' is {}, it's an
+    # anonymous union.
+    elif discriminator == {}:
+        enum_define = None
+
+    # Else, it's a flat union.
+    else:
+        # The object must have a member 'base'.
+        if not base:
+            raise QAPIExprError(expr_info,
+                                "Flat union '%s' must have a base field"
+                                % name)
+        # The value of member 'discriminator' must name a member of the
+        # base type.
+        discriminator_type = base_fields.get(discriminator)
+        if not discriminator_type:
+            raise QAPIExprError(expr_info,
+                                "Discriminator '%s' is not a member of base "
+                                "type '%s'"
+                                % (discriminator, base))
+        enum_define = find_enum(discriminator_type)
+        # Do not allow string discriminator
+        if not enum_define:
+            raise QAPIExprError(expr_info,
+                                "Discriminator '%s' must be of enumeration "
+                                "type" % discriminator)
+
+    # Check every branch
+    for (key, value) in members.items():
+        # If this named member's value names an enum type, then all members
+        # of 'data' must also be members of the enum type.
+        if enum_define and not key in enum_define['enum_values']:
+            raise QAPIExprError(expr_info,
+                                "Discriminator value '%s' is not found in "
+                                "enum '%s'" %
+                                (key, enum_define["enum_name"]))
+        # Todo: add checking for values. Key is checked as above, value can be
+        # also checked here, but we need more functions to handle array case.
+
+def check_exprs(schema):
+    for expr_elem in schema.exprs:
+        expr = expr_elem['expr']
+        if expr.has_key('union'):
+            check_union(expr, expr_elem['info'])
+
 def parse_schema(fp):
     try:
         schema = QAPISchema(fp)
@@ -167,16 +272,29 @@
 
     exprs = []
 
-    for expr in schema.exprs:
+    for expr_elem in schema.exprs:
+        expr = expr_elem['expr']
         if expr.has_key('enum'):
-            add_enum(expr['enum'])
+            add_enum(expr['enum'], expr['data'])
         elif expr.has_key('union'):
             add_union(expr)
-            add_enum('%sKind' % expr['union'])
         elif expr.has_key('type'):
             add_struct(expr)
         exprs.append(expr)
 
+    # Try again for hidden UnionKind enum
+    for expr_elem in schema.exprs:
+        expr = expr_elem['expr']
+        if expr.has_key('union'):
+            if not discriminator_find_enum_define(expr):
+                add_enum('%sKind' % expr['union'])
+
+    try:
+        check_exprs(schema)
+    except QAPIExprError, e:
+        print >>sys.stderr, e
+        exit(1)
+
     return exprs
 
 def parse_args(typeinfo):
@@ -289,13 +407,19 @@
             return union
     return None
 
-def add_enum(name):
+def add_enum(name, enum_values = None):
     global enum_types
-    enum_types.append(name)
+    enum_types.append({"enum_name": name, "enum_values": enum_values})
+
+def find_enum(name):
+    global enum_types
+    for enum in enum_types:
+        if enum['enum_name'] == name:
+            return enum
+    return None
 
 def is_enum(name):
-    global enum_types
-    return (name in enum_types)
+    return find_enum(name) != None
 
 def c_type(name):
     if name == 'str':
@@ -373,3 +497,30 @@
 
 ''',
                  name=guardname(name))
+
+# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
+# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
+# ENUM24_Name -> ENUM24_NAME
+def _generate_enum_string(value):
+    c_fun_str = c_fun(value, False)
+    if value.isupper():
+        return c_fun_str
+
+    new_name = ''
+    l = len(c_fun_str)
+    for i in range(l):
+        c = c_fun_str[i]
+        # When c is upper and no "_" appears before, do more checks
+        if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
+            # Case 1: next string is lower
+            # Case 2: previous string is digit
+            if (i < (l - 1) and c_fun_str[i + 1].islower()) or \
+            c_fun_str[i - 1].isdigit():
+                new_name += '_'
+        new_name += c
+    return new_name.lstrip('_').upper()
+
+def generate_enum_full_value(enum_name, enum_value):
+    abbrev_string = _generate_enum_string(enum_name)
+    value_string = _generate_enum_string(enum_value)
+    return "%s_%s" % (abbrev_string, value_string)
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 9f69d7e..5cfe450 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -315,7 +315,7 @@
 } X86RegisterInfo32;
 
 #define REGISTER(reg) \
-    [R_##reg] = { .name = #reg, .qapi_enum = X86_C_P_U_REGISTER32_##reg }
+    [R_##reg] = { .name = #reg, .qapi_enum = X86_CPU_REGISTER32_##reg }
 X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = {
     REGISTER(EAX),
     REGISTER(ECX),
diff --git a/target-sparc/cpu.c b/target-sparc/cpu.c
index e7f878e..5806e59 100644
--- a/target-sparc/cpu.c
+++ b/target-sparc/cpu.c
@@ -458,7 +458,8 @@
         .mmu_trcr_mask = 0xffffffff,
         .nwindows = 8,
         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
-        CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL | CPU_FEATURE_POWERDOWN,
+        CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL | CPU_FEATURE_POWERDOWN |
+        CPU_FEATURE_CASA,
     },
 #endif
 };
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index c519063..ed6d2d1 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -271,6 +271,7 @@
 #define CPU_FEATURE_ASR17        (1 << 15)
 #define CPU_FEATURE_CACHE_CTRL   (1 << 16)
 #define CPU_FEATURE_POWERDOWN    (1 << 17)
+#define CPU_FEATURE_CASA         (1 << 18)
 
 #ifndef TARGET_SPARC64
 #define CPU_DEFAULT_FEATURES (CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP |  \
@@ -282,7 +283,8 @@
                               CPU_FEATURE_MUL | CPU_FEATURE_DIV |     \
                               CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT | \
                               CPU_FEATURE_FMUL | CPU_FEATURE_VIS1 |   \
-                              CPU_FEATURE_VIS2 | CPU_FEATURE_FSMULD)
+                              CPU_FEATURE_VIS2 | CPU_FEATURE_FSMULD | \
+                              CPU_FEATURE_CASA)
 enum {
     mmu_us_12, // Ultrasparc < III (64 entry TLB)
     mmu_us_3,  // Ultrasparc III (512 entry TLB)
diff --git a/target-sparc/helper.h b/target-sparc/helper.h
index 2a771b2..cd8d3fa 100644
--- a/target-sparc/helper.h
+++ b/target-sparc/helper.h
@@ -22,7 +22,6 @@
 DEF_HELPER_4(ldda_asi, void, env, tl, int, int)
 DEF_HELPER_5(ldf_asi, void, env, tl, int, int, int)
 DEF_HELPER_5(stf_asi, void, env, tl, int, int, int)
-DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32)
 DEF_HELPER_5(casx_asi, tl, env, tl, tl, tl, i32)
 DEF_HELPER_2(set_softint, void, env, i64)
 DEF_HELPER_2(clear_softint, void, env, i64)
@@ -31,6 +30,9 @@
 DEF_HELPER_1(tick_get_count, i64, ptr)
 DEF_HELPER_2(tick_set_limit, void, ptr, i64)
 #endif
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+DEF_HELPER_5(cas_asi, tl, env, tl, tl, tl, i32)
+#endif
 DEF_HELPER_3(check_align, void, env, tl, i32)
 DEF_HELPER_1(debug, void, env)
 DEF_HELPER_1(save, void, env)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 92761ad..32491b4 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -584,6 +584,7 @@
         }
         break;
     case 0xb: /* Supervisor data access */
+    case 0x80:
         switch (size) {
         case 1:
             ret = cpu_ldub_kernel(env, addr);
@@ -955,6 +956,7 @@
         }
         break;
     case 0xb: /* Supervisor data access */
+    case 0x80:
         switch (size) {
         case 1:
             cpu_stb_kernel(env, addr, val);
@@ -2232,20 +2234,6 @@
     }
 }
 
-target_ulong helper_cas_asi(CPUSPARCState *env, target_ulong addr,
-                            target_ulong val1, target_ulong val2, uint32_t asi)
-{
-    target_ulong ret;
-
-    val2 &= 0xffffffffUL;
-    ret = helper_ld_asi(env, addr, asi, 4, 0);
-    ret &= 0xffffffffUL;
-    if (val2 == ret) {
-        helper_st_asi(env, addr, val1 & 0xffffffffUL, asi, 4);
-    }
-    return ret;
-}
-
 target_ulong helper_casx_asi(CPUSPARCState *env, target_ulong addr,
                              target_ulong val1, target_ulong val2,
                              uint32_t asi)
@@ -2260,6 +2248,22 @@
 }
 #endif /* TARGET_SPARC64 */
 
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+target_ulong helper_cas_asi(CPUSPARCState *env, target_ulong addr,
+                            target_ulong val1, target_ulong val2, uint32_t asi)
+{
+    target_ulong ret;
+
+    val2 &= 0xffffffffUL;
+    ret = helper_ld_asi(env, addr, asi, 4, 0);
+    ret &= 0xffffffffUL;
+    if (val2 == ret) {
+        helper_st_asi(env, addr, val1 & 0xffffffffUL, asi, 4);
+    }
+    return ret;
+}
+#endif /* !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64) */
+
 void helper_ldqf(CPUSPARCState *env, target_ulong addr, int mem_idx)
 {
     /* XXX add 128 bit load */
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 6150b22..46d7859 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -2107,18 +2107,6 @@
     tcg_temp_free_i64(t64);
 }
 
-static inline void gen_cas_asi(DisasContext *dc, TCGv addr,
-                               TCGv val2, int insn, int rd)
-{
-    TCGv val1 = gen_load_gpr(dc, rd);
-    TCGv dst = gen_dest_gpr(dc, rd);
-    TCGv_i32 r_asi = gen_get_asi(insn, addr);
-
-    gen_helper_cas_asi(dst, cpu_env, addr, val1, val2, r_asi);
-    tcg_temp_free_i32(r_asi);
-    gen_store_gpr(dc, rd, dst);
-}
-
 static inline void gen_casx_asi(DisasContext *dc, TCGv addr,
                                 TCGv val2, int insn, int rd)
 {
@@ -2229,6 +2217,22 @@
 #endif
 
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+static inline void gen_cas_asi(DisasContext *dc, TCGv addr,
+                               TCGv val2, int insn, int rd)
+{
+    TCGv val1 = gen_load_gpr(dc, rd);
+    TCGv dst = gen_dest_gpr(dc, rd);
+#ifdef TARGET_SPARC64
+    TCGv_i32 r_asi = gen_get_asi(insn, addr);
+#else
+    TCGv_i32 r_asi = tcg_const_i32(GET_FIELD(insn, 19, 26));
+#endif
+
+    gen_helper_cas_asi(dst, cpu_env, addr, val1, val2, r_asi);
+    tcg_temp_free_i32(r_asi);
+    gen_store_gpr(dc, rd, dst);
+}
+
 static inline void gen_ldstub_asi(TCGv dst, TCGv addr, int insn)
 {
     TCGv_i64 r_val;
@@ -5103,11 +5107,6 @@
                     }
                     gen_stf_asi(cpu_addr, insn, 8, DFPREG(rd));
                     break;
-                case 0x3c: /* V9 casa */
-                    rs2 = GET_FIELD(insn, 27, 31);
-                    cpu_src2 = gen_load_gpr(dc, rs2);
-                    gen_cas_asi(dc, cpu_addr, cpu_src2, insn, rd);
-                    break;
                 case 0x3e: /* V9 casxa */
                     rs2 = GET_FIELD(insn, 27, 31);
                     cpu_src2 = gen_load_gpr(dc, rs2);
@@ -5120,6 +5119,22 @@
                 case 0x37: /* stdc */
                     goto ncp_insn;
 #endif
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+                case 0x3c: /* V9 or LEON3 casa */
+#ifndef TARGET_SPARC64
+                    CHECK_IU_FEATURE(dc, CASA);
+                    if (IS_IMM) {
+                        goto illegal_insn;
+                    }
+                    if (!supervisor(dc)) {
+                        goto priv_insn;
+                    }
+#endif
+                    rs2 = GET_FIELD(insn, 27, 31);
+                    cpu_src2 = gen_load_gpr(dc, rs2);
+                    gen_cas_asi(dc, cpu_addr, cpu_src2, insn, rd);
+                    break;
+#endif
                 default:
                     goto illegal_insn;
                 }
diff --git a/tests/Makefile b/tests/Makefile
index b17d41e..471b4c8 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -35,6 +35,7 @@
 check-unit-y += tests/test-iov$(EXESUF)
 gcov-files-test-iov-y = util/iov.c
 check-unit-y += tests/test-aio$(EXESUF)
+check-unit-y += tests/test-rfifolock$(EXESUF)
 check-unit-y += tests/test-throttle$(EXESUF)
 gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c
 gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c
@@ -69,9 +70,24 @@
 check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
 gcov-files-ipack-y += hw/char/ipoctal232.c
 
+check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF)
+gcov-files-virtioserial-y += hw/char/virtio-console.c
+
 gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio.c
 check-qtest-virtio-y += tests/virtio-net-test$(EXESUF)
 gcov-files-virtio-y += i386-softmmu/hw/net/virtio-net.c
+check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF)
+gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-balloon.c
+check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF)
+gcov-files-virtio-y += i386-softmmu/hw/block/virtio-blk.c
+check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF)
+gcov-files-virtio-y += hw/virtio/virtio-rng.c
+check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF)
+gcov-files-virtio-y += i386-softmmu/hw/scsi/virtio-scsi.c
+check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF)
+gcov-files-virtio-y += i386-softmmu/hw/char/virtio-serial-bus.c
+check-qtest-virtio-y += $(check-qtest-virtioserial-y)
+gcov-files-virtio-y += $(gcov-files-virtioserial-y)
 
 check-qtest-pci-y += tests/e1000-test$(EXESUF)
 gcov-files-pci-y += hw/net/e1000.c
@@ -87,9 +103,9 @@
 check-qtest-pci-y += $(check-qtest-virtio-y)
 gcov-files-pci-y += $(gcov-files-virtio-y) hw/virtio/virtio-pci.c
 check-qtest-pci-y += tests/tpci200-test$(EXESUF)
-gcov-files-pci-y += hw/char/tpci200.c
+gcov-files-pci-y += hw/ipack/tpci200.c
 check-qtest-pci-y += $(check-qtest-ipack-y)
-gcov-files-pci-y += $(gcov-files-ipack-y) hw/ipack/tpci200.c
+gcov-files-pci-y += $(gcov-files-ipack-y)
 
 check-qtest-i386-y = tests/endianness-test$(EXESUF)
 check-qtest-i386-y += tests/fdc-test$(EXESUF)
@@ -129,6 +145,8 @@
 gcov-files-arm-y += hw/misc/tmp105.c
 check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
 check-qtest-ppc64-y += tests/boot-order-test$(EXESUF)
+check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF)
+gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c
 check-qtest-microblazeel-y = $(check-qtest-microblaze-y)
 check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
 
@@ -142,7 +160,11 @@
         missing-comma-object.json non-objects.json \
         qapi-schema-test.json quoted-structural-chars.json \
         trailing-comma-list.json trailing-comma-object.json \
-        unclosed-list.json unclosed-object.json unclosed-string.json)
+        unclosed-list.json unclosed-object.json unclosed-string.json \
+        duplicate-key.json union-invalid-base.json flat-union-no-base.json \
+        flat-union-invalid-discriminator.json \
+        flat-union-invalid-branch-key.json flat-union-reverse-define.json \
+        flat-union-string-discriminator.json)
 
 GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
 
@@ -172,6 +194,7 @@
 tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(qom-core-obj) libqemuutil.a libqemustub.a
 tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil.a libqemustub.a
 tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a
+tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o libqemuutil.a libqemustub.a
 tests/test-throttle$(EXESUF): tests/test-throttle.o $(block-obj-y) libqemuutil.a libqemustub.a
 tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a
 tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a
@@ -221,6 +244,7 @@
 tests/rtc-test$(EXESUF): tests/rtc-test.o
 tests/m48t59-test$(EXESUF): tests/m48t59-test.o
 tests/endianness-test$(EXESUF): tests/endianness-test.o
+tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
 tests/fdc-test$(EXESUF): tests/fdc-test.o
 tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
 tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
@@ -235,7 +259,13 @@
 tests/eepro100-test$(EXESUF): tests/eepro100-test.o
 tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
 tests/ne2000-test$(EXESUF): tests/ne2000-test.o
+tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o
+tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o
 tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o
+tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o
+tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o
+tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o
+tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o
 tests/tpci200-test$(EXESUF): tests/tpci200-test.o
 tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
 tests/qom-test$(EXESUF): tests/qom-test.o
diff --git a/tests/acpi-test-data/pc/SSDT b/tests/acpi-test-data/pc/SSDT
index c1a4589..ae5a9a5 100644
--- a/tests/acpi-test-data/pc/SSDT
+++ b/tests/acpi-test-data/pc/SSDT
Binary files differ
diff --git a/tests/acpi-test-data/q35/SSDT b/tests/acpi-test-data/q35/SSDT
index 9915dbe..634b481 100644
--- a/tests/acpi-test-data/q35/SSDT
+++ b/tests/acpi-test-data/q35/SSDT
Binary files differ
diff --git a/tests/libqtest.c b/tests/libqtest.c
index f587d36..2b90e4a 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -34,6 +34,7 @@
 #include "qapi/qmp/json-parser.h"
 
 #define MAX_IRQ 256
+#define SOCKET_TIMEOUT 5
 
 QTestState *global_qtest;
 
@@ -78,12 +79,16 @@
     struct sockaddr_un addr;
     socklen_t addrlen;
     int ret;
+    struct timeval timeout = { .tv_sec = SOCKET_TIMEOUT,
+                               .tv_usec = 0 };
+
+    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout,
+               sizeof(timeout));
 
     addrlen = sizeof(addr);
     do {
         ret = accept(sock, (struct sockaddr *)&addr, &addrlen);
     } while (ret == -1 && errno == EINTR);
-    g_assert_no_errno(ret);
     close(sock);
 
     return ret;
@@ -147,12 +152,16 @@
     }
 
     s->fd = socket_accept(sock);
-    s->qmp_fd = socket_accept(qmpsock);
+    if (s->fd >= 0) {
+        s->qmp_fd = socket_accept(qmpsock);
+    }
     unlink(socket_path);
     unlink(qmp_socket_path);
     g_free(socket_path);
     g_free(qmp_socket_path);
 
+    g_assert(s->fd >= 0 && s->qmp_fd >= 0);
+
     s->rx = g_string_new("");
     for (i = 0; i < MAX_IRQ; i++) {
         s->irq_level[i] = false;
@@ -581,3 +590,23 @@
     qtest_sendf(s, "\n");
     qtest_rsp(s, 0);
 }
+
+QDict *qmp(const char *fmt, ...)
+{
+    va_list ap;
+    QDict *response;
+
+    va_start(ap, fmt);
+    response = qtest_qmpv(global_qtest, fmt, ap);
+    va_end(ap);
+    return response;
+}
+
+void qmp_discard_response(const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    qtest_qmpv_discard_response(global_qtest, fmt, ap);
+    va_end(ap);
+}
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 9deebdc..8268c09 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -356,16 +356,7 @@
  *
  * Sends a QMP message to QEMU and returns the response.
  */
-static inline QDict *qmp(const char *fmt, ...)
-{
-    va_list ap;
-    QDict *response;
-
-    va_start(ap, fmt);
-    response = qtest_qmpv(global_qtest, fmt, ap);
-    va_end(ap);
-    return response;
-}
+QDict *qmp(const char *fmt, ...);
 
 /**
  * qmp_discard_response:
@@ -373,14 +364,7 @@
  *
  * Sends a QMP message to QEMU and consumes the response.
  */
-static inline void qmp_discard_response(const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start(ap, fmt);
-    qtest_qmpv_discard_response(global_qtest, fmt, ap);
-    va_end(ap);
-}
+void qmp_discard_response(const char *fmt, ...);
 
 /**
  * get_irq:
diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
index e3bd904..4ce3dcf 100644
--- a/tests/qapi-schema/comments.out
+++ b/tests/qapi-schema/comments.out
@@ -1,3 +1,3 @@
 [OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
-['Status']
+[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
 []
diff --git a/tests/qapi-schema/duplicate-key.err b/tests/qapi-schema/duplicate-key.err
new file mode 100644
index 0000000..0801c6a
--- /dev/null
+++ b/tests/qapi-schema/duplicate-key.err
@@ -0,0 +1 @@
+<stdin>:2:10: Duplicate key "key"
diff --git a/tests/qapi-schema/duplicate-key.exit b/tests/qapi-schema/duplicate-key.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/duplicate-key.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/duplicate-key.json b/tests/qapi-schema/duplicate-key.json
new file mode 100644
index 0000000..1b55d88
--- /dev/null
+++ b/tests/qapi-schema/duplicate-key.json
@@ -0,0 +1,2 @@
+{ 'key': 'value',
+  'key': 'value' }
diff --git a/tests/qapi-schema/duplicate-key.out b/tests/qapi-schema/duplicate-key.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/qapi-schema/duplicate-key.out
diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.err b/tests/qapi-schema/flat-union-invalid-branch-key.err
new file mode 100644
index 0000000..1125caf
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-branch-key.err
@@ -0,0 +1 @@
+<stdin>:13: Discriminator value 'value_wrong' is not found in enum 'TestEnum'
diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.exit b/tests/qapi-schema/flat-union-invalid-branch-key.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-branch-key.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.json b/tests/qapi-schema/flat-union-invalid-branch-key.json
new file mode 100644
index 0000000..a624282
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-branch-key.json
@@ -0,0 +1,17 @@
+{ 'enum': 'TestEnum',
+  'data': [ 'value1', 'value2' ] }
+
+{ 'type': 'TestBase',
+  'data': { 'enum1': 'TestEnum' } }
+
+{ 'type': 'TestTypeA',
+  'data': { 'string': 'str' } }
+
+{ 'type': 'TestTypeB',
+  'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+  'base': 'TestBase',
+  'discriminator': 'enum1',
+  'data': { 'value_wrong': 'TestTypeA',
+            'value2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/flat-union-invalid-branch-key.out b/tests/qapi-schema/flat-union-invalid-branch-key.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-branch-key.out
diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.err b/tests/qapi-schema/flat-union-invalid-discriminator.err
new file mode 100644
index 0000000..cad9dbf
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-discriminator.err
@@ -0,0 +1 @@
+<stdin>:13: Discriminator 'enum_wrong' is not a member of base type 'TestBase'
diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.exit b/tests/qapi-schema/flat-union-invalid-discriminator.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-discriminator.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.json b/tests/qapi-schema/flat-union-invalid-discriminator.json
new file mode 100644
index 0000000..887157e
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-discriminator.json
@@ -0,0 +1,17 @@
+{ 'enum': 'TestEnum',
+  'data': [ 'value1', 'value2' ] }
+
+{ 'type': 'TestBase',
+  'data': { 'enum1': 'TestEnum' } }
+
+{ 'type': 'TestTypeA',
+  'data': { 'string': 'str' } }
+
+{ 'type': 'TestTypeB',
+  'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+  'base': 'TestBase',
+  'discriminator': 'enum_wrong',
+  'data': { 'value1': 'TestTypeA',
+            'value2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/flat-union-invalid-discriminator.out b/tests/qapi-schema/flat-union-invalid-discriminator.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/qapi-schema/flat-union-invalid-discriminator.out
diff --git a/tests/qapi-schema/flat-union-no-base.err b/tests/qapi-schema/flat-union-no-base.err
new file mode 100644
index 0000000..e2d7443
--- /dev/null
+++ b/tests/qapi-schema/flat-union-no-base.err
@@ -0,0 +1 @@
+<stdin>:7: Flat union 'TestUnion' must have a base field
diff --git a/tests/qapi-schema/flat-union-no-base.exit b/tests/qapi-schema/flat-union-no-base.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/flat-union-no-base.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-no-base.json b/tests/qapi-schema/flat-union-no-base.json
new file mode 100644
index 0000000..50f2673
--- /dev/null
+++ b/tests/qapi-schema/flat-union-no-base.json
@@ -0,0 +1,10 @@
+{ 'type': 'TestTypeA',
+  'data': { 'string': 'str' } }
+
+{ 'type': 'TestTypeB',
+  'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+  'discriminator': 'enum1',
+  'data': { 'value1': 'TestTypeA',
+            'value2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/flat-union-no-base.out b/tests/qapi-schema/flat-union-no-base.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/qapi-schema/flat-union-no-base.out
diff --git a/tests/qapi-schema/flat-union-reverse-define.err b/tests/qapi-schema/flat-union-reverse-define.err
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/qapi-schema/flat-union-reverse-define.err
diff --git a/tests/qapi-schema/flat-union-reverse-define.exit b/tests/qapi-schema/flat-union-reverse-define.exit
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/tests/qapi-schema/flat-union-reverse-define.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/flat-union-reverse-define.json b/tests/qapi-schema/flat-union-reverse-define.json
new file mode 100644
index 0000000..9ea7e72
--- /dev/null
+++ b/tests/qapi-schema/flat-union-reverse-define.json
@@ -0,0 +1,17 @@
+{ 'union': 'TestUnion',
+  'base': 'TestBase',
+  'discriminator': 'enum1',
+  'data': { 'value1': 'TestTypeA',
+            'value2': 'TestTypeB' } }
+
+{ 'type': 'TestBase',
+  'data': { 'enum1': 'TestEnum' } }
+
+{ 'enum': 'TestEnum',
+  'data': [ 'value1', 'value2' ] }
+
+{ 'type': 'TestTypeA',
+  'data': { 'string': 'str' } }
+
+{ 'type': 'TestTypeB',
+  'data': { 'integer': 'int' } }
diff --git a/tests/qapi-schema/flat-union-reverse-define.out b/tests/qapi-schema/flat-union-reverse-define.out
new file mode 100644
index 0000000..03c952e
--- /dev/null
+++ b/tests/qapi-schema/flat-union-reverse-define.out
@@ -0,0 +1,9 @@
+[OrderedDict([('union', 'TestUnion'), ('base', 'TestBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'TestTypeA'), ('value2', 'TestTypeB')]))]),
+ OrderedDict([('type', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]),
+ OrderedDict([('enum', 'TestEnum'), ('data', ['value1', 'value2'])]),
+ OrderedDict([('type', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]),
+ OrderedDict([('type', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])]
+[{'enum_name': 'TestEnum', 'enum_values': ['value1', 'value2']}]
+[OrderedDict([('type', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]),
+ OrderedDict([('type', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]),
+ OrderedDict([('type', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])]
diff --git a/tests/qapi-schema/flat-union-string-discriminator.err b/tests/qapi-schema/flat-union-string-discriminator.err
new file mode 100644
index 0000000..8748270
--- /dev/null
+++ b/tests/qapi-schema/flat-union-string-discriminator.err
@@ -0,0 +1 @@
+<stdin>:13: Discriminator 'kind' must be of enumeration type
diff --git a/tests/qapi-schema/flat-union-string-discriminator.exit b/tests/qapi-schema/flat-union-string-discriminator.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/flat-union-string-discriminator.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/flat-union-string-discriminator.json b/tests/qapi-schema/flat-union-string-discriminator.json
new file mode 100644
index 0000000..e966aeb
--- /dev/null
+++ b/tests/qapi-schema/flat-union-string-discriminator.json
@@ -0,0 +1,17 @@
+{ 'enum': 'TestEnum',
+  'data': [ 'value1', 'value2' ] }
+
+{ 'type': 'TestBase',
+  'data': { 'enum1': 'TestEnum', 'kind': 'str' } }
+
+{ 'type': 'TestTypeA',
+  'data': { 'string': 'str' } }
+
+{ 'type': 'TestTypeB',
+  'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+  'base': 'TestBase',
+  'discriminator': 'kind',
+  'data': { 'kind1': 'TestTypeA',
+            'kind2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/flat-union-string-discriminator.out b/tests/qapi-schema/flat-union-string-discriminator.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/qapi-schema/flat-union-string-discriminator.out
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
index 471ba47..818c06d 100644
--- a/tests/qapi-schema/qapi-schema-test.json
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -37,10 +37,13 @@
   'base': 'UserDefZero',
   'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } }
 
+{ 'type': 'UserDefUnionBase',
+  'data': { 'string': 'str', 'enum1': 'EnumOne' } }
+
 { 'union': 'UserDefFlatUnion',
-  'base': 'UserDefOne',
-  'discriminator': 'string',
-  'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } }
+  'base': 'UserDefUnionBase',
+  'discriminator': 'enum1',
+  'data': { 'value1' : 'UserDefA', 'value2' : 'UserDefB', 'value3' : 'UserDefB' } }
 # FIXME generated struct UserDefFlatUnion has members for direct base
 # UserDefOne, but lacks members for indirect base UserDefZero
 
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
index 89b53d4..6cd03f3 100644
--- a/tests/qapi-schema/qapi-schema-test.out
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -7,7 +7,8 @@
  OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
  OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
  OrderedDict([('union', 'UserDefUnion'), ('base', 'UserDefZero'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]),
- OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefOne'), ('discriminator', 'string'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]),
+ OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
+ OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]),
  OrderedDict([('union', 'UserDefAnonUnion'), ('discriminator', OrderedDict()), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]),
  OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str'])]))]),
  OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]),
@@ -15,11 +16,10 @@
  OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]),
  OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]),
  OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])]
-['EnumOne',
- 'UserDefUnionKind',
- 'UserDefFlatUnionKind',
- 'UserDefAnonUnionKind',
- 'UserDefNativeListUnionKind']
+[{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']},
+ {'enum_name': 'UserDefUnionKind', 'enum_values': None},
+ {'enum_name': 'UserDefAnonUnionKind', 'enum_values': None},
+ {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}]
 [OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
  OrderedDict([('type', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
  OrderedDict([('type', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
@@ -27,4 +27,5 @@
  OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]),
  OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
  OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
+ OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
  OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))])]
diff --git a/tests/qapi-schema/union-invalid-base.err b/tests/qapi-schema/union-invalid-base.err
new file mode 100644
index 0000000..dd8e3d1
--- /dev/null
+++ b/tests/qapi-schema/union-invalid-base.err
@@ -0,0 +1 @@
+<stdin>:7: Base 'TestBaseWrong' is not a valid type
diff --git a/tests/qapi-schema/union-invalid-base.exit b/tests/qapi-schema/union-invalid-base.exit
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/tests/qapi-schema/union-invalid-base.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/union-invalid-base.json b/tests/qapi-schema/union-invalid-base.json
new file mode 100644
index 0000000..1fa4930
--- /dev/null
+++ b/tests/qapi-schema/union-invalid-base.json
@@ -0,0 +1,10 @@
+{ 'type': 'TestTypeA',
+  'data': { 'string': 'str' } }
+
+{ 'type': 'TestTypeB',
+  'data': { 'integer': 'int' } }
+
+{ 'union': 'TestUnion',
+  'base': 'TestBaseWrong',
+  'data': { 'value1': 'TestTypeA',
+            'value2': 'TestTypeB' } }
diff --git a/tests/qapi-schema/union-invalid-base.out b/tests/qapi-schema/union-invalid-base.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/qapi-schema/union-invalid-base.out
diff --git a/tests/qdev-monitor-test.c b/tests/qdev-monitor-test.c
index ba7f9cc..e20ffd6 100644
--- a/tests/qdev-monitor-test.c
+++ b/tests/qdev-monitor-test.c
@@ -32,8 +32,7 @@
                    "}}");
     g_assert(response);
     error = qdict_get_qdict(response, "error");
-    g_assert(!strcmp(qdict_get_try_str(error, "desc") ?: "",
-                     "Device needs media, but drive is empty"));
+    g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, "GenericError");
     QDECREF(response);
 
     /* Delete the drive */
@@ -42,7 +41,7 @@
                    "   \"command-line\": \"drive_del drive0\""
                    "}}");
     g_assert(response);
-    g_assert(!strcmp(qdict_get_try_str(response, "return") ?: "(null)", ""));
+    g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "");
     QDECREF(response);
 
     /* Try to re-add the drive.  This fails with duplicate IDs if a leaked
@@ -53,8 +52,7 @@
                    "   \"command-line\": \"drive_add pci-addr=auto if=none,id=drive0\""
                    "}}");
     g_assert(response);
-    g_assert(!strcmp(qdict_get_try_str(response, "return") ?: "",
-                     "OK\r\n"));
+    g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "OK\r\n");
     QDECREF(response);
 
     qtest_end();
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
index af8ed9f..f0116aa 100755
--- a/tests/qemu-iotests/060
+++ b/tests/qemu-iotests/060
@@ -138,6 +138,32 @@
 _check_test_img
 $QEMU_IO -c "$OPEN_RO" -c "read -P 1 0 512" | _filter_qemu_io
 
+echo
+echo "=== Testing overlap while COW is in flight ==="
+echo
+# compat=0.10 is required in order to make the following discard actually
+# unallocate the sector rather than make it a zero sector - we want COW, after
+# all.
+IMGOPTS='compat=0.10' _make_test_img 1G
+# Write two clusters, the second one enforces creation of an L2 table after
+# the first data cluster.
+$QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io
+# Discard the first cluster. This cluster will soon enough be reallocated and
+# used for COW.
+$QEMU_IO -c 'discard 0k 64k' "$TEST_IMG" | _filter_qemu_io
+# Now, corrupt the image by marking the second L2 table cluster as free.
+poke_file "$TEST_IMG" '131084' "\x00\x00" # 0x2000c
+# Start a write operation requiring COW on the image stopping it right before
+# doing the read; then, trigger the corruption prevention by writing anything to
+# any unallocated cluster, leading to an attempt to overwrite the second L2
+# table. Finally, resume the COW write and see it fail (but not crash).
+echo "open -o file.driver=blkdebug $TEST_IMG
+break cow_read 0
+aio_write 0k 1k
+wait_break 0
+write 64k 64k
+resume 0" | $QEMU_IO | _filter_qemu_io
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
index 6c7bdbb..a517948 100644
--- a/tests/qemu-iotests/060.out
+++ b/tests/qemu-iotests/060.out
@@ -78,4 +78,19 @@
 No errors were found on the image.
 read 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Testing overlap while COW is in flight ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 536870912
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+discard 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qcow2: Preventing invalid write on metadata (overlaps with active L2 table); image marked as corrupt.
+blkdebug: Suspended request '0'
+write failed: Input/output error
+blkdebug: Resuming request '0'
+aio_write failed: No medium found
 *** done
diff --git a/tests/qom-test.c b/tests/qom-test.c
index b6671fb..6d9a00b 100644
--- a/tests/qom-test.c
+++ b/tests/qom-test.c
@@ -10,6 +10,7 @@
 #include <glib.h>
 #include <string.h>
 
+#include "qemu-common.h"
 #include "libqtest.h"
 #include "qemu/osdep.h"
 #include "qapi/qmp/types.h"
@@ -43,6 +44,40 @@
     return false;
 }
 
+static void test_properties(const char *path)
+{
+    char *child_path;
+    QDict *response, *tuple;
+    QList *list;
+    QListEntry *entry;
+
+    g_test_message("Obtaining properties of %s", path);
+    response = qmp("{ 'execute': 'qom-list',"
+                   "  'arguments': { 'path': '%s' } }", path);
+    g_assert(response);
+
+    g_assert(qdict_haskey(response, "return"));
+    list = qobject_to_qlist(qdict_get(response, "return"));
+    QLIST_FOREACH_ENTRY(list, entry) {
+        tuple = qobject_to_qdict(qlist_entry_obj(entry));
+        if (strstart(qdict_get_str(tuple, "type"), "child<", NULL)) {
+            child_path = g_strdup_printf("%s/%s",
+                                         path, qdict_get_str(tuple, "name"));
+            test_properties(child_path);
+            g_free(child_path);
+        } else {
+            const char *prop = qdict_get_str(tuple, "name");
+            g_test_message("Testing property %s.%s", path, prop);
+            response = qmp("{ 'execute': 'qom-get',"
+                           "  'arguments': { 'path': '%s',"
+                           "                 'property': '%s' } }",
+                           path, prop);
+            /* qom-get may fail but should not, e.g., segfault. */
+            g_assert(response);
+        }
+    }
+}
+
 static void test_machine(gconstpointer data)
 {
     const char *machine = data;
@@ -51,8 +86,12 @@
 
     args = g_strdup_printf("-machine %s", machine);
     qtest_start(args);
+
+    test_properties("/machine");
+
     response = qmp("{ 'execute': 'quit' }");
     g_assert(qdict_haskey(response, "return"));
+
     qtest_end();
     g_free(args);
 }
diff --git a/tests/spapr-phb-test.c b/tests/spapr-phb-test.c
new file mode 100644
index 0000000..b629de4
--- /dev/null
+++ b/tests/spapr-phb-test.c
@@ -0,0 +1,35 @@
+/*
+ * QTest testcase for SPAPR PHB
+ *
+ * Authors:
+ *  Alexey Kardashevskiy <aik@ozlabs.ru>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <glib.h>
+
+#include "libqtest.h"
+
+#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void test_phb_device(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/spapr-phb/device", test_phb_device);
+
+    qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=100");
+
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/test-aio.c b/tests/test-aio.c
index 592721e..56f4288 100644
--- a/tests/test-aio.c
+++ b/tests/test-aio.c
@@ -112,6 +112,64 @@
     g_assert(!aio_poll(ctx, false));
 }
 
+typedef struct {
+    QemuMutex start_lock;
+    bool thread_acquired;
+} AcquireTestData;
+
+static void *test_acquire_thread(void *opaque)
+{
+    AcquireTestData *data = opaque;
+
+    /* Wait for other thread to let us start */
+    qemu_mutex_lock(&data->start_lock);
+    qemu_mutex_unlock(&data->start_lock);
+
+    aio_context_acquire(ctx);
+    aio_context_release(ctx);
+
+    data->thread_acquired = true; /* success, we got here */
+
+    return NULL;
+}
+
+static void dummy_notifier_read(EventNotifier *unused)
+{
+    g_assert(false); /* should never be invoked */
+}
+
+static void test_acquire(void)
+{
+    QemuThread thread;
+    EventNotifier notifier;
+    AcquireTestData data;
+
+    /* Dummy event notifier ensures aio_poll() will block */
+    event_notifier_init(&notifier, false);
+    aio_set_event_notifier(ctx, &notifier, dummy_notifier_read);
+    g_assert(!aio_poll(ctx, false)); /* consume aio_notify() */
+
+    qemu_mutex_init(&data.start_lock);
+    qemu_mutex_lock(&data.start_lock);
+    data.thread_acquired = false;
+
+    qemu_thread_create(&thread, "test_acquire_thread",
+                       test_acquire_thread,
+                       &data, QEMU_THREAD_JOINABLE);
+
+    /* Block in aio_poll(), let other thread kick us and acquire context */
+    aio_context_acquire(ctx);
+    qemu_mutex_unlock(&data.start_lock); /* let the thread run */
+    g_assert(!aio_poll(ctx, true));
+    aio_context_release(ctx);
+
+    qemu_thread_join(&thread);
+    aio_set_event_notifier(ctx, &notifier, NULL);
+    event_notifier_cleanup(&notifier);
+
+    g_assert(data.thread_acquired);
+}
+
 static void test_bh_schedule(void)
 {
     BHTestData data = { .n = 0 };
@@ -775,6 +833,7 @@
 
     g_test_init(&argc, &argv, NULL);
     g_test_add_func("/aio/notify",                  test_notify);
+    g_test_add_func("/aio/acquire",                 test_acquire);
     g_test_add_func("/aio/bh/schedule",             test_bh_schedule);
     g_test_add_func("/aio/bh/schedule10",           test_bh_schedule10);
     g_test_add_func("/aio/bh/cancel",               test_bh_cancel);
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 8e62c2d..554e222 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -141,7 +141,7 @@
 
     ret3 = qobject_to_qint(test_qmp_dispatch(req));
     assert(qint_get_int(ret3) == 66);
-    QDECREF(ret);
+    QDECREF(ret3);
 
     QDECREF(req);
 }
diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
index 64d72f6..38b5e95 100644
--- a/tests/test-qmp-input-strict.c
+++ b/tests/test-qmp-input-strict.c
@@ -146,7 +146,10 @@
     Visitor *v;
     Error *errp = NULL;
 
-    v = validate_test_init(data, "{ 'string': 'a', 'boolean': true }");
+    v = validate_test_init(data,
+                           "{ 'enum1': 'value1', "
+                           "'string': 'str', "
+                           "'boolean': true }");
     /* TODO when generator bug is fixed, add 'integer': 41 */
 
     visit_type_UserDefFlatUnion(v, &tmp, NULL, &errp);
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index 2dffafc..1729667 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -310,14 +310,18 @@
     Error *err = NULL;
     UserDefFlatUnion *tmp;
 
-    v = visitor_input_test_init(data, "{ 'string': 'a', 'boolean': true }");
+    v = visitor_input_test_init(data,
+                                "{ 'enum1': 'value1', "
+                                "'string': 'str', "
+                                "'boolean': true }");
     /* TODO when generator bug is fixed, add 'integer': 41 */
 
     visit_type_UserDefFlatUnion(v, &tmp, NULL, &err);
     g_assert(err == NULL);
-    g_assert_cmpint(tmp->kind, ==, USER_DEF_UNION_KIND_A);
+    g_assert_cmpint(tmp->kind, ==, ENUM_ONE_VALUE1);
+    g_assert_cmpstr(tmp->string, ==, "str");
     /* TODO g_assert_cmpint(tmp->integer, ==, 41); */
-    g_assert_cmpint(tmp->a->boolean, ==, true);
+    g_assert_cmpint(tmp->value1->boolean, ==, true);
     qapi_free_UserDefFlatUnion(tmp);
 }
 
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index 105f4cf..da27971 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -449,10 +449,11 @@
     Error *err = NULL;
 
     UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion));
-    tmp->kind = USER_DEF_UNION_KIND_A;
-    tmp->a = g_malloc0(sizeof(UserDefA));
+    tmp->kind = ENUM_ONE_VALUE1;
+    tmp->string = g_strdup("str");
+    tmp->value1 = g_malloc0(sizeof(UserDefA));
     /* TODO when generator bug is fixed: tmp->integer = 41; */
-    tmp->a->boolean = true;
+    tmp->value1->boolean = true;
 
     visit_type_UserDefFlatUnion(data->ov, &tmp, NULL, &err);
     g_assert(err == NULL);
@@ -461,7 +462,8 @@
     g_assert(qobject_type(arg) == QTYPE_QDICT);
     qdict = qobject_to_qdict(arg);
 
-    g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "a");
+    g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1");
+    g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str");
     /* TODO g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41); */
     g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true);
 
diff --git a/tests/test-rfifolock.c b/tests/test-rfifolock.c
new file mode 100644
index 0000000..0572ebb
--- /dev/null
+++ b/tests/test-rfifolock.c
@@ -0,0 +1,91 @@
+/*
+ * RFifoLock tests
+ *
+ * Copyright Red Hat, Inc. 2013
+ *
+ * Authors:
+ *  Stefan Hajnoczi    <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include <glib.h>
+#include "qemu-common.h"
+#include "qemu/rfifolock.h"
+
+static void test_nesting(void)
+{
+    RFifoLock lock;
+
+    /* Trivial test, ensure the lock is recursive */
+    rfifolock_init(&lock, NULL, NULL);
+    rfifolock_lock(&lock);
+    rfifolock_lock(&lock);
+    rfifolock_lock(&lock);
+    rfifolock_unlock(&lock);
+    rfifolock_unlock(&lock);
+    rfifolock_unlock(&lock);
+    rfifolock_destroy(&lock);
+}
+
+typedef struct {
+    RFifoLock lock;
+    int fd[2];
+} CallbackTestData;
+
+static void rfifolock_cb(void *opaque)
+{
+    CallbackTestData *data = opaque;
+    int ret;
+    char c = 0;
+
+    ret = write(data->fd[1], &c, sizeof(c));
+    g_assert(ret == 1);
+}
+
+static void *callback_thread(void *opaque)
+{
+    CallbackTestData *data = opaque;
+
+    /* The other thread holds the lock so the contention callback will be
+     * invoked...
+     */
+    rfifolock_lock(&data->lock);
+    rfifolock_unlock(&data->lock);
+    return NULL;
+}
+
+static void test_callback(void)
+{
+    CallbackTestData data;
+    QemuThread thread;
+    int ret;
+    char c;
+
+    rfifolock_init(&data.lock, rfifolock_cb, &data);
+    ret = qemu_pipe(data.fd);
+    g_assert(ret == 0);
+
+    /* Hold lock but allow the callback to kick us by writing to the pipe */
+    rfifolock_lock(&data.lock);
+    qemu_thread_create(&thread, "callback_thread",
+                       callback_thread, &data, QEMU_THREAD_JOINABLE);
+    ret = read(data.fd[0], &c, sizeof(c));
+    g_assert(ret == 1);
+    rfifolock_unlock(&data.lock);
+    /* If we got here then the callback was invoked, as expected */
+
+    qemu_thread_join(&thread);
+    close(data.fd[0]);
+    close(data.fd[1]);
+    rfifolock_destroy(&data.lock);
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    g_test_add_func("/nesting", test_nesting);
+    g_test_add_func("/callback", test_callback);
+    return g_test_run();
+}
diff --git a/tests/virtio-balloon-test.c b/tests/virtio-balloon-test.c
new file mode 100644
index 0000000..becebb5
--- /dev/null
+++ b/tests/virtio-balloon-test.c
@@ -0,0 +1,33 @@
+/*
+ * QTest testcase for VirtIO Balloon
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void pci_nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/virtio/balloon/pci/nop", pci_nop);
+
+    qtest_start("-device virtio-balloon-pci");
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
new file mode 100644
index 0000000..d53f875
--- /dev/null
+++ b/tests/virtio-blk-test.c
@@ -0,0 +1,34 @@
+/*
+ * QTest testcase for VirtIO Block Device
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void pci_nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/virtio/blk/pci/nop", pci_nop);
+
+    qtest_start("-drive id=drv0,if=none,file=/dev/null "
+                "-device virtio-blk-pci,drive=drv0");
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/virtio-console-test.c b/tests/virtio-console-test.c
new file mode 100644
index 0000000..f98f5af2
--- /dev/null
+++ b/tests/virtio-console-test.c
@@ -0,0 +1,34 @@
+/*
+ * QTest testcase for VirtIO Console
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void pci_nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/virtio/console/pci/nop", pci_nop);
+
+    qtest_start("-device virtio-serial-pci,id=vser0 "
+                "-device virtconsole,bus=vser0.0");
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/virtio-rng-test.c b/tests/virtio-rng-test.c
new file mode 100644
index 0000000..402c206
--- /dev/null
+++ b/tests/virtio-rng-test.c
@@ -0,0 +1,33 @@
+/*
+ * QTest testcase for VirtIO RNG
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void pci_nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/virtio/rng/pci/nop", pci_nop);
+
+    qtest_start("-device virtio-rng-pci");
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c
new file mode 100644
index 0000000..3230908
--- /dev/null
+++ b/tests/virtio-scsi-test.c
@@ -0,0 +1,35 @@
+/*
+ * QTest testcase for VirtIO SCSI
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void pci_nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/virtio/scsi/pci/nop", pci_nop);
+
+    qtest_start("-drive id=drv0,if=none,file=/dev/null "
+                "-device virtio-scsi-pci,id=vscsi0 "
+                "-device scsi-hd,bus=vscsi0.0,drive=drv0");
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c
new file mode 100644
index 0000000..e743875
--- /dev/null
+++ b/tests/virtio-serial-test.c
@@ -0,0 +1,33 @@
+/*
+ * QTest testcase for VirtIO Serial
+ *
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+/* Tests only initialization so far. TODO: Replace with functional tests */
+static void pci_nop(void)
+{
+}
+
+int main(int argc, char **argv)
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("/virtio/serial/pci/nop", pci_nop);
+
+    qtest_start("-device virtio-serial-pci");
+    ret = g_test_run();
+
+    qtest_end();
+
+    return ret;
+}
diff --git a/trace/control-internal.h b/trace/control-internal.h
index cce2da4..b3f587e 100644
--- a/trace/control-internal.h
+++ b/trace/control-internal.h
@@ -16,17 +16,17 @@
 extern TraceEvent trace_events[];
 
 
+static inline TraceEventID trace_event_count(void)
+{
+    return TRACE_EVENT_COUNT;
+}
+
 static inline TraceEvent *trace_event_id(TraceEventID id)
 {
     assert(id < trace_event_count());
     return &trace_events[id];
 }
 
-static inline TraceEventID trace_event_count(void)
-{
-    return TRACE_EVENT_COUNT;
-}
-
 static inline bool trace_event_is_pattern(const char *str)
 {
     assert(str != NULL);
diff --git a/util/Makefile.objs b/util/Makefile.objs
index 937376b..df83b62 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -14,3 +14,4 @@
 util-obj-y += throttle.o
 util-obj-y += getauxval.o
 util-obj-y += readline.o
+util-obj-y += rfifolock.o
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index c2eeb4f..8e9c770 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -63,6 +63,10 @@
 #include <sys/syscall.h>
 #endif
 
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+
 int qemu_get_thread_id(void)
 {
 #if defined(__linux__)
diff --git a/util/rfifolock.c b/util/rfifolock.c
new file mode 100644
index 0000000..afbf748
--- /dev/null
+++ b/util/rfifolock.c
@@ -0,0 +1,78 @@
+/*
+ * Recursive FIFO lock
+ *
+ * Copyright Red Hat, Inc. 2013
+ *
+ * Authors:
+ *  Stefan Hajnoczi   <stefanha@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <assert.h>
+#include "qemu/rfifolock.h"
+
+void rfifolock_init(RFifoLock *r, void (*cb)(void *), void *opaque)
+{
+    qemu_mutex_init(&r->lock);
+    r->head = 0;
+    r->tail = 0;
+    qemu_cond_init(&r->cond);
+    r->nesting = 0;
+    r->cb = cb;
+    r->cb_opaque = opaque;
+}
+
+void rfifolock_destroy(RFifoLock *r)
+{
+    qemu_cond_destroy(&r->cond);
+    qemu_mutex_destroy(&r->lock);
+}
+
+/*
+ * Theory of operation:
+ *
+ * In order to ensure FIFO ordering, implement a ticketlock.  Threads acquiring
+ * the lock enqueue themselves by incrementing the tail index.  When the lock
+ * is unlocked, the head is incremented and waiting threads are notified.
+ *
+ * Recursive locking does not take a ticket since the head is only incremented
+ * when the outermost recursive caller unlocks.
+ */
+void rfifolock_lock(RFifoLock *r)
+{
+    qemu_mutex_lock(&r->lock);
+
+    /* Take a ticket */
+    unsigned int ticket = r->tail++;
+
+    if (r->nesting > 0 && qemu_thread_is_self(&r->owner_thread)) {
+        r->tail--; /* put ticket back, we're nesting */
+    } else {
+        while (ticket != r->head) {
+            /* Invoke optional contention callback */
+            if (r->cb) {
+                r->cb(r->cb_opaque);
+            }
+            qemu_cond_wait(&r->cond, &r->lock);
+        }
+    }
+
+    qemu_thread_get_self(&r->owner_thread);
+    r->nesting++;
+    qemu_mutex_unlock(&r->lock);
+}
+
+void rfifolock_unlock(RFifoLock *r)
+{
+    qemu_mutex_lock(&r->lock);
+    assert(r->nesting > 0);
+    assert(qemu_thread_is_self(&r->owner_thread));
+    if (--r->nesting == 0) {
+        r->head++;
+        qemu_cond_broadcast(&r->cond);
+    }
+    qemu_mutex_unlock(&r->lock);
+}
diff --git a/vl.c b/vl.c
index bca5c95..862cf20 100644
--- a/vl.c
+++ b/vl.c
@@ -1571,54 +1571,82 @@
 /***********************************************************/
 /* machine registration */
 
-static QEMUMachine *first_machine = NULL;
-QEMUMachine *current_machine = NULL;
+MachineState *current_machine;
+
+static void machine_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->qemu_machine = data;
+}
 
 int qemu_register_machine(QEMUMachine *m)
 {
-    QEMUMachine **pm;
-    pm = &first_machine;
-    while (*pm != NULL)
-        pm = &(*pm)->next;
-    m->next = NULL;
-    *pm = m;
+    TypeInfo ti = {
+        .name       = g_strconcat(m->name, TYPE_MACHINE_SUFFIX, NULL),
+        .parent     = TYPE_MACHINE,
+        .class_init = machine_class_init,
+        .class_data = (void *)m,
+    };
+
+    type_register(&ti);
+
     return 0;
 }
 
-static QEMUMachine *find_machine(const char *name)
+static MachineClass *find_machine(const char *name)
 {
-    QEMUMachine *m;
+    GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false);
+    MachineClass *mc = NULL;
 
-    for(m = first_machine; m != NULL; m = m->next) {
-        if (!strcmp(m->name, name))
-            return m;
-        if (m->alias && !strcmp(m->alias, name))
-            return m;
-    }
-    return NULL;
-}
+    for (el = machines; el; el = el->next) {
+        MachineClass *temp = el->data;
 
-QEMUMachine *find_default_machine(void)
-{
-    QEMUMachine *m;
-
-    for(m = first_machine; m != NULL; m = m->next) {
-        if (m->is_default) {
-            return m;
+        if (!strcmp(temp->qemu_machine->name, name)) {
+            mc = temp;
+            break;
+        }
+        if (temp->qemu_machine->alias &&
+            !strcmp(temp->qemu_machine->alias, name)) {
+            mc = temp;
+            break;
         }
     }
-    return NULL;
+
+    g_slist_free(machines);
+    return mc;
+}
+
+MachineClass *find_default_machine(void)
+{
+    GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false);
+    MachineClass *mc = NULL;
+
+    for (el = machines; el; el = el->next) {
+        MachineClass *temp = el->data;
+
+        if (temp->qemu_machine->is_default) {
+            mc = temp;
+            break;
+        }
+    }
+
+    g_slist_free(machines);
+    return mc;
 }
 
 MachineInfoList *qmp_query_machines(Error **errp)
 {
+    GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false);
     MachineInfoList *mach_list = NULL;
     QEMUMachine *m;
 
-    for (m = first_machine; m; m = m->next) {
+    for (el = machines; el; el = el->next) {
+        MachineClass *mc = el->data;
         MachineInfoList *entry;
         MachineInfo *info;
 
+        m = mc->qemu_machine;
         info = g_malloc0(sizeof(*info));
         if (m->is_default) {
             info->has_is_default = true;
@@ -1639,6 +1667,7 @@
         mach_list = entry;
     }
 
+    g_slist_free(machines);
     return mach_list;
 }
 
@@ -1832,8 +1861,12 @@
 
 void qemu_system_reset(bool report)
 {
-    if (current_machine && current_machine->reset) {
-        current_machine->reset();
+    MachineClass *mc;
+
+    mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL;
+
+    if (mc && mc->qemu_machine->reset) {
+        mc->qemu_machine->reset();
     } else {
         qemu_devices_reset();
     }
@@ -2605,24 +2638,29 @@
     return 0;
 }
 
-static QEMUMachine *machine_parse(const char *name)
+static MachineClass *machine_parse(const char *name)
 {
-    QEMUMachine *m, *machine = NULL;
+    MachineClass *mc = NULL;
+    GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false);
 
     if (name) {
-        machine = find_machine(name);
+        mc = find_machine(name);
     }
-    if (machine) {
-        return machine;
+    if (mc) {
+        return mc;
     }
     printf("Supported machines are:\n");
-    for (m = first_machine; m != NULL; m = m->next) {
+    for (el = machines; el; el = el->next) {
+        MachineClass *mc = el->data;
+        QEMUMachine *m = mc->qemu_machine;
         if (m->alias) {
             printf("%-20s %s (alias of %s)\n", m->alias, m->desc, m->name);
         }
         printf("%-20s %s%s\n", m->name, m->desc,
                m->is_default ? " (default)" : "");
     }
+
+    g_slist_free(machines);
     exit(!name || !is_help_option(name));
 }
 
@@ -2871,6 +2909,7 @@
     int optind;
     const char *optarg;
     const char *loadvm = NULL;
+    MachineClass *machine_class;
     QEMUMachine *machine;
     const char *cpu_model;
     const char *vga_model = "none";
@@ -2945,7 +2984,7 @@
     os_setup_early_signal_handling();
 
     module_call_init(MODULE_INIT_MACHINE);
-    machine = find_default_machine();
+    machine_class = find_default_machine();
     cpu_model = NULL;
     ram_size = 0;
     snapshot = 0;
@@ -3011,7 +3050,7 @@
             }
             switch(popt->index) {
             case QEMU_OPTION_M:
-                machine = machine_parse(optarg);
+                machine_class = machine_parse(optarg);
                 break;
             case QEMU_OPTION_no_kvm_irqchip: {
                 olist = qemu_find_opts("machine");
@@ -3567,7 +3606,7 @@
                 }
                 optarg = qemu_opt_get(opts, "type");
                 if (optarg) {
-                    machine = machine_parse(optarg);
+                    machine_class = machine_parse(optarg);
                 }
                 break;
              case QEMU_OPTION_no_kvm:
@@ -3873,11 +3912,17 @@
     }
 #endif
 
-    if (machine == NULL) {
+    if (machine_class == NULL) {
         fprintf(stderr, "No machine found.\n");
         exit(1);
     }
 
+    current_machine = MACHINE(object_new(object_class_get_name(
+                          OBJECT_CLASS(machine_class))));
+    object_property_add_child(object_get_root(), "machine",
+                              OBJECT(current_machine), &error_abort);
+
+    machine = machine_class->qemu_machine;
     if (machine->hw_version) {
         qemu_set_version(machine->hw_version);
     }
@@ -4306,7 +4351,9 @@
                                  .kernel_cmdline = kernel_cmdline,
                                  .initrd_filename = initrd_filename,
                                  .cpu_model = cpu_model };
-    machine->init(&args);
+
+    current_machine->init_args = args;
+    machine->init(&current_machine->init_args);
 
     audio_init();
 
@@ -4314,8 +4361,6 @@
 
     set_numa_modes();
 
-    current_machine = machine;
-
     /* init USB devices */
     if (usb_enabled(false)) {
         if (foreach_device_config(DEV_USB, usb_parse) < 0)