summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS20
-rw-r--r--audio/audio.c2
-rw-r--r--audio/wavcapture.c1
-rw-r--r--block.c68
-rw-r--r--block/blkdebug.c8
-rw-r--r--block/blkverify.c11
-rw-r--r--block/crypto.c6
-rw-r--r--block/curl.c2
-rw-r--r--block/file-posix.c8
-rw-r--r--block/file-win32.c4
-rw-r--r--block/gluster.c48
-rw-r--r--block/nbd.c77
-rw-r--r--block/nfs.c43
-rw-r--r--block/null.c2
-rw-r--r--block/qcow2.c4
-rw-r--r--block/quorum.c16
-rw-r--r--block/rbd.c16
-rw-r--r--block/sheepdog.c20
-rw-r--r--block/snapshot.c2
-rw-r--r--block/ssh.c16
-rw-r--r--block/vvfat.c10
-rw-r--r--block/vxhs.c6
-rw-r--r--blockdev-nbd.c21
-rw-r--r--blockdev.c30
-rw-r--r--chardev/char-fd.c8
-rw-r--r--chardev/char-io.c23
-rw-r--r--chardev/char-io.h4
-rw-r--r--chardev/char-mux.c11
-rw-r--r--chardev/char-mux.h2
-rw-r--r--chardev/char-pty.c8
-rw-r--r--chardev/char-socket.c166
-rw-r--r--chardev/char-udp.c54
-rw-r--r--chardev/char.c161
-rwxr-xr-xconfigure2
-rw-r--r--contrib/libvhost-user/libvhost-user.c2
-rw-r--r--crypto/block-luks.c13
-rw-r--r--crypto/init.c6
-rw-r--r--crypto/random-gcrypt.c2
-rw-r--r--crypto/random-gnutls.c3
-rw-r--r--crypto/random-platform.c45
-rw-r--r--default-configs/s390x-softmmu.mak1
-rw-r--r--dump.c7
-rw-r--r--gdb-xml/i386-32bit-core.xml65
-rw-r--r--gdb-xml/i386-64bit-core.xml73
-rw-r--r--gdbstub.c112
-rw-r--r--hmp.c177
-rw-r--r--hmp.h4
-rw-r--r--hw/audio/Makefile.objs2
-rw-r--r--hw/audio/adlib.c47
-rw-r--r--hw/audio/fmopl.c277
-rw-r--r--hw/audio/fmopl.h175
-rw-r--r--hw/audio/gus.c2
-rw-r--r--hw/audio/gusemu.h22
-rw-r--r--hw/audio/gusemu_hal.c74
-rw-r--r--hw/audio/gusemu_mixer.c28
-rw-r--r--hw/audio/hda-codec.c3
-rw-r--r--hw/audio/intel-hda.c5
-rw-r--r--hw/audio/intel-hda.h2
-rw-r--r--hw/block/xen_disk.c2
-rw-r--r--hw/char/Makefile.objs1
-rw-r--r--hw/char/terminal3270.c293
-rw-r--r--hw/display/cg3.c2
-rw-r--r--hw/display/tcx.c1
-rw-r--r--hw/i386/acpi-build.c35
-rw-r--r--hw/input/hid.c4
-rw-r--r--hw/input/trace-events1
-rw-r--r--hw/openrisc/cputimer.c1
-rw-r--r--hw/pci-host/piix.c6
-rw-r--r--hw/pci/pcie_aer.c48
-rw-r--r--hw/s390x/3270-ccw.c174
-rw-r--r--hw/s390x/Makefile.objs1
-rw-r--r--hw/s390x/css.c24
-rw-r--r--hw/s390x/ipl.c39
-rw-r--r--hw/s390x/ipl.h3
-rw-r--r--hw/s390x/s390-virtio-ccw.c37
-rw-r--r--hw/s390x/sclp.c9
-rw-r--r--hw/scsi/Makefile.objs2
-rw-r--r--hw/scsi/megasas.c10
-rw-r--r--hw/scsi/vhost-scsi-common.c143
-rw-r--r--hw/scsi/vhost-scsi.c194
-rw-r--r--hw/scsi/vmw_pvscsi.c2
-rw-r--r--hw/usb/ccid-card-passthru.c2
-rw-r--r--hw/usb/redirect.c2
-rw-r--r--hw/usb/xen-usb.c12
-rw-r--r--hw/vfio/common.c14
-rw-r--r--hw/vfio/pci.c4
-rw-r--r--hw/xen/xen-common.c2
-rw-r--r--include/block/nbd.h3
-rw-r--r--include/crypto/block.h6
-rw-r--r--include/crypto/random.h9
-rw-r--r--include/exec/ram_addr.h13
-rw-r--r--include/hw/acpi/acpi-defs.h77
-rw-r--r--include/hw/i386/pc.h6
-rw-r--r--include/hw/pci/pcie_aer.h4
-rw-r--r--include/hw/s390x/3270-ccw.h53
-rw-r--r--include/hw/s390x/css.h2
-rw-r--r--include/hw/s390x/s390-virtio-ccw.h1
-rw-r--r--include/hw/virtio/vhost-scsi-common.h48
-rw-r--r--include/hw/virtio/vhost-scsi.h11
-rw-r--r--include/hw/virtio/virtio-scsi.h2
-rw-r--r--include/io/channel-socket.h4
-rw-r--r--include/migration/cpu.h7
-rw-r--r--include/migration/migration.h3
-rw-r--r--include/migration/vmstate.h18
-rw-r--r--include/qapi/clone-visitor.h14
-rw-r--r--include/qapi/qmp/qdict.h8
-rw-r--r--include/qapi/qmp/qlist.h8
-rw-r--r--include/qapi/visitor.h6
-rw-r--r--include/qemu/sockets.h16
-rw-r--r--include/sysemu/char.h20
-rw-r--r--include/sysemu/dump.h1
-rw-r--r--include/sysemu/sysemu.h5
-rw-r--r--io/dns-resolver.c17
-rw-r--r--linux-user/elfload.c2
-rw-r--r--linux-user/main.c18
-rw-r--r--linux-user/openrisc/target_cpu.h6
-rw-r--r--linux-user/openrisc/target_signal.h2
-rw-r--r--linux-user/signal.c17
-rw-r--r--migration/exec.c4
-rw-r--r--migration/migration.c2
-rw-r--r--migration/postcopy-ram.c7
-rw-r--r--migration/postcopy-ram.h (renamed from include/migration/postcopy-ram.h)3
-rw-r--r--migration/ram.c269
-rw-r--r--migration/rdma.c4
-rw-r--r--migration/savevm.c185
-rw-r--r--migration/socket.c21
-rw-r--r--migration/tls.c1
-rw-r--r--migration/trace-events2
-rw-r--r--monitor.c36
-rw-r--r--net/vhost-user.c2
-rw-r--r--pc-bios/s390-ccw.imgbin26456 -> 26472 bytes
-rw-r--r--pc-bios/s390-ccw/Makefile2
-rw-r--r--pc-bios/s390-ccw/bootmap.c34
-rw-r--r--pc-bios/s390-ccw/bootmap.h24
-rw-r--r--pc-bios/s390-ccw/main.c38
-rw-r--r--pc-bios/s390-ccw/s390-ccw.h17
-rw-r--r--pc-bios/s390-ccw/sclp.c (renamed from pc-bios/s390-ccw/sclp-ascii.c)12
-rw-r--r--pc-bios/s390-ccw/sclp.h2
-rw-r--r--pc-bios/sgabios.binbin4096 -> 4096 bytes
-rw-r--r--qapi-schema.json38
-rw-r--r--qapi/block-core.json6
-rw-r--r--qapi/block.json2
-rw-r--r--qapi/qapi-clone-visitor.c13
-rw-r--r--qapi/qmp-dispatch.c14
-rw-r--r--qapi/qmp-event.c2
-rw-r--r--qapi/qobject-input-visitor.c32
-rw-r--r--qemu-doc.texi50
-rw-r--r--qemu-img.c6
-rw-r--r--qemu-io.c2
-rw-r--r--qemu-nbd.c11
-rw-r--r--qemu-options.hx18
-rw-r--r--qemu.sasl54
-rw-r--r--qga/main.c4
-rw-r--r--qobject/qdict.c2
-rw-r--r--qom/container.c1
-rw-r--r--replay/replay-snapshot.c2
m---------roms/sgabios0
-rwxr-xr-xscripts/checkpatch.pl21
-rw-r--r--scripts/coccinelle/qobject.cocci35
-rwxr-xr-xscripts/get_maintainer.pl53
-rwxr-xr-xscripts/qmp/qmp-shell44
-rw-r--r--scripts/tracetool/__init__.py4
-rw-r--r--target/i386/cpu.c21
-rw-r--r--target/i386/hax-mem.c19
-rw-r--r--target/openrisc/cpu.c16
-rw-r--r--target/openrisc/cpu.h46
-rw-r--r--target/openrisc/gdbstub.c4
-rw-r--r--target/openrisc/interrupt.c11
-rw-r--r--target/openrisc/machine.c76
-rw-r--r--target/openrisc/mmu.c24
-rw-r--r--target/openrisc/sys_helper.c35
-rw-r--r--target/openrisc/translate.c5
-rw-r--r--target/s390x/cpu_models.c4
-rw-r--r--tcg/mips/tcg-target.inc.c4
-rw-r--r--tests/acpi-utils.h10
-rw-r--r--tests/bios-tables-test.c23
-rw-r--r--tests/check-qdict.c144
-rw-r--r--tests/check-qlist.c4
-rw-r--r--tests/device-introspect-test.c4
-rw-r--r--tests/fdc-test.c8
-rw-r--r--tests/libqtest.c8
-rw-r--r--tests/test-char.c365
-rw-r--r--tests/test-crypto-block.c6
-rw-r--r--tests/test-io-channel-socket.c52
-rw-r--r--tests/test-keyval.c4
-rw-r--r--tests/test-qemu-opts.c4
-rw-r--r--tests/test-qga.c41
-rw-r--r--tests/test-qmp-commands.c30
-rw-r--r--tests/test-qmp-event.c30
-rw-r--r--tests/test-qobject-output-visitor.c6
-rw-r--r--tests/vhost-user-test.c2
-rw-r--r--ui/console.c2
-rw-r--r--ui/gtk.c2
-rw-r--r--ui/input.c18
-rw-r--r--ui/vnc-auth-sasl.c5
-rw-r--r--ui/vnc.c68
-rw-r--r--util/qemu-config.c6
-rw-r--r--util/qemu-option.c6
-rw-r--r--util/qemu-sockets.c181
-rw-r--r--util/qemu-thread-posix.c18
-rw-r--r--util/qemu-thread-win32.c11
-rw-r--r--util/trace-events4
-rw-r--r--vl.c24
203 files changed, 3787 insertions, 2145 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index e79ffb3f8a..f8282f5122 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12,6 +12,8 @@ consult qemu-devel and not any specific individual privately.
 Descriptions of section entries:
 
 	M: Mail patches to: FullName <address@domain>
+	R: Designated reviewer: FullName <address@domain>
+	   These reviewers should be CCed on patches.
 	L: Mailing list that is relevant to this area
 	W: Web-page with status/info
 	Q: Patchwork web based patch tracking system site
@@ -196,8 +198,8 @@ F: hw/nios2/
 F: disas/nios2.c
 
 OpenRISC
-M: Jia Liu <proljc@gmail.com>
-S: Maintained
+M: Stafford Horne <shorne@gmail.com>
+S: Odd Fixes
 F: target/openrisc/
 F: hw/openrisc/
 F: tests/tcg/openrisc/
@@ -1393,6 +1395,7 @@ S: Supported
 F: qobject/
 F: include/qapi/qmp/
 X: include/qapi/qmp/dispatch.h
+F: scripts/coccinelle/qobject.cocci
 F: tests/check-qdict.c
 F: tests/check-qfloat.c
 F: tests/check-qint.c
@@ -1484,6 +1487,7 @@ S: Maintained
 F: crypto/
 F: include/crypto/
 F: tests/test-crypto-*
+F: qemu.sasl
 
 Coroutines
 M: Stefan Hajnoczi <stefanha@redhat.com>
@@ -1546,6 +1550,18 @@ F: net/colo*
 F: net/filter-rewriter.c
 F: net/filter-mirror.c
 
+Record/replay
+M: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
+R: Paolo Bonzini <pbonzini@redhat.com>
+W: http://wiki.qemu.org/Features/record-replay
+S: Supported
+F: replay/*
+F: block/blkreplay.c
+F: net/filter-replay.c
+F: include/sysemu/replay.h
+F: docs/replay.txt
+F: stubs/replay.c
+
 Usermode Emulation
 ------------------
 Overall
diff --git a/audio/audio.c b/audio/audio.c
index c8898d8422..beafed209b 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -2028,6 +2028,8 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
                     sw = sw1;
                 }
                 QLIST_REMOVE (cap, entries);
+                g_free (cap->hw.mix_buf);
+                g_free (cap->buf);
                 g_free (cap);
             }
             return;
diff --git a/audio/wavcapture.c b/audio/wavcapture.c
index 8bfb9e7654..5863803584 100644
--- a/audio/wavcapture.c
+++ b/audio/wavcapture.c
@@ -88,6 +88,7 @@ static void wav_capture_destroy (void *opaque)
     WAVState *wav = opaque;
 
     AUD_del_capture (wav->cap, wav);
+    g_free (wav);
 }
 
 static void wav_capture_info (void *opaque)
diff --git a/block.c b/block.c
index 6c6bb3ec7a..a45b9b5c29 100644
--- a/block.c
+++ b/block.c
@@ -974,16 +974,14 @@ static void update_flags_from_options(int *flags, QemuOpts *opts)
 static void update_options_from_flags(QDict *options, int flags)
 {
     if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) {
-        qdict_put(options, BDRV_OPT_CACHE_DIRECT,
-                  qbool_from_bool(flags & BDRV_O_NOCACHE));
+        qdict_put_bool(options, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE);
     }
     if (!qdict_haskey(options, BDRV_OPT_CACHE_NO_FLUSH)) {
-        qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
-                  qbool_from_bool(flags & BDRV_O_NO_FLUSH));
+        qdict_put_bool(options, BDRV_OPT_CACHE_NO_FLUSH,
+                       flags & BDRV_O_NO_FLUSH);
     }
     if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
-        qdict_put(options, BDRV_OPT_READ_ONLY,
-                  qbool_from_bool(!(flags & BDRV_O_RDWR)));
+        qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
     }
 }
 
@@ -1399,7 +1397,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
     /* Fetch the file name from the options QDict if necessary */
     if (protocol && filename) {
         if (!qdict_haskey(*options, "filename")) {
-            qdict_put(*options, "filename", qstring_from_str(filename));
+            qdict_put_str(*options, "filename", filename);
             parse_filename = true;
         } else {
             error_setg(errp, "Can't specify 'file' and 'filename' options at "
@@ -1420,7 +1418,7 @@ static int bdrv_fill_options(QDict **options, const char *filename,
             }
 
             drvname = drv->format_name;
-            qdict_put(*options, "driver", qstring_from_str(drvname));
+            qdict_put_str(*options, "driver", drvname);
         } else {
             error_setg(errp, "Must specify either driver or file");
             return -EINVAL;
@@ -2075,7 +2073,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
     }
 
     if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
-        qdict_put(options, "driver", qstring_from_str(bs->backing_format));
+        qdict_put_str(options, "driver", bs->backing_format);
     }
 
     backing_hd = bdrv_open_inherit(*backing_filename ? backing_filename : NULL,
@@ -2197,7 +2195,7 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
     char *tmp_filename = g_malloc0(PATH_MAX + 1);
     int64_t total_size;
     QemuOpts *opts = NULL;
-    BlockDriverState *bs_snapshot;
+    BlockDriverState *bs_snapshot = NULL;
     Error *local_err = NULL;
     int ret;
 
@@ -2230,38 +2228,32 @@ static BlockDriverState *bdrv_append_temp_snapshot(BlockDriverState *bs,
     }
 
     /* Prepare options QDict for the temporary file */
-    qdict_put(snapshot_options, "file.driver",
-              qstring_from_str("file"));
-    qdict_put(snapshot_options, "file.filename",
-              qstring_from_str(tmp_filename));
-    qdict_put(snapshot_options, "driver",
-              qstring_from_str("qcow2"));
+    qdict_put_str(snapshot_options, "file.driver", "file");
+    qdict_put_str(snapshot_options, "file.filename", tmp_filename);
+    qdict_put_str(snapshot_options, "driver", "qcow2");
 
     bs_snapshot = bdrv_open(NULL, NULL, snapshot_options, flags, errp);
     snapshot_options = NULL;
     if (!bs_snapshot) {
-        ret = -EINVAL;
         goto out;
     }
 
-    /* bdrv_append() consumes a strong reference to bs_snapshot (i.e. it will
-     * call bdrv_unref() on it), so in order to be able to return one, we have
-     * to increase bs_snapshot's refcount here */
+    /* bdrv_append() consumes a strong reference to bs_snapshot
+     * (i.e. it will call bdrv_unref() on it) even on error, so in
+     * order to be able to return one, we have to increase
+     * bs_snapshot's refcount here */
     bdrv_ref(bs_snapshot);
     bdrv_append(bs_snapshot, bs, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
-        ret = -EINVAL;
+        bs_snapshot = NULL;
         goto out;
     }
 
-    g_free(tmp_filename);
-    return bs_snapshot;
-
 out:
     QDECREF(snapshot_options);
     g_free(tmp_filename);
-    return NULL;
+    return bs_snapshot;
 }
 
 /*
@@ -2410,8 +2402,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
                 goto fail;
             }
 
-            qdict_put(options, "file",
-                      qstring_from_str(bdrv_get_node_name(file_bs)));
+            qdict_put_str(options, "file", bdrv_get_node_name(file_bs));
         }
     }
 
@@ -2433,8 +2424,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
          * sure to update both bs->options (which has the full effective
          * options for bs) and options (which has file.* already removed).
          */
-        qdict_put(bs->options, "driver", qstring_from_str(drv->format_name));
-        qdict_put(options, "driver", qstring_from_str(drv->format_name));
+        qdict_put_str(bs->options, "driver", drv->format_name);
+        qdict_put_str(options, "driver", drv->format_name);
     } else if (!drv) {
         error_setg(errp, "Must specify either driver or file");
         goto fail;
@@ -2810,12 +2801,12 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
      * that they are checked at the end of this function. */
     value = qemu_opt_get(opts, "node-name");
     if (value) {
-        qdict_put(reopen_state->options, "node-name", qstring_from_str(value));
+        qdict_put_str(reopen_state->options, "node-name", value);
     }
 
     value = qemu_opt_get(opts, "driver");
     if (value) {
-        qdict_put(reopen_state->options, "driver", qstring_from_str(value));
+        qdict_put_str(reopen_state->options, "driver", value);
     }
 
     /* If we are to stay read-only, do not allow permission change
@@ -4306,8 +4297,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
 
             if (backing_fmt) {
                 backing_options = qdict_new();
-                qdict_put(backing_options, "driver",
-                          qstring_from_str(backing_fmt));
+                qdict_put_str(backing_options, "driver", backing_fmt);
             }
 
             bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
@@ -4712,11 +4702,9 @@ void bdrv_refresh_filename(BlockDriverState *bs)
          * contain a representation of the filename, therefore the following
          * suffices without querying the (exact_)filename of this BDS. */
         if (bs->file->bs->full_open_options) {
-            qdict_put_obj(opts, "driver",
-                          QOBJECT(qstring_from_str(drv->format_name)));
+            qdict_put_str(opts, "driver", drv->format_name);
             QINCREF(bs->file->bs->full_open_options);
-            qdict_put_obj(opts, "file",
-                          QOBJECT(bs->file->bs->full_open_options));
+            qdict_put(opts, "file", bs->file->bs->full_open_options);
 
             bs->full_open_options = opts;
         } else {
@@ -4732,8 +4720,7 @@ void bdrv_refresh_filename(BlockDriverState *bs)
 
         opts = qdict_new();
         append_open_options(opts, bs);
-        qdict_put_obj(opts, "driver",
-                      QOBJECT(qstring_from_str(drv->format_name)));
+        qdict_put_str(opts, "driver", drv->format_name);
 
         if (bs->exact_filename[0]) {
             /* This may not work for all block protocol drivers (some may
@@ -4743,8 +4730,7 @@ void bdrv_refresh_filename(BlockDriverState *bs)
              * needs some special format of the options QDict, it needs to
              * implement the driver-specific bdrv_refresh_filename() function.
              */
-            qdict_put_obj(opts, "filename",
-                          QOBJECT(qstring_from_str(bs->exact_filename)));
+            qdict_put_str(opts, "filename", bs->exact_filename);
         }
 
         bs->full_open_options = opts;
diff --git a/block/blkdebug.c b/block/blkdebug.c
index d2a7561c4c..3c088934db 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -301,7 +301,7 @@ static void blkdebug_parse_filename(const char *filename, QDict *options,
     if (!strstart(filename, "blkdebug:", &filename)) {
         /* There was no prefix; therefore, all options have to be already
            present in the QDict (except for the filename) */
-        qdict_put(options, "x-image", qstring_from_str(filename));
+        qdict_put_str(options, "x-image", filename);
         return;
     }
 
@@ -320,7 +320,7 @@ static void blkdebug_parse_filename(const char *filename, QDict *options,
 
     /* TODO Allow multi-level nesting and set file.filename here */
     filename = c + 1;
-    qdict_put(options, "x-image", qstring_from_str(filename));
+    qdict_put_str(options, "x-image", filename);
 }
 
 static QemuOptsList runtime_opts = {
@@ -693,10 +693,10 @@ static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
     }
 
     opts = qdict_new();
-    qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkdebug")));
+    qdict_put_str(opts, "driver", "blkdebug");
 
     QINCREF(bs->file->bs->full_open_options);
-    qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options));
+    qdict_put(opts, "image", bs->file->bs->full_open_options);
 
     for (e = qdict_first(options); e; e = qdict_next(options, e)) {
         if (strcmp(qdict_entry_key(e), "x-image")) {
diff --git a/block/blkverify.c b/block/blkverify.c
index af23281669..6b0a603cf0 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -67,7 +67,7 @@ static void blkverify_parse_filename(const char *filename, QDict *options,
     if (!strstart(filename, "blkverify:", &filename)) {
         /* There was no prefix; therefore, all options have to be already
            present in the QDict (except for the filename) */
-        qdict_put(options, "x-image", qstring_from_str(filename));
+        qdict_put_str(options, "x-image", filename);
         return;
     }
 
@@ -84,7 +84,7 @@ static void blkverify_parse_filename(const char *filename, QDict *options,
 
     /* TODO Allow multi-level nesting and set file.filename here */
     filename = c + 1;
-    qdict_put(options, "x-image", qstring_from_str(filename));
+    qdict_put_str(options, "x-image", filename);
 }
 
 static QemuOptsList runtime_opts = {
@@ -288,13 +288,12 @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options)
         && s->test_file->bs->full_open_options)
     {
         QDict *opts = qdict_new();
-        qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("blkverify")));
+        qdict_put_str(opts, "driver", "blkverify");
 
         QINCREF(bs->file->bs->full_open_options);
-        qdict_put_obj(opts, "raw", QOBJECT(bs->file->bs->full_open_options));
+        qdict_put(opts, "raw", bs->file->bs->full_open_options);
         QINCREF(s->test_file->bs->full_open_options);
-        qdict_put_obj(opts, "test",
-                      QOBJECT(s->test_file->bs->full_open_options));
+        qdict_put(opts, "test", s->test_file->bs->full_open_options);
 
         bs->full_open_options = opts;
     }
diff --git a/block/crypto.c b/block/crypto.c
index 6828180840..10e5ddccaa 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -56,10 +56,10 @@ static int block_crypto_probe_generic(QCryptoBlockFormat format,
 
 
 static ssize_t block_crypto_read_func(QCryptoBlock *block,
-                                      void *opaque,
                                       size_t offset,
                                       uint8_t *buf,
                                       size_t buflen,
+                                      void *opaque,
                                       Error **errp)
 {
     BlockDriverState *bs = opaque;
@@ -83,10 +83,10 @@ struct BlockCryptoCreateData {
 
 
 static ssize_t block_crypto_write_func(QCryptoBlock *block,
-                                       void *opaque,
                                        size_t offset,
                                        const uint8_t *buf,
                                        size_t buflen,
+                                       void *opaque,
                                        Error **errp)
 {
     struct BlockCryptoCreateData *data = opaque;
@@ -102,8 +102,8 @@ static ssize_t block_crypto_write_func(QCryptoBlock *block,
 
 
 static ssize_t block_crypto_init_func(QCryptoBlock *block,
-                                      void *opaque,
                                       size_t headerlen,
+                                      void *opaque,
                                       Error **errp)
 {
     struct BlockCryptoCreateData *data = opaque;
diff --git a/block/curl.c b/block/curl.c
index 2708d57c2f..aa6e8cc0e5 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -548,7 +548,7 @@ static void curl_clean_state(CURLState *s)
 static void curl_parse_filename(const char *filename, QDict *options,
                                 Error **errp)
 {
-    qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
+    qdict_put_str(options, CURL_BLOCK_OPT_URL, filename);
 }
 
 static void curl_detach_aio_context(BlockDriverState *bs)
diff --git a/block/file-posix.c b/block/file-posix.c
index 1941fb6749..19c48a043e 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -375,7 +375,7 @@ static void raw_parse_filename(const char *filename, QDict *options,
      * function call can be ignored. */
     strstart(filename, "file:", &filename);
 
-    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+    qdict_put_str(options, "filename", filename);
 }
 
 static QemuOptsList raw_runtime_opts = {
@@ -2155,7 +2155,7 @@ static void hdev_parse_filename(const char *filename, QDict *options,
     /* The prefix is optional, just as for "file". */
     strstart(filename, "host_device:", &filename);
 
-    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+    qdict_put_str(options, "filename", filename);
 }
 
 static bool hdev_is_sg(BlockDriverState *bs)
@@ -2244,7 +2244,7 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
             goto hdev_open_Mac_error;
         }
 
-        qdict_put(options, "filename", qstring_from_str(bsd_path));
+        qdict_put_str(options, "filename", bsd_path);
 
 hdev_open_Mac_error:
         g_free(mediaType);
@@ -2454,7 +2454,7 @@ static void cdrom_parse_filename(const char *filename, QDict *options,
     /* The prefix is optional, just as for "file". */
     strstart(filename, "host_cdrom:", &filename);
 
-    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+    qdict_put_str(options, "filename", filename);
 }
 #endif
 
diff --git a/block/file-win32.c b/block/file-win32.c
index 7872e00a21..d1eb0a14b2 100644
--- a/block/file-win32.c
+++ b/block/file-win32.c
@@ -281,7 +281,7 @@ static void raw_parse_filename(const char *filename, QDict *options,
      * function call can be ignored. */
     strstart(filename, "file:", &filename);
 
-    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+    qdict_put_str(options, "filename", filename);
 }
 
 static QemuOptsList raw_runtime_opts = {
@@ -668,7 +668,7 @@ static void hdev_parse_filename(const char *filename, QDict *options,
     /* The prefix is optional, just as for "file". */
     strstart(filename, "host_device:", &filename);
 
-    qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+    qdict_put_str(options, "filename", filename);
 }
 
 static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
diff --git a/block/gluster.c b/block/gluster.c
index 1d4e2f7c52..7c76cd0988 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -321,7 +321,7 @@ static int parse_volume_options(BlockdevOptionsGluster *gconf, char *path)
 static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
                                   const char *filename)
 {
-    SocketAddressFlat *gsconf;
+    SocketAddress *gsconf;
     URI *uri;
     QueryParams *qp = NULL;
     bool is_unix = false;
@@ -332,19 +332,19 @@ static int qemu_gluster_parse_uri(BlockdevOptionsGluster *gconf,
         return -EINVAL;
     }
 
-    gconf->server = g_new0(SocketAddressFlatList, 1);
-    gconf->server->value = gsconf = g_new0(SocketAddressFlat, 1);
+    gconf->server = g_new0(SocketAddressList, 1);
+    gconf->server->value = gsconf = g_new0(SocketAddress, 1);
 
     /* transport */
     if (!uri->scheme || !strcmp(uri->scheme, "gluster")) {
-        gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
+        gsconf->type = SOCKET_ADDRESS_TYPE_INET;
     } else if (!strcmp(uri->scheme, "gluster+tcp")) {
-        gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
+        gsconf->type = SOCKET_ADDRESS_TYPE_INET;
     } else if (!strcmp(uri->scheme, "gluster+unix")) {
-        gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_UNIX;
+        gsconf->type = SOCKET_ADDRESS_TYPE_UNIX;
         is_unix = true;
     } else if (!strcmp(uri->scheme, "gluster+rdma")) {
-        gsconf->type = SOCKET_ADDRESS_FLAT_TYPE_INET;
+        gsconf->type = SOCKET_ADDRESS_TYPE_INET;
         error_report("Warning: rdma feature is not supported, falling "
                      "back to tcp");
     } else {
@@ -396,7 +396,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
     struct glfs *glfs;
     int ret;
     int old_errno;
-    SocketAddressFlatList *server;
+    SocketAddressList *server;
     unsigned long long port;
 
     glfs = glfs_find_preopened(gconf->volume);
@@ -413,11 +413,11 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
 
     for (server = gconf->server; server; server = server->next) {
         switch (server->value->type) {
-        case SOCKET_ADDRESS_FLAT_TYPE_UNIX:
+        case SOCKET_ADDRESS_TYPE_UNIX:
             ret = glfs_set_volfile_server(glfs, "unix",
                                    server->value->u.q_unix.path, 0);
             break;
-        case SOCKET_ADDRESS_FLAT_TYPE_INET:
+        case SOCKET_ADDRESS_TYPE_INET:
             if (parse_uint_full(server->value->u.inet.port, &port, 10) < 0 ||
                 port > 65535) {
                 error_setg(errp, "'%s' is not a valid port number",
@@ -429,8 +429,8 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
                                    server->value->u.inet.host,
                                    (int)port);
             break;
-        case SOCKET_ADDRESS_FLAT_TYPE_VSOCK:
-        case SOCKET_ADDRESS_FLAT_TYPE_FD:
+        case SOCKET_ADDRESS_TYPE_VSOCK:
+        case SOCKET_ADDRESS_TYPE_FD:
         default:
             abort();
         }
@@ -450,7 +450,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
         error_setg(errp, "Gluster connection for volume %s, path %s failed"
                          " to connect", gconf->volume, gconf->path);
         for (server = gconf->server; server; server = server->next) {
-            if (server->value->type  == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
+            if (server->value->type  == SOCKET_ADDRESS_TYPE_UNIX) {
                 error_append_hint(errp, "hint: failed on socket %s ",
                                   server->value->u.q_unix.path);
             } else {
@@ -487,8 +487,8 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
                                   QDict *options, Error **errp)
 {
     QemuOpts *opts;
-    SocketAddressFlat *gsconf = NULL;
-    SocketAddressFlatList *curr = NULL;
+    SocketAddress *gsconf = NULL;
+    SocketAddressList *curr = NULL;
     QDict *backing_options = NULL;
     Error *local_err = NULL;
     char *str = NULL;
@@ -542,14 +542,14 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
             goto out;
 
         }
-        gsconf = g_new0(SocketAddressFlat, 1);
+        gsconf = g_new0(SocketAddress, 1);
         if (!strcmp(ptr, "tcp")) {
             ptr = "inet";       /* accept legacy "tcp" */
         }
-        type = qapi_enum_parse(SocketAddressFlatType_lookup, ptr,
-                               SOCKET_ADDRESS_FLAT_TYPE__MAX, -1, NULL);
-        if (type != SOCKET_ADDRESS_FLAT_TYPE_INET
-            && type != SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
+        type = qapi_enum_parse(SocketAddressType_lookup, ptr,
+                               SOCKET_ADDRESS_TYPE__MAX, -1, NULL);
+        if (type != SOCKET_ADDRESS_TYPE_INET
+            && type != SOCKET_ADDRESS_TYPE_UNIX) {
             error_setg(&local_err,
                        "Parameter '%s' may be 'inet' or 'unix'",
                        GLUSTER_OPT_TYPE);
@@ -559,7 +559,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
         gsconf->type = type;
         qemu_opts_del(opts);
 
-        if (gsconf->type == SOCKET_ADDRESS_FLAT_TYPE_INET) {
+        if (gsconf->type == SOCKET_ADDRESS_TYPE_INET) {
             /* create opts info from runtime_inet_opts list */
             opts = qemu_opts_create(&runtime_inet_opts, NULL, 0, &error_abort);
             qemu_opts_absorb_qdict(opts, backing_options, &local_err);
@@ -628,11 +628,11 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
         }
 
         if (gconf->server == NULL) {
-            gconf->server = g_new0(SocketAddressFlatList, 1);
+            gconf->server = g_new0(SocketAddressList, 1);
             gconf->server->value = gsconf;
             curr = gconf->server;
         } else {
-            curr->next = g_new0(SocketAddressFlatList, 1);
+            curr->next = g_new0(SocketAddressList, 1);
             curr->next->value = gsconf;
             curr = curr->next;
         }
@@ -648,7 +648,7 @@ static int qemu_gluster_parse_json(BlockdevOptionsGluster *gconf,
 
 out:
     error_propagate(errp, local_err);
-    qapi_free_SocketAddressFlat(gsconf);
+    qapi_free_SocketAddress(gsconf);
     qemu_opts_del(opts);
     g_free(str);
     QDECREF(backing_options);
diff --git a/block/nbd.c b/block/nbd.c
index 814ab26dce..975faab2c5 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -47,7 +47,7 @@ typedef struct BDRVNBDState {
     NBDClientSession client;
 
     /* For nbd_refresh_filename() */
-    SocketAddressFlat *saddr;
+    SocketAddress *saddr;
     char *export, *tlscredsid;
 } BDRVNBDState;
 
@@ -79,7 +79,7 @@ static int nbd_parse_uri(const char *filename, QDict *options)
     p = uri->path ? uri->path : "/";
     p += strspn(p, "/");
     if (p[0]) {
-        qdict_put(options, "export", qstring_from_str(p));
+        qdict_put_str(options, "export", p);
     }
 
     qp = query_params_parse(uri->query);
@@ -94,9 +94,8 @@ static int nbd_parse_uri(const char *filename, QDict *options)
             ret = -EINVAL;
             goto out;
         }
-        qdict_put(options, "server.type", qstring_from_str("unix"));
-        qdict_put(options, "server.path",
-                  qstring_from_str(qp->p[0].value));
+        qdict_put_str(options, "server.type", "unix");
+        qdict_put_str(options, "server.path", qp->p[0].value);
     } else {
         QString *host;
         char *port_str;
@@ -115,11 +114,11 @@ static int nbd_parse_uri(const char *filename, QDict *options)
             host = qstring_from_str(uri->server);
         }
 
-        qdict_put(options, "server.type", qstring_from_str("inet"));
+        qdict_put_str(options, "server.type", "inet");
         qdict_put(options, "server.host", host);
 
         port_str = g_strdup_printf("%d", uri->port ?: NBD_DEFAULT_PORT);
-        qdict_put(options, "server.port", qstring_from_str(port_str));
+        qdict_put_str(options, "server.port", port_str);
         g_free(port_str);
     }
 
@@ -181,7 +180,7 @@ static void nbd_parse_filename(const char *filename, QDict *options,
         export_name[0] = 0; /* truncate 'file' */
         export_name += strlen(EN_OPTSTR);
 
-        qdict_put(options, "export", qstring_from_str(export_name));
+        qdict_put_str(options, "export", export_name);
     }
 
     /* extract the host_spec - fail if it's not nbd:... */
@@ -196,19 +195,19 @@ static void nbd_parse_filename(const char *filename, QDict *options,
 
     /* are we a UNIX or TCP socket? */
     if (strstart(host_spec, "unix:", &unixpath)) {
-        qdict_put(options, "server.type", qstring_from_str("unix"));
-        qdict_put(options, "server.path", qstring_from_str(unixpath));
+        qdict_put_str(options, "server.type", "unix");
+        qdict_put_str(options, "server.path", unixpath);
     } else {
-        InetSocketAddress *addr = NULL;
+        InetSocketAddress *addr = g_new(InetSocketAddress, 1);
 
-        addr = inet_parse(host_spec, errp);
-        if (!addr) {
-            goto out;
+        if (inet_parse(addr, host_spec, errp)) {
+            goto out_inet;
         }
 
-        qdict_put(options, "server.type", qstring_from_str("inet"));
-        qdict_put(options, "server.host", qstring_from_str(addr->host));
-        qdict_put(options, "server.port", qstring_from_str(addr->port));
+        qdict_put_str(options, "server.type", "inet");
+        qdict_put_str(options, "server.host", addr->host);
+        qdict_put_str(options, "server.port", addr->port);
+    out_inet:
         qapi_free_InetSocketAddress(addr);
     }
 
@@ -247,22 +246,22 @@ static bool nbd_process_legacy_socket_options(QDict *output_options,
             return false;
         }
 
-        qdict_put(output_options, "server.type", qstring_from_str("unix"));
-        qdict_put(output_options, "server.path", qstring_from_str(path));
+        qdict_put_str(output_options, "server.type", "unix");
+        qdict_put_str(output_options, "server.path", path);
     } else if (host) {
-        qdict_put(output_options, "server.type", qstring_from_str("inet"));
-        qdict_put(output_options, "server.host", qstring_from_str(host));
-        qdict_put(output_options, "server.port",
-                  qstring_from_str(port ?: stringify(NBD_DEFAULT_PORT)));
+        qdict_put_str(output_options, "server.type", "inet");
+        qdict_put_str(output_options, "server.host", host);
+        qdict_put_str(output_options, "server.port",
+                      port ?: stringify(NBD_DEFAULT_PORT));
     }
 
     return true;
 }
 
-static SocketAddressFlat *nbd_config(BDRVNBDState *s, QDict *options,
-                                     Error **errp)
+static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
+                                 Error **errp)
 {
-    SocketAddressFlat *saddr = NULL;
+    SocketAddress *saddr = NULL;
     QDict *addr = NULL;
     QObject *crumpled_addr = NULL;
     Visitor *iv = NULL;
@@ -288,7 +287,7 @@ static SocketAddressFlat *nbd_config(BDRVNBDState *s, QDict *options,
      * visitor expects the former.
      */
     iv = qobject_input_visitor_new(crumpled_addr);
-    visit_type_SocketAddressFlat(iv, NULL, &saddr, &local_err);
+    visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto done;
@@ -307,10 +306,9 @@ NBDClientSession *nbd_get_client_session(BlockDriverState *bs)
     return &s->client;
 }
 
-static QIOChannelSocket *nbd_establish_connection(SocketAddressFlat *saddr_flat,
+static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
                                                   Error **errp)
 {
-    SocketAddress *saddr = socket_address_crumple(saddr_flat);
     QIOChannelSocket *sioc;
     Error *local_err = NULL;
 
@@ -320,7 +318,6 @@ static QIOChannelSocket *nbd_establish_connection(SocketAddressFlat *saddr_flat,
     qio_channel_socket_connect_sync(sioc,
                                     saddr,
                                     &local_err);
-    qapi_free_SocketAddress(saddr);
     if (local_err) {
         object_unref(OBJECT(sioc));
         error_propagate(errp, local_err);
@@ -413,7 +410,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
         goto error;
     }
 
-    /* Translate @host, @port, and @path to a SocketAddressFlat */
+    /* Translate @host, @port, and @path to a SocketAddress */
     if (!nbd_process_legacy_socket_options(options, opts, errp)) {
         goto error;
     }
@@ -434,7 +431,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
         }
 
         /* TODO SOCKET_ADDRESS_KIND_FD where fd has AF_INET or AF_INET6 */
-        if (s->saddr->type != SOCKET_ADDRESS_FLAT_TYPE_INET) {
+        if (s->saddr->type != SOCKET_ADDRESS_TYPE_INET) {
             error_setg(errp, "TLS only supported over IP sockets");
             goto error;
         }
@@ -461,7 +458,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
         object_unref(OBJECT(tlscreds));
     }
     if (ret < 0) {
-        qapi_free_SocketAddressFlat(s->saddr);
+        qapi_free_SocketAddress(s->saddr);
         g_free(s->export);
         g_free(s->tlscredsid);
     }
@@ -487,7 +484,7 @@ static void nbd_close(BlockDriverState *bs)
 
     nbd_client_close(bs);
 
-    qapi_free_SocketAddressFlat(s->saddr);
+    qapi_free_SocketAddress(s->saddr);
     g_free(s->export);
     g_free(s->tlscredsid);
 }
@@ -518,17 +515,17 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
     Visitor *ov;
     const char *host = NULL, *port = NULL, *path = NULL;
 
-    if (s->saddr->type == SOCKET_ADDRESS_FLAT_TYPE_INET) {
+    if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) {
         const InetSocketAddress *inet = &s->saddr->u.inet;
         if (!inet->has_ipv4 && !inet->has_ipv6 && !inet->has_to) {
             host = inet->host;
             port = inet->port;
         }
-    } else if (s->saddr->type == SOCKET_ADDRESS_FLAT_TYPE_UNIX) {
+    } else if (s->saddr->type == SOCKET_ADDRESS_TYPE_UNIX) {
         path = s->saddr->u.q_unix.path;
     } /* else can't represent as pseudo-filename */
 
-    qdict_put(opts, "driver", qstring_from_str("nbd"));
+    qdict_put_str(opts, "driver", "nbd");
 
     if (path && s->export) {
         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
@@ -545,16 +542,16 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options)
     }
 
     ov = qobject_output_visitor_new(&saddr_qdict);
-    visit_type_SocketAddressFlat(ov, NULL, &s->saddr, &error_abort);
+    visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort);
     visit_complete(ov, &saddr_qdict);
     visit_free(ov);
     qdict_put_obj(opts, "server", saddr_qdict);
 
     if (s->export) {
-        qdict_put(opts, "export", qstring_from_str(s->export));
+        qdict_put_str(opts, "export", s->export);
     }
     if (s->tlscredsid) {
-        qdict_put(opts, "tls-creds", qstring_from_str(s->tlscredsid));
+        qdict_put_str(opts, "tls-creds", s->tlscredsid);
     }
 
     qdict_flatten(opts);
diff --git a/block/nfs.c b/block/nfs.c
index 76572ae546..848b2c0bb0 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -104,9 +104,9 @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
         goto out;
     }
 
-    qdict_put(options, "server.host", qstring_from_str(uri->server));
-    qdict_put(options, "server.type", qstring_from_str("inet"));
-    qdict_put(options, "path", qstring_from_str(uri->path));
+    qdict_put_str(options, "server.host", uri->server);
+    qdict_put_str(options, "server.type", "inet");
+    qdict_put_str(options, "path", uri->path);
 
     for (i = 0; i < qp->n; i++) {
         unsigned long long val;
@@ -121,23 +121,17 @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
             goto out;
         }
         if (!strcmp(qp->p[i].name, "uid")) {
-            qdict_put(options, "user",
-                      qstring_from_str(qp->p[i].value));
+            qdict_put_str(options, "user", qp->p[i].value);
         } else if (!strcmp(qp->p[i].name, "gid")) {
-            qdict_put(options, "group",
-                      qstring_from_str(qp->p[i].value));
+            qdict_put_str(options, "group", qp->p[i].value);
         } else if (!strcmp(qp->p[i].name, "tcp-syncnt")) {
-            qdict_put(options, "tcp-syn-count",
-                      qstring_from_str(qp->p[i].value));
+            qdict_put_str(options, "tcp-syn-count", qp->p[i].value);
         } else if (!strcmp(qp->p[i].name, "readahead")) {
-            qdict_put(options, "readahead-size",
-                      qstring_from_str(qp->p[i].value));
+            qdict_put_str(options, "readahead-size", qp->p[i].value);
         } else if (!strcmp(qp->p[i].name, "pagecache")) {
-            qdict_put(options, "page-cache-size",
-                      qstring_from_str(qp->p[i].value));
+            qdict_put_str(options, "page-cache-size", qp->p[i].value);
         } else if (!strcmp(qp->p[i].name, "debug")) {
-            qdict_put(options, "debug",
-                      qstring_from_str(qp->p[i].value));
+            qdict_put_str(options, "debug", qp->p[i].value);
         } else {
             error_setg(errp, "Unknown NFS parameter name: %s",
                        qp->p[i].name);
@@ -819,7 +813,7 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
     QObject *server_qdict;
     Visitor *ov;
 
-    qdict_put(opts, "driver", qstring_from_str("nfs"));
+    qdict_put_str(opts, "driver", "nfs");
 
     if (client->uid && !client->gid) {
         snprintf(bs->exact_filename, sizeof(bs->exact_filename),
@@ -842,28 +836,25 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
     visit_type_NFSServer(ov, NULL, &client->server, &error_abort);
     visit_complete(ov, &server_qdict);
     qdict_put_obj(opts, "server", server_qdict);
-    qdict_put(opts, "path", qstring_from_str(client->path));
+    qdict_put_str(opts, "path", client->path);
 
     if (client->uid) {
-        qdict_put(opts, "user", qint_from_int(client->uid));
+        qdict_put_int(opts, "user", client->uid);
     }
     if (client->gid) {
-        qdict_put(opts, "group", qint_from_int(client->gid));
+        qdict_put_int(opts, "group", client->gid);
     }
     if (client->tcp_syncnt) {
-        qdict_put(opts, "tcp-syn-cnt",
-                  qint_from_int(client->tcp_syncnt));
+        qdict_put_int(opts, "tcp-syn-cnt", client->tcp_syncnt);
     }
     if (client->readahead) {
-        qdict_put(opts, "readahead-size",
-                  qint_from_int(client->readahead));
+        qdict_put_int(opts, "readahead-size", client->readahead);
     }
     if (client->pagecache) {
-        qdict_put(opts, "page-cache-size",
-                  qint_from_int(client->pagecache));
+        qdict_put_int(opts, "page-cache-size", client->pagecache);
     }
     if (client->debug) {
-        qdict_put(opts, "debug", qint_from_int(client->debug));
+        qdict_put_int(opts, "debug", client->debug);
     }
 
     visit_free(ov);
diff --git a/block/null.c b/block/null.c
index b300390944..876f90965b 100644
--- a/block/null.c
+++ b/block/null.c
@@ -232,7 +232,7 @@ static void null_refresh_filename(BlockDriverState *bs, QDict *opts)
                  bs->drv->format_name);
     }
 
-    qdict_put(opts, "driver", qstring_from_str(bs->drv->format_name));
+    qdict_put_str(opts, "driver", bs->drv->format_name);
     bs->full_open_options = opts;
 }
 
diff --git a/block/qcow2.c b/block/qcow2.c
index 5c1573c999..1c2697732b 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2265,7 +2265,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
      * table)
      */
     options = qdict_new();
-    qdict_put(options, "driver", qstring_from_str("qcow2"));
+    qdict_put_str(options, "driver", "qcow2");
     blk = blk_new_open(filename, NULL, options,
                        BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH,
                        &local_err);
@@ -2327,7 +2327,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
 
     /* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning */
     options = qdict_new();
-    qdict_put(options, "driver", qstring_from_str("qcow2"));
+    qdict_put_str(options, "driver", "qcow2");
     blk = blk_new_open(filename, NULL, options,
                        BDRV_O_RDWR | BDRV_O_NO_BACKING, &local_err);
     if (blk == NULL) {
diff --git a/block/quorum.c b/block/quorum.c
index 40205fb1b3..1b2a8c3937 100644
--- a/block/quorum.c
+++ b/block/quorum.c
@@ -1096,19 +1096,15 @@ static void quorum_refresh_filename(BlockDriverState *bs, QDict *options)
     children = qlist_new();
     for (i = 0; i < s->num_children; i++) {
         QINCREF(s->children[i]->bs->full_open_options);
-        qlist_append_obj(children,
-                         QOBJECT(s->children[i]->bs->full_open_options));
+        qlist_append(children, s->children[i]->bs->full_open_options);
     }
 
     opts = qdict_new();
-    qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("quorum")));
-    qdict_put_obj(opts, QUORUM_OPT_VOTE_THRESHOLD,
-                  QOBJECT(qint_from_int(s->threshold)));
-    qdict_put_obj(opts, QUORUM_OPT_BLKVERIFY,
-                  QOBJECT(qbool_from_bool(s->is_blkverify)));
-    qdict_put_obj(opts, QUORUM_OPT_REWRITE,
-                  QOBJECT(qbool_from_bool(s->rewrite_corrupted)));
-    qdict_put_obj(opts, "children", QOBJECT(children));
+    qdict_put_str(opts, "driver", "quorum");
+    qdict_put_int(opts, QUORUM_OPT_VOTE_THRESHOLD, s->threshold);
+    qdict_put_bool(opts, QUORUM_OPT_BLKVERIFY, s->is_blkverify);
+    qdict_put_bool(opts, QUORUM_OPT_REWRITE, s->rewrite_corrupted);
+    qdict_put(opts, "children", children);
 
     bs->full_open_options = opts;
 }
diff --git a/block/rbd.c b/block/rbd.c
index fbf30591d1..e551639e47 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -154,20 +154,20 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
         goto done;
     }
     qemu_rbd_unescape(found_str);
-    qdict_put(options, "pool", qstring_from_str(found_str));
+    qdict_put_str(options, "pool", found_str);
 
     if (strchr(p, '@')) {
         found_str = qemu_rbd_next_tok(p, '@', &p);
         qemu_rbd_unescape(found_str);
-        qdict_put(options, "image", qstring_from_str(found_str));
+        qdict_put_str(options, "image", found_str);
 
         found_str = qemu_rbd_next_tok(p, ':', &p);
         qemu_rbd_unescape(found_str);
-        qdict_put(options, "snapshot", qstring_from_str(found_str));
+        qdict_put_str(options, "snapshot", found_str);
     } else {
         found_str = qemu_rbd_next_tok(p, ':', &p);
         qemu_rbd_unescape(found_str);
-        qdict_put(options, "image", qstring_from_str(found_str));
+        qdict_put_str(options, "image", found_str);
     }
     if (!p) {
         goto done;
@@ -189,9 +189,9 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
         qemu_rbd_unescape(value);
 
         if (!strcmp(name, "conf")) {
-            qdict_put(options, "conf", qstring_from_str(value));
+            qdict_put_str(options, "conf", value);
         } else if (!strcmp(name, "id")) {
-            qdict_put(options, "user" , qstring_from_str(value));
+            qdict_put_str(options, "user", value);
         } else {
             /*
              * We pass these internally to qemu_rbd_set_keypairs(), so
@@ -204,8 +204,8 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options,
             if (!keypairs) {
                 keypairs = qlist_new();
             }
-            qlist_append(keypairs, qstring_from_str(name));
-            qlist_append(keypairs, qstring_from_str(value));
+            qlist_append_str(keypairs, name);
+            qlist_append_str(keypairs, value);
         }
     }
 
diff --git a/block/sheepdog.c b/block/sheepdog.c
index fe8fd923d5..a18315a1ca 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -536,14 +536,12 @@ static SocketAddress *sd_socket_address(const char *path,
     SocketAddress *addr = g_new0(SocketAddress, 1);
 
     if (path) {
-        addr->type = SOCKET_ADDRESS_KIND_UNIX;
-        addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
-        addr->u.q_unix.data->path = g_strdup(path);
+        addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+        addr->u.q_unix.path = g_strdup(path);
     } else {
-        addr->type = SOCKET_ADDRESS_KIND_INET;
-        addr->u.inet.data = g_new0(InetSocketAddress, 1);
-        addr->u.inet.data->host = g_strdup(host ?: SD_DEFAULT_ADDR);
-        addr->u.inet.data->port = g_strdup(port ?: stringify(SD_DEFAULT_PORT));
+        addr->type = SOCKET_ADDRESS_TYPE_INET;
+        addr->u.inet.host = g_strdup(host ?: SD_DEFAULT_ADDR);
+        addr->u.inet.port = g_strdup(port ?: stringify(SD_DEFAULT_PORT));
     }
 
     return addr;
@@ -554,7 +552,6 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
     QDict *server = NULL;
     QObject *crumpled_server = NULL;
     Visitor *iv = NULL;
-    SocketAddressFlat *saddr_flat = NULL;
     SocketAddress *saddr = NULL;
     Error *local_err = NULL;
 
@@ -574,16 +571,13 @@ static SocketAddress *sd_server_config(QDict *options, Error **errp)
      * visitor expects the former.
      */
     iv = qobject_input_visitor_new(crumpled_server);
-    visit_type_SocketAddressFlat(iv, NULL, &saddr_flat, &local_err);
+    visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto done;
     }
 
-    saddr = socket_address_crumple(saddr_flat);
-
 done:
-    qapi_free_SocketAddressFlat(saddr_flat);
     visit_free(iv);
     qobject_decref(crumpled_server);
     QDECREF(server);
@@ -597,7 +591,7 @@ static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
 
     fd = socket_connect(s->addr, NULL, NULL, errp);
 
-    if (s->addr->type == SOCKET_ADDRESS_KIND_INET && fd >= 0) {
+    if (s->addr->type == SOCKET_ADDRESS_TYPE_INET && fd >= 0) {
         int ret = socket_set_nodelay(fd);
         if (ret < 0) {
             error_report("%s", strerror(errno));
diff --git a/block/snapshot.c b/block/snapshot.c
index 06b1185d27..a46564e7b7 100644
--- a/block/snapshot.c
+++ b/block/snapshot.c
@@ -200,7 +200,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
 
         qdict_extract_subqdict(options, &file_options, "file.");
         QDECREF(file_options);
-        qdict_put(options, "file", qstring_from_str(bdrv_get_node_name(file)));
+        qdict_put_str(options, "file", bdrv_get_node_name(file));
 
         drv->bdrv_close(bs);
         bdrv_unref_child(bs, bs->file);
diff --git a/block/ssh.c b/block/ssh.c
index df09f6c5ba..11203fc5a2 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -227,24 +227,23 @@ static int parse_uri(const char *filename, QDict *options, Error **errp)
     }
 
     if(uri->user && strcmp(uri->user, "") != 0) {
-        qdict_put(options, "user", qstring_from_str(uri->user));
+        qdict_put_str(options, "user", uri->user);
     }
 
-    qdict_put(options, "server.host", qstring_from_str(uri->server));
+    qdict_put_str(options, "server.host", uri->server);
 
     port_str = g_strdup_printf("%d", uri->port ?: 22);
-    qdict_put(options, "server.port", qstring_from_str(port_str));
+    qdict_put_str(options, "server.port", port_str);
     g_free(port_str);
 
-    qdict_put(options, "path", qstring_from_str(uri->path));
+    qdict_put_str(options, "path", uri->path);
 
     /* Pick out any query parameters that we understand, and ignore
      * the rest.
      */
     for (i = 0; i < qp->n; ++i) {
         if (strcmp(qp->p[i].name, "host_key_check") == 0) {
-            qdict_put(options, "host_key_check",
-                      qstring_from_str(qp->p[i].value));
+            qdict_put_str(options, "host_key_check", qp->p[i].value);
         }
     }
 
@@ -574,9 +573,8 @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
     }
 
     if (host) {
-        qdict_put(output_opts, "server.host", qstring_from_str(host));
-        qdict_put(output_opts, "server.port",
-                  qstring_from_str(port ?: stringify(22)));
+        qdict_put_str(output_opts, "server.host", host);
+        qdict_put_str(output_opts, "server.port", port ?: stringify(22));
     }
 
     return true;
diff --git a/block/vvfat.c b/block/vvfat.c
index b509d55642..9c82371360 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1057,10 +1057,10 @@ static void vvfat_parse_filename(const char *filename, QDict *options,
     }
 
     /* Fill in the options QDict */
-    qdict_put(options, "dir", qstring_from_str(filename));
-    qdict_put(options, "fat-type", qint_from_int(fat_type));
-    qdict_put(options, "floppy", qbool_from_bool(floppy));
-    qdict_put(options, "rw", qbool_from_bool(rw));
+    qdict_put_str(options, "dir", filename);
+    qdict_put_int(options, "fat-type", fat_type);
+    qdict_put_bool(options, "floppy", floppy);
+    qdict_put_bool(options, "rw", rw);
 }
 
 static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
@@ -3051,7 +3051,7 @@ static int enable_write_target(BlockDriverState *bs, Error **errp)
     }
 
     options = qdict_new();
-    qdict_put(options, "write-target.driver", qstring_from_str("qcow"));
+    qdict_put_str(options, "write-target.driver", "qcow");
     s->qcow = bdrv_open_child(s->qcow_filename, options, "write-target", bs,
                               &child_vvfat_qcow, false, errp);
     QDECREF(options);
diff --git a/block/vxhs.c b/block/vxhs.c
index 9ffe9d3814..75cc6c8672 100644
--- a/block/vxhs.c
+++ b/block/vxhs.c
@@ -182,15 +182,15 @@ static int vxhs_parse_uri(const char *filename, QDict *options)
         return -EINVAL;
     }
 
-    qdict_put(options, VXHS_OPT_SERVER".host", qstring_from_str(uri->server));
+    qdict_put_str(options, VXHS_OPT_SERVER ".host", uri->server);
 
     if (uri->port) {
         port = g_strdup_printf("%d", uri->port);
-        qdict_put(options, VXHS_OPT_SERVER".port", qstring_from_str(port));
+        qdict_put_str(options, VXHS_OPT_SERVER ".port", port);
         g_free(port);
     }
 
-    qdict_put(options, "vdisk-id", qstring_from_str(uri->path));
+    qdict_put_str(options, "vdisk-id", uri->path);
 
     trace_vxhs_parse_uri_hostinfo(uri->server, uri->port);
     uri_free(uri);
diff --git a/blockdev-nbd.c b/blockdev-nbd.c
index 8a11807df3..dd0860f4a6 100644
--- a/blockdev-nbd.c
+++ b/blockdev-nbd.c
@@ -99,9 +99,8 @@ static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
 }
 
 
-void qmp_nbd_server_start(SocketAddress *addr,
-                          bool has_tls_creds, const char *tls_creds,
-                          Error **errp)
+void nbd_server_start(SocketAddress *addr, const char *tls_creds,
+                      Error **errp)
 {
     if (nbd_server) {
         error_setg(errp, "NBD server already running");
@@ -118,14 +117,14 @@ void qmp_nbd_server_start(SocketAddress *addr,
         goto error;
     }
 
-    if (has_tls_creds) {
+    if (tls_creds) {
         nbd_server->tlscreds = nbd_get_tls_creds(tls_creds, errp);
         if (!nbd_server->tlscreds) {
             goto error;
         }
 
-        /* TODO SOCKET_ADDRESS_KIND_FD where fd has AF_INET or AF_INET6 */
-        if (addr->type != SOCKET_ADDRESS_KIND_INET) {
+        /* TODO SOCKET_ADDRESS_TYPE_FD where fd has AF_INET or AF_INET6 */
+        if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
             error_setg(errp, "TLS is only supported with IPv4/IPv6");
             goto error;
         }
@@ -145,6 +144,16 @@ void qmp_nbd_server_start(SocketAddress *addr,
     nbd_server = NULL;
 }
 
+void qmp_nbd_server_start(SocketAddressLegacy *addr,
+                          bool has_tls_creds, const char *tls_creds,
+                          Error **errp)
+{
+    SocketAddress *addr_flat = socket_address_flatten(addr);
+
+    nbd_server_start(addr_flat, tls_creds, errp);
+    qapi_free_SocketAddress(addr_flat);
+}
+
 void qmp_nbd_server_add(const char *device, bool has_writable, bool writable,
                         Error **errp)
 {
diff --git a/blockdev.c b/blockdev.c
index 4d8cdedd54..0b38c3df71 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -527,7 +527,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
             error_setg(errp, "Cannot specify both 'driver' and 'format'");
             goto early_err;
         }
-        qdict_put(bs_opts, "driver", qstring_from_str(buf));
+        qdict_put_str(bs_opts, "driver", buf);
     }
 
     on_write_error = BLOCKDEV_ON_ERROR_ENOSPC;
@@ -903,10 +903,8 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
         copy_on_read = false;
     }
 
-    qdict_put(bs_opts, BDRV_OPT_READ_ONLY,
-              qstring_from_str(read_only ? "on" : "off"));
-    qdict_put(bs_opts, "copy-on-read",
-              qstring_from_str(copy_on_read ? "on" :"off"));
+    qdict_put_str(bs_opts, BDRV_OPT_READ_ONLY, read_only ? "on" : "off");
+    qdict_put_str(bs_opts, "copy-on-read", copy_on_read ? "on" : "off");
 
     /* Controller type */
     value = qemu_opt_get(legacy_opts, "if");
@@ -1030,7 +1028,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
             new_id = g_strdup_printf("%s%s%i", if_name[type],
                                      mediastr, unit_id);
         }
-        qdict_put(bs_opts, "id", qstring_from_str(new_id));
+        qdict_put_str(bs_opts, "id", new_id);
         g_free(new_id);
     }
 
@@ -1067,7 +1065,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
             error_report("werror is not supported by this bus type");
             goto fail;
         }
-        qdict_put(bs_opts, "werror", qstring_from_str(werror));
+        qdict_put_str(bs_opts, "werror", werror);
     }
 
     rerror = qemu_opt_get(legacy_opts, "rerror");
@@ -1077,7 +1075,7 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
             error_report("rerror is not supported by this bus type");
             goto fail;
         }
-        qdict_put(bs_opts, "rerror", qstring_from_str(rerror));
+        qdict_put_str(bs_opts, "rerror", rerror);
     }
 
     /* Actual block device init: Functionality shared with blockdev-add */
@@ -1737,10 +1735,9 @@ static void external_snapshot_prepare(BlkActionState *common,
 
         options = qdict_new();
         if (s->has_snapshot_node_name) {
-            qdict_put(options, "node-name",
-                      qstring_from_str(snapshot_node_name));
+            qdict_put_str(options, "node-name", snapshot_node_name);
         }
-        qdict_put(options, "driver", qstring_from_str(format));
+        qdict_put_str(options, "driver", format);
 
         flags |= BDRV_O_NO_BACKING;
     }
@@ -2579,11 +2576,10 @@ void qmp_blockdev_change_medium(bool has_device, const char *device,
 
     options = qdict_new();
     detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
-    qdict_put(options, "detect-zeroes",
-              qstring_from_str(detect_zeroes ? "on" : "off"));
+    qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
 
     if (has_format) {
-        qdict_put(options, "driver", qstring_from_str(format));
+        qdict_put_str(options, "driver", format);
     }
 
     medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
@@ -3232,7 +3228,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
 
     if (backup->format) {
         options = qdict_new();
-        qdict_put(options, "driver", qstring_from_str(backup->format));
+        qdict_put_str(options, "driver", backup->format);
     }
 
     target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
@@ -3536,10 +3532,10 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
 
     options = qdict_new();
     if (arg->has_node_name) {
-        qdict_put(options, "node-name", qstring_from_str(arg->node_name));
+        qdict_put_str(options, "node-name", arg->node_name);
     }
     if (format) {
-        qdict_put(options, "driver", qstring_from_str(format));
+        qdict_put_str(options, "driver", format);
     }
 
     /* Mirroring takes care of copy-on-write using the source's backing
diff --git a/chardev/char-fd.c b/chardev/char-fd.c
index 548dd4cdd9..0b182c552c 100644
--- a/chardev/char-fd.c
+++ b/chardev/char-fd.c
@@ -58,7 +58,7 @@ static gboolean fd_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     ret = qio_channel_read(
         chan, (gchar *)buf, len, NULL);
     if (ret == 0) {
-        remove_fd_in_watch(chr, NULL);
+        remove_fd_in_watch(chr);
         qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
         return FALSE;
     }
@@ -89,9 +89,9 @@ static void fd_chr_update_read_handler(Chardev *chr,
 {
     FDChardev *s = FD_CHARDEV(chr);
 
-    remove_fd_in_watch(chr, NULL);
+    remove_fd_in_watch(chr);
     if (s->ioc_in) {
-        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc_in,
+        chr->gsource = io_add_watch_poll(chr, s->ioc_in,
                                            fd_chr_read_poll,
                                            fd_chr_read, chr,
                                            context);
@@ -103,7 +103,7 @@ static void char_fd_finalize(Object *obj)
     Chardev *chr = CHARDEV(obj);
     FDChardev *s = FD_CHARDEV(obj);
 
-    remove_fd_in_watch(chr, NULL);
+    remove_fd_in_watch(chr);
     if (s->ioc_in) {
         object_unref(OBJECT(s->ioc_in));
     }
diff --git a/chardev/char-io.c b/chardev/char-io.c
index b4bb094ea3..b5708eef45 100644
--- a/chardev/char-io.c
+++ b/chardev/char-io.c
@@ -98,7 +98,7 @@ static GSourceFuncs io_watch_poll_funcs = {
     .finalize = io_watch_poll_finalize,
 };
 
-guint io_add_watch_poll(Chardev *chr,
+GSource *io_add_watch_poll(Chardev *chr,
                         QIOChannel *ioc,
                         IOCanReadHandler *fd_can_read,
                         QIOChannelFunc fd_read,
@@ -106,7 +106,6 @@ guint io_add_watch_poll(Chardev *chr,
                         GMainContext *context)
 {
     IOWatchPoll *iwp;
-    int tag;
     char *name;
 
     iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs,
@@ -122,21 +121,15 @@ guint io_add_watch_poll(Chardev *chr,
     g_source_set_name((GSource *)iwp, name);
     g_free(name);
 
-    tag = g_source_attach(&iwp->parent, context);
+    g_source_attach(&iwp->parent, context);
     g_source_unref(&iwp->parent);
-    return tag;
+    return (GSource *)iwp;
 }
 
-static void io_remove_watch_poll(guint tag, GMainContext *context)
+static void io_remove_watch_poll(GSource *source)
 {
-    GSource *source;
     IOWatchPoll *iwp;
 
-    g_return_if_fail(tag > 0);
-
-    source = g_main_context_find_source_by_id(context, tag);
-    g_return_if_fail(source != NULL);
-
     iwp = io_watch_poll_from_source(source);
     if (iwp->src) {
         g_source_destroy(iwp->src);
@@ -146,11 +139,11 @@ static void io_remove_watch_poll(guint tag, GMainContext *context)
     g_source_destroy(&iwp->parent);
 }
 
-void remove_fd_in_watch(Chardev *chr, GMainContext *context)
+void remove_fd_in_watch(Chardev *chr)
 {
-    if (chr->fd_in_tag) {
-        io_remove_watch_poll(chr->fd_in_tag, context);
-        chr->fd_in_tag = 0;
+    if (chr->gsource) {
+        io_remove_watch_poll(chr->gsource);
+        chr->gsource = NULL;
     }
 }
 
diff --git a/chardev/char-io.h b/chardev/char-io.h
index 842be56bda..55973a7671 100644
--- a/chardev/char-io.h
+++ b/chardev/char-io.h
@@ -29,14 +29,14 @@
 #include "sysemu/char.h"
 
 /* Can only be used for read */
-guint io_add_watch_poll(Chardev *chr,
+GSource *io_add_watch_poll(Chardev *chr,
                         QIOChannel *ioc,
                         IOCanReadHandler *fd_can_read,
                         QIOChannelFunc fd_read,
                         gpointer user_data,
                         GMainContext *context);
 
-void remove_fd_in_watch(Chardev *chr, GMainContext *context);
+void remove_fd_in_watch(Chardev *chr);
 
 int io_channel_send(QIOChannel *ioc, const void *buf, size_t len);
 
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index 5547a36a0a..37d42c65c6 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -114,7 +114,7 @@ static void mux_print_help(Chardev *chr)
     }
 }
 
-void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
+static void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
 {
     CharBackend *be = d->backends[mux_nr];
 
@@ -222,9 +222,9 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
 
 bool muxes_realized;
 
-static void mux_chr_event(void *opaque, int event)
+void mux_chr_send_all_event(Chardev *chr, int event)
 {
-    MuxChardev *d = MUX_CHARDEV(opaque);
+    MuxChardev *d = MUX_CHARDEV(chr);
     int i;
 
     if (!muxes_realized) {
@@ -237,6 +237,11 @@ static void mux_chr_event(void *opaque, int event)
     }
 }
 
+static void mux_chr_event(void *opaque, int event)
+{
+    mux_chr_send_all_event(CHARDEV(opaque), event);
+}
+
 static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
 {
     MuxChardev *d = MUX_CHARDEV(s);
diff --git a/chardev/char-mux.h b/chardev/char-mux.h
index 9a2fffce91..3f41dfcfd2 100644
--- a/chardev/char-mux.h
+++ b/chardev/char-mux.h
@@ -58,6 +58,6 @@ typedef struct MuxChardev {
 
 void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
 void mux_set_focus(Chardev *chr, int focus);
-void mux_chr_send_event(MuxChardev *d, int mux_nr, int event);
+void mux_chr_send_all_event(Chardev *chr, int event);
 
 #endif /* CHAR_MUX_H */
diff --git a/chardev/char-pty.c b/chardev/char-pty.c
index a6337be8aa..35a175d796 100644
--- a/chardev/char-pty.c
+++ b/chardev/char-pty.c
@@ -185,7 +185,7 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
     PtyChardev *s = PTY_CHARDEV(opaque);
 
     s->open_tag = 0;
-    qemu_chr_be_generic_open(chr);
+    qemu_chr_be_event(chr, CHR_EVENT_OPENED);
     return FALSE;
 }
 
@@ -199,7 +199,7 @@ static void pty_chr_state(Chardev *chr, int connected)
             g_source_remove(s->open_tag);
             s->open_tag = 0;
         }
-        remove_fd_in_watch(chr, NULL);
+        remove_fd_in_watch(chr);
         s->connected = 0;
         /* (re-)connect poll interval for idle guests: once per second.
          * We check more frequently in case the guests sends data to
@@ -215,8 +215,8 @@ static void pty_chr_state(Chardev *chr, int connected)
             s->connected = 1;
             s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr);
         }
-        if (!chr->fd_in_tag) {
-            chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
+        if (!chr->gsource) {
+            chr->gsource = io_add_watch_poll(chr, s->ioc,
                                                pty_chr_read_poll,
                                                pty_chr_read,
                                                chr, NULL);
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 36ab0d633a..e2fb7f7cd5 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -55,6 +55,7 @@ typedef struct {
     SocketAddress *addr;
     bool is_listen;
     bool is_telnet;
+    bool is_tn3270;
 
     guint reconnect_timer;
     int64_t reconnect_time;
@@ -141,19 +142,25 @@ static int tcp_chr_read_poll(void *opaque)
     return s->max_size;
 }
 
-#define IAC 255
-#define IAC_BREAK 243
 static void tcp_chr_process_IAC_bytes(Chardev *chr,
                                       SocketChardev *s,
                                       uint8_t *buf, int *size)
 {
-    /* Handle any telnet client's basic IAC options to satisfy char by
-     * char mode with no echo.  All IAC options will be removed from
-     * the buf and the do_telnetopt variable will be used to track the
-     * state of the width of the IAC information.
+    /* Handle any telnet or tn3270 client's basic IAC options.
+     * For telnet options, it satisfies char by char mode with no echo.
+     * For tn3270 options, it satisfies binary mode with EOR.
+     * All IAC options will be removed from the buf and the do_opt
+     * pointer will be used to track the state of the width of the
+     * IAC information.
      *
-     * IAC commands come in sets of 3 bytes with the exception of the
-     * "IAC BREAK" command and the double IAC.
+     * RFC854: "All TELNET commands consist of at least a two byte sequence.
+     * The commands dealing with option negotiation are three byte sequences,
+     * the third byte being the code for the option referenced."
+     * "IAC BREAK", "IAC IP", "IAC NOP" and the double IAC are two bytes.
+     * "IAC SB", "IAC SE" and "IAC EOR" are saved to split up data boundary
+     * for tn3270.
+     * NOP, Break and Interrupt Process(IP) might be encountered during a TN3270
+     * session, and NOP and IP need to be done later.
      */
 
     int i;
@@ -174,6 +181,18 @@ static void tcp_chr_process_IAC_bytes(Chardev *chr,
                     /* Handle IAC break commands by sending a serial break */
                     qemu_chr_be_event(chr, CHR_EVENT_BREAK);
                     s->do_telnetopt++;
+                } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_EOR
+                           || (unsigned char)buf[i] == IAC_SB
+                           || (unsigned char)buf[i] == IAC_SE)
+                           && s->do_telnetopt == 2) {
+                    buf[j++] = IAC;
+                    buf[j++] = buf[i];
+                    s->do_telnetopt++;
+                } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_IP
+                           || (unsigned char)buf[i] == IAC_NOP)
+                           && s->do_telnetopt == 2) {
+                    /* TODO: IP and NOP need to be implemented later. */
+                    s->do_telnetopt++;
                 }
                 s->do_telnetopt++;
             }
@@ -327,7 +346,7 @@ static void tcp_chr_free_connection(Chardev *chr)
     }
 
     tcp_set_msgfds(chr, NULL, 0);
-    remove_fd_in_watch(chr, NULL);
+    remove_fd_in_watch(chr);
     object_unref(OBJECT(s->sioc));
     s->sioc = NULL;
     object_unref(OBJECT(s->ioc));
@@ -341,31 +360,40 @@ static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr,
                                   bool is_listen, bool is_telnet)
 {
     switch (addr->type) {
-    case SOCKET_ADDRESS_KIND_INET:
+    case SOCKET_ADDRESS_TYPE_INET:
         return g_strdup_printf("%s%s:%s:%s%s", prefix,
                                is_telnet ? "telnet" : "tcp",
-                               addr->u.inet.data->host,
-                               addr->u.inet.data->port,
+                               addr->u.inet.host,
+                               addr->u.inet.port,
                                is_listen ? ",server" : "");
         break;
-    case SOCKET_ADDRESS_KIND_UNIX:
+    case SOCKET_ADDRESS_TYPE_UNIX:
         return g_strdup_printf("%sunix:%s%s", prefix,
-                               addr->u.q_unix.data->path,
+                               addr->u.q_unix.path,
                                is_listen ? ",server" : "");
         break;
-    case SOCKET_ADDRESS_KIND_FD:
-        return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.data->str,
+    case SOCKET_ADDRESS_TYPE_FD:
+        return g_strdup_printf("%sfd:%s%s", prefix, addr->u.fd.str,
                                is_listen ? ",server" : "");
         break;
-    case SOCKET_ADDRESS_KIND_VSOCK:
+    case SOCKET_ADDRESS_TYPE_VSOCK:
         return g_strdup_printf("%svsock:%s:%s", prefix,
-                               addr->u.vsock.data->cid,
-                               addr->u.vsock.data->port);
+                               addr->u.vsock.cid,
+                               addr->u.vsock.port);
     default:
         abort();
     }
 }
 
+static void update_disconnected_filename(SocketChardev *s)
+{
+    Chardev *chr = CHARDEV(s);
+
+    g_free(chr->filename);
+    chr->filename = SocketAddress_to_str("disconnected:", s->addr,
+                                         s->is_listen, s->is_telnet);
+}
+
 static void tcp_chr_disconnect(Chardev *chr)
 {
     SocketChardev *s = SOCKET_CHARDEV(chr);
@@ -380,8 +408,7 @@ static void tcp_chr_disconnect(Chardev *chr)
         s->listen_tag = qio_channel_add_watch(
             QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
     }
-    chr->filename = SocketAddress_to_str("disconnected:", s->addr,
-                                         s->is_listen, s->is_telnet);
+    update_disconnected_filename(s);
     qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
     if (s->reconnect_time) {
         qemu_chr_socket_restart_timer(chr);
@@ -484,12 +511,12 @@ static void tcp_chr_connect(void *opaque)
 
     s->connected = 1;
     if (s->ioc) {
-        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
+        chr->gsource = io_add_watch_poll(chr, s->ioc,
                                            tcp_chr_read_poll,
                                            tcp_chr_read,
                                            chr, NULL);
     }
-    qemu_chr_be_generic_open(chr);
+    qemu_chr_be_event(chr, CHR_EVENT_OPENED);
 }
 
 static void tcp_chr_update_read_handler(Chardev *chr,
@@ -501,9 +528,9 @@ static void tcp_chr_update_read_handler(Chardev *chr,
         return;
     }
 
-    remove_fd_in_watch(chr, NULL);
+    remove_fd_in_watch(chr);
     if (s->ioc) {
-        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
+        chr->gsource = io_add_watch_poll(chr, s->ioc,
                                            tcp_chr_read_poll,
                                            tcp_chr_read, chr,
                                            context);
@@ -512,7 +539,7 @@ static void tcp_chr_update_read_handler(Chardev *chr,
 
 typedef struct {
     Chardev *chr;
-    char buf[12];
+    char buf[21];
     size_t buflen;
 } TCPChardevTelnetInit;
 
@@ -550,9 +577,6 @@ static void tcp_chr_telnet_init(Chardev *chr)
     TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
     size_t n = 0;
 
-    init->chr = chr;
-    init->buflen = 12;
-
 #define IACSET(x, a, b, c)                      \
     do {                                        \
         x[n++] = a;                             \
@@ -560,12 +584,26 @@ static void tcp_chr_telnet_init(Chardev *chr)
         x[n++] = c;                             \
     } while (0)
 
-    /* Prep the telnet negotion to put telnet in binary,
-     * no echo, single char mode */
-    IACSET(init->buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
-    IACSET(init->buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
-    IACSET(init->buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
-    IACSET(init->buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
+    init->chr = chr;
+    if (!s->is_tn3270) {
+        init->buflen = 12;
+        /* Prep the telnet negotion to put telnet in binary,
+         * no echo, single char mode */
+        IACSET(init->buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
+        IACSET(init->buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
+        IACSET(init->buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
+        IACSET(init->buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
+    } else {
+        init->buflen = 21;
+        /* Prep the TN3270 negotion based on RFC1576 */
+        IACSET(init->buf, 0xff, 0xfd, 0x19);  /* IAC DO EOR */
+        IACSET(init->buf, 0xff, 0xfb, 0x19);  /* IAC WILL EOR */
+        IACSET(init->buf, 0xff, 0xfd, 0x00);  /* IAC DO BINARY */
+        IACSET(init->buf, 0xff, 0xfb, 0x00);  /* IAC WILL BINARY */
+        IACSET(init->buf, 0xff, 0xfd, 0x18);  /* IAC DO TERMINAL TYPE */
+        IACSET(init->buf, 0xff, 0xfa, 0x18);  /* IAC SB TERMINAL TYPE */
+        IACSET(init->buf, 0x01, 0xff, 0xf0);  /* SEND IAC SE */
+    }
 
 #undef IACSET
 
@@ -585,7 +623,8 @@ static void tcp_chr_tls_handshake(QIOTask *task,
     if (qio_task_propagate_error(task, NULL)) {
         tcp_chr_disconnect(chr);
     } else {
-        if (s->do_telnetopt) {
+        /* tn3270 does not support TLS yet */
+        if (s->do_telnetopt && !s->is_tn3270) {
             tcp_chr_telnet_init(chr);
         } else {
             tcp_chr_connect(chr);
@@ -609,7 +648,7 @@ static void tcp_chr_tls_init(Chardev *chr)
     } else {
         tioc = qio_channel_tls_new_client(
             s->ioc, s->tls_creds,
-            s->addr->u.inet.data->host,
+            s->addr->u.inet.host,
             &err);
     }
     if (tioc == NULL) {
@@ -820,16 +859,18 @@ static void qmp_chardev_open_socket(Chardev *chr,
 {
     SocketChardev *s = SOCKET_CHARDEV(chr);
     ChardevSocket *sock = backend->u.socket.data;
-    SocketAddress *addr = sock->addr;
     bool do_nodelay     = sock->has_nodelay ? sock->nodelay : false;
     bool is_listen      = sock->has_server  ? sock->server  : true;
     bool is_telnet      = sock->has_telnet  ? sock->telnet  : false;
+    bool is_tn3270      = sock->has_tn3270  ? sock->tn3270  : false;
     bool is_waitconnect = sock->has_wait    ? sock->wait    : false;
     int64_t reconnect   = sock->has_reconnect ? sock->reconnect : 0;
     QIOChannelSocket *sioc = NULL;
+    SocketAddress *addr;
 
     s->is_listen = is_listen;
     s->is_telnet = is_telnet;
+    s->is_tn3270 = is_tn3270;
     s->do_nodelay = do_nodelay;
     if (sock->tls_creds) {
         Object *creds;
@@ -864,22 +905,21 @@ static void qmp_chardev_open_socket(Chardev *chr,
         }
     }
 
-    s->addr = QAPI_CLONE(SocketAddress, sock->addr);
+    s->addr = addr = socket_address_flatten(sock->addr);
 
     qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_RECONNECTABLE);
     /* TODO SOCKET_ADDRESS_FD where fd has AF_UNIX */
-    if (addr->type == SOCKET_ADDRESS_KIND_UNIX) {
+    if (addr->type == SOCKET_ADDRESS_TYPE_UNIX) {
         qemu_chr_set_feature(chr, QEMU_CHAR_FEATURE_FD_PASS);
     }
 
     /* be isn't opened until we get a connection */
     *be_opened = false;
 
-    chr->filename = SocketAddress_to_str("disconnected:",
-                                         addr, is_listen, is_telnet);
+    update_disconnected_filename(s);
 
     if (is_listen) {
-        if (is_telnet) {
+        if (is_telnet || is_tn3270) {
             s->do_telnetopt = 1;
         }
     } else if (reconnect > 0) {
@@ -904,6 +944,11 @@ static void qmp_chardev_open_socket(Chardev *chr,
             if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
                 goto error;
             }
+
+            qapi_free_SocketAddress(s->addr);
+            s->addr = socket_local_address(sioc->fd, errp);
+            update_disconnected_filename(s);
+
             s->listen_ioc = sioc;
             if (is_waitconnect &&
                 qemu_chr_wait_connected(chr, errp) < 0) {
@@ -933,13 +978,14 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
     bool is_listen      = qemu_opt_get_bool(opts, "server", false);
     bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true);
     bool is_telnet      = qemu_opt_get_bool(opts, "telnet", false);
+    bool is_tn3270      = qemu_opt_get_bool(opts, "tn3270", false);
     bool do_nodelay     = !qemu_opt_get_bool(opts, "delay", true);
     int64_t reconnect   = qemu_opt_get_number(opts, "reconnect", 0);
     const char *path = qemu_opt_get(opts, "path");
     const char *host = qemu_opt_get(opts, "host");
     const char *port = qemu_opt_get(opts, "port");
     const char *tls_creds = qemu_opt_get(opts, "tls-creds");
-    SocketAddress *addr;
+    SocketAddressLegacy *addr;
     ChardevSocket *sock;
 
     backend->type = CHARDEV_BACKEND_KIND_SOCKET;
@@ -968,20 +1014,22 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
     sock->server = is_listen;
     sock->has_telnet = true;
     sock->telnet = is_telnet;
+    sock->has_tn3270 = true;
+    sock->tn3270 = is_tn3270;
     sock->has_wait = true;
     sock->wait = is_waitconnect;
     sock->has_reconnect = true;
     sock->reconnect = reconnect;
     sock->tls_creds = g_strdup(tls_creds);
 
-    addr = g_new0(SocketAddress, 1);
+    addr = g_new0(SocketAddressLegacy, 1);
     if (path) {
         UnixSocketAddress *q_unix;
-        addr->type = SOCKET_ADDRESS_KIND_UNIX;
+        addr->type = SOCKET_ADDRESS_LEGACY_KIND_UNIX;
         q_unix = addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
         q_unix->path = g_strdup(path);
     } else {
-        addr->type = SOCKET_ADDRESS_KIND_INET;
+        addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
         addr->u.inet.data = g_new(InetSocketAddress, 1);
         *addr->u.inet.data = (InetSocketAddress) {
             .host = g_strdup(host),
@@ -997,6 +1045,23 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
     sock->addr = addr;
 }
 
+static void
+char_socket_get_addr(Object *obj, Visitor *v, const char *name,
+                     void *opaque, Error **errp)
+{
+    SocketChardev *s = SOCKET_CHARDEV(obj);
+
+    visit_type_SocketAddress(v, name, &s->addr, errp);
+}
+
+static bool
+char_socket_get_connected(Object *obj, Error **errp)
+{
+    SocketChardev *s = SOCKET_CHARDEV(obj);
+
+    return s->connected;
+}
+
 static void char_socket_class_init(ObjectClass *oc, void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -1012,6 +1077,13 @@ static void char_socket_class_init(ObjectClass *oc, void *data)
     cc->chr_add_client = tcp_chr_add_client;
     cc->chr_add_watch = tcp_chr_add_watch;
     cc->chr_update_read_handler = tcp_chr_update_read_handler;
+
+    object_class_property_add(oc, "addr", "SocketAddress",
+                              char_socket_get_addr, NULL,
+                              NULL, NULL, &error_abort);
+
+    object_class_property_add_bool(oc, "connected", char_socket_get_connected,
+                                   NULL, &error_abort);
 }
 
 static const TypeInfo char_socket_type_info = {
diff --git a/chardev/char-udp.c b/chardev/char-udp.c
index 804bd22efa..607647642a 100644
--- a/chardev/char-udp.c
+++ b/chardev/char-udp.c
@@ -51,6 +51,18 @@ static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
         s->ioc, (const char *)buf, len, NULL);
 }
 
+static void udp_chr_flush_buffer(UdpChardev *s)
+{
+    Chardev *chr = CHARDEV(s);
+
+    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+        int n = MIN(s->max_size, s->bufcnt - s->bufptr);
+        qemu_chr_be_write(chr, &s->buf[s->bufptr], n);
+        s->bufptr += n;
+        s->max_size = qemu_chr_be_can_write(chr);
+    }
+}
+
 static int udp_chr_read_poll(void *opaque)
 {
     Chardev *chr = CHARDEV(opaque);
@@ -61,11 +73,8 @@ static int udp_chr_read_poll(void *opaque)
     /* If there were any stray characters in the queue process them
      * first
      */
-    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
-        qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
-        s->bufptr++;
-        s->max_size = qemu_chr_be_can_write(chr);
-    }
+    udp_chr_flush_buffer(s);
+
     return s->max_size;
 }
 
@@ -81,17 +90,12 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
     ret = qio_channel_read(
         s->ioc, (char *)s->buf, sizeof(s->buf), NULL);
     if (ret <= 0) {
-        remove_fd_in_watch(chr, NULL);
+        remove_fd_in_watch(chr);
         return FALSE;
     }
     s->bufcnt = ret;
-
     s->bufptr = 0;
-    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
-        qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
-        s->bufptr++;
-        s->max_size = qemu_chr_be_can_write(chr);
-    }
+    udp_chr_flush_buffer(s);
 
     return TRUE;
 }
@@ -101,9 +105,9 @@ static void udp_chr_update_read_handler(Chardev *chr,
 {
     UdpChardev *s = UDP_CHARDEV(chr);
 
-    remove_fd_in_watch(chr, NULL);
+    remove_fd_in_watch(chr);
     if (s->ioc) {
-        chr->fd_in_tag = io_add_watch_poll(chr, s->ioc,
+        chr->gsource = io_add_watch_poll(chr, s->ioc,
                                            udp_chr_read_poll,
                                            udp_chr_read, chr,
                                            context);
@@ -115,7 +119,7 @@ static void char_udp_finalize(Object *obj)
     Chardev *chr = CHARDEV(obj);
     UdpChardev *s = UDP_CHARDEV(obj);
 
-    remove_fd_in_watch(chr, NULL);
+    remove_fd_in_watch(chr);
     if (s->ioc) {
         object_unref(OBJECT(s->ioc));
     }
@@ -130,7 +134,7 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
     const char *localaddr = qemu_opt_get(opts, "localaddr");
     const char *localport = qemu_opt_get(opts, "localport");
     bool has_local = false;
-    SocketAddress *addr;
+    SocketAddressLegacy *addr;
     ChardevUdp *udp;
 
     backend->type = CHARDEV_BACKEND_KIND_UDP;
@@ -155,8 +159,8 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
     udp = backend->u.udp.data = g_new0(ChardevUdp, 1);
     qemu_chr_parse_common(opts, qapi_ChardevUdp_base(udp));
 
-    addr = g_new0(SocketAddress, 1);
-    addr->type = SOCKET_ADDRESS_KIND_INET;
+    addr = g_new0(SocketAddressLegacy, 1);
+    addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
     addr->u.inet.data = g_new(InetSocketAddress, 1);
     *addr->u.inet.data = (InetSocketAddress) {
         .host = g_strdup(host),
@@ -170,8 +174,8 @@ static void qemu_chr_parse_udp(QemuOpts *opts, ChardevBackend *backend,
 
     if (has_local) {
         udp->has_local = true;
-        addr = g_new0(SocketAddress, 1);
-        addr->type = SOCKET_ADDRESS_KIND_INET;
+        addr = g_new0(SocketAddressLegacy, 1);
+        addr->type = SOCKET_ADDRESS_LEGACY_KIND_INET;
         addr->u.inet.data = g_new(InetSocketAddress, 1);
         *addr->u.inet.data = (InetSocketAddress) {
             .host = g_strdup(localaddr),
@@ -187,13 +191,17 @@ static void qmp_chardev_open_udp(Chardev *chr,
                                  Error **errp)
 {
     ChardevUdp *udp = backend->u.udp.data;
+    SocketAddress *local_addr = socket_address_flatten(udp->local);
+    SocketAddress *remote_addr = socket_address_flatten(udp->remote);
     QIOChannelSocket *sioc = qio_channel_socket_new();
     char *name;
     UdpChardev *s = UDP_CHARDEV(chr);
+    int ret;
 
-    if (qio_channel_socket_dgram_sync(sioc,
-                                      udp->local, udp->remote,
-                                      errp) < 0) {
+    ret = qio_channel_socket_dgram_sync(sioc, local_addr, remote_addr, errp);
+    qapi_free_SocketAddress(local_addr);
+    qapi_free_SocketAddress(remote_addr);
+    if (ret < 0) {
         object_unref(OBJECT(sioc));
         return;
     }
diff --git a/chardev/char.c b/chardev/char.c
index 3df116350b..4e24dc39af 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -42,8 +42,10 @@
 /***********************************************************/
 /* character device */
 
-static QTAILQ_HEAD(ChardevHead, Chardev) chardevs =
-    QTAILQ_HEAD_INITIALIZER(chardevs);
+static Object *get_chardevs_root(void)
+{
+    return container_get(object_get_root(), "/chardevs");
+}
 
 void qemu_chr_be_event(Chardev *s, int event)
 {
@@ -66,12 +68,6 @@ void qemu_chr_be_event(Chardev *s, int event)
     be->chr_event(be->opaque, event);
 }
 
-void qemu_chr_be_generic_open(Chardev *s)
-{
-    qemu_chr_be_event(s, CHR_EVENT_OPENED);
-}
-
-
 /* Not reporting errors from writing to logfile, as logs are
  * defined to be "best effort" only */
 static void qemu_chr_fe_write_log(Chardev *s,
@@ -453,26 +449,24 @@ static const TypeInfo char_type_info = {
  * mux will receive CHR_EVENT_OPENED notifications for the BE
  * immediately.
  */
-static void muxes_realize_done(Notifier *notifier, void *unused)
+static int open_muxes(Object *child, void *opaque)
 {
-    Chardev *chr;
+    if (CHARDEV_IS_MUX(child)) {
+        /* send OPENED to all already-attached FEs */
+        mux_chr_send_all_event(CHARDEV(child), CHR_EVENT_OPENED);
+        /* mark mux as OPENED so any new FEs will immediately receive
+         * OPENED event
+         */
+        qemu_chr_be_event(CHARDEV(child), CHR_EVENT_OPENED);
+    }
 
-    QTAILQ_FOREACH(chr, &chardevs, next) {
-        if (CHARDEV_IS_MUX(chr)) {
-            MuxChardev *d = MUX_CHARDEV(chr);
-            int i;
+    return 0;
+}
 
-            /* send OPENED to all already-attached FEs */
-            for (i = 0; i < d->mux_cnt; i++) {
-                mux_chr_send_event(d, i, CHR_EVENT_OPENED);
-            }
-            /* mark mux as OPENED so any new FEs will immediately receive
-             * OPENED event
-             */
-            qemu_chr_be_generic_open(chr);
-        }
-    }
+static void muxes_realize_done(Notifier *notifier, void *unused)
+{
     muxes_realized = true;
+    object_child_foreach(get_chardevs_root(), open_muxes, NULL);
 }
 
 static Notifier muxes_realize_notify = {
@@ -560,7 +554,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
     cc = CHARDEV_GET_CLASS(s);
     if (!opaque && !fd_can_read && !fd_read && !fd_event) {
         fe_open = 0;
-        remove_fd_in_watch(s, context);
+        remove_fd_in_watch(s);
     } else {
         fe_open = 1;
     }
@@ -581,7 +575,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
         /* We're connecting to an already opened device, so let's make sure we
            also get the open event */
         if (s->be_open) {
-            qemu_chr_be_generic_open(s);
+            qemu_chr_be_event(s, CHR_EVENT_OPENED);
         }
     }
 
@@ -696,7 +690,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
         return opts;
     }
     if (strstart(filename, "tcp:", &p) ||
-        strstart(filename, "telnet:", &p)) {
+        strstart(filename, "telnet:", &p) ||
+        strstart(filename, "tn3270:", &p)) {
         if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
             host[0] = 0;
             if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
@@ -712,8 +707,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
                 goto fail;
             }
         }
-        if (strstart(filename, "telnet:", &p))
+        if (strstart(filename, "telnet:", &p)) {
             qemu_opt_set(opts, "telnet", "on", &error_abort);
+        } else if (strstart(filename, "tn3270:", &p)) {
+            qemu_opt_set(opts, "tn3270", "on", &error_abort);
+        }
         return opts;
     }
     if (strstart(filename, "udp:", &p)) {
@@ -770,7 +768,7 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
     const char *logfile = qemu_opt_get(opts, "logfile");
 
     backend->has_logfile = logfile != NULL;
-    backend->logfile = logfile ? g_strdup(logfile) : NULL;
+    backend->logfile = g_strdup(logfile);
 
     backend->has_logappend = true;
     backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
@@ -805,26 +803,6 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
     return cc;
 }
 
-static Chardev *qemu_chardev_add(const char *id, const char *typename,
-                                 ChardevBackend *backend, Error **errp)
-{
-    Chardev *chr;
-
-    chr = qemu_chr_find(id);
-    if (chr) {
-        error_setg(errp, "Chardev '%s' already exists", id);
-        return NULL;
-    }
-
-    chr = qemu_chardev_new(id, typename, backend, errp);
-    if (!chr) {
-        return NULL;
-    }
-
-    QTAILQ_INSERT_TAIL(&chardevs, chr, next);
-    return chr;
-}
-
 static const struct ChardevAlias {
     const char *typename;
     const char *alias;
@@ -941,9 +919,10 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
         backend->u.null.data = ccom; /* Any ChardevCommon member would work */
     }
 
-    chr = qemu_chardev_add(bid ? bid : id,
+    chr = qemu_chardev_new(bid ? bid : id,
                            object_class_get_name(OBJECT_CLASS(cc)),
                            backend, errp);
+
     if (chr == NULL) {
         goto out;
     }
@@ -955,9 +934,9 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
         backend->type = CHARDEV_BACKEND_KIND_MUX;
         backend->u.mux.data = g_new0(ChardevMux, 1);
         backend->u.mux.data->chardev = g_strdup(bid);
-        mux = qemu_chardev_add(id, TYPE_CHARDEV_MUX, backend, errp);
+        mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, errp);
         if (mux == NULL) {
-            qemu_chr_delete(chr);
+            object_unparent(OBJECT(chr));
             chr = NULL;
             goto out;
         }
@@ -1071,27 +1050,29 @@ void qemu_chr_fe_disconnect(CharBackend *be)
     }
 }
 
-void qemu_chr_delete(Chardev *chr)
+static int qmp_query_chardev_foreach(Object *obj, void *data)
 {
-    QTAILQ_REMOVE(&chardevs, chr, next);
-    object_unref(OBJECT(chr));
+    Chardev *chr = CHARDEV(obj);
+    ChardevInfoList **list = data;
+    ChardevInfoList *info = g_malloc0(sizeof(*info));
+
+    info->value = g_malloc0(sizeof(*info->value));
+    info->value->label = g_strdup(chr->label);
+    info->value->filename = g_strdup(chr->filename);
+    info->value->frontend_open = chr->be && chr->be->fe_open;
+
+    info->next = *list;
+    *list = info;
+
+    return 0;
 }
 
 ChardevInfoList *qmp_query_chardev(Error **errp)
 {
     ChardevInfoList *chr_list = NULL;
-    Chardev *chr;
-
-    QTAILQ_FOREACH(chr, &chardevs, next) {
-        ChardevInfoList *info = g_malloc0(sizeof(*info));
-        info->value = g_malloc0(sizeof(*info->value));
-        info->value->label = g_strdup(chr->label);
-        info->value->filename = g_strdup(chr->filename);
-        info->value->frontend_open = chr->be && chr->be->fe_open;
 
-        info->next = chr_list;
-        chr_list = info;
-    }
+    object_child_foreach(get_chardevs_root(),
+                         qmp_query_chardev_foreach, &chr_list);
 
     return chr_list;
 }
@@ -1119,14 +1100,9 @@ ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
 
 Chardev *qemu_chr_find(const char *name)
 {
-    Chardev *chr;
+    Object *obj = object_resolve_path_component(get_chardevs_root(), name);
 
-    QTAILQ_FOREACH(chr, &chardevs, next) {
-        if (strcmp(chr->label, name) != 0)
-            continue;
-        return chr;
-    }
-    return NULL;
+    return obj ? CHARDEV(obj) : NULL;
 }
 
 QemuOptsList qemu_chardev_opts = {
@@ -1177,6 +1153,9 @@ QemuOptsList qemu_chardev_opts = {
             .name = "telnet",
             .type = QEMU_OPT_BOOL,
         },{
+            .name = "tn3270",
+            .type = QEMU_OPT_BOOL,
+        },{
             .name = "tls-creds",
             .type = QEMU_OPT_STRING,
         },{
@@ -1236,22 +1215,23 @@ void qemu_chr_set_feature(Chardev *chr,
 }
 
 Chardev *qemu_chardev_new(const char *id, const char *typename,
-                          ChardevBackend *backend, Error **errp)
+                          ChardevBackend *backend,
+                          Error **errp)
 {
+    Object *obj;
     Chardev *chr = NULL;
     Error *local_err = NULL;
     bool be_opened = true;
 
     assert(g_str_has_prefix(typename, "chardev-"));
 
-    chr = CHARDEV(object_new(typename));
+    obj = object_new(typename);
+    chr = CHARDEV(obj);
     chr->label = g_strdup(id);
 
     qemu_char_open(chr, backend, &be_opened, &local_err);
     if (local_err) {
-        error_propagate(errp, local_err);
-        object_unref(OBJECT(chr));
-        return NULL;
+        goto end;
     }
 
     if (!chr->filename) {
@@ -1261,6 +1241,21 @@ Chardev *qemu_chardev_new(const char *id, const char *typename,
         qemu_chr_be_event(chr, CHR_EVENT_OPENED);
     }
 
+    if (id) {
+        object_property_add_child(get_chardevs_root(), id, obj, &local_err);
+        if (local_err) {
+            goto end;
+        }
+        object_unref(obj);
+    }
+
+end:
+    if (local_err) {
+        error_propagate(errp, local_err);
+        object_unref(obj);
+        return NULL;
+    }
+
     return chr;
 }
 
@@ -1276,7 +1271,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
         return NULL;
     }
 
-    chr = qemu_chardev_add(id, object_class_get_name(OBJECT_CLASS(cc)),
+    chr = qemu_chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
                            backend, errp);
     if (!chr) {
         return NULL;
@@ -1309,16 +1304,12 @@ void qmp_chardev_remove(const char *id, Error **errp)
             "Chardev '%s' cannot be unplugged in record/replay mode", id);
         return;
     }
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
 }
 
 void qemu_chr_cleanup(void)
 {
-    Chardev *chr, *tmp;
-
-    QTAILQ_FOREACH_SAFE(chr, &chardevs, next, tmp) {
-        qemu_chr_delete(chr);
-    }
+    object_unparent(get_chardevs_root());
 }
 
 static void register_types(void)
diff --git a/configure b/configure
index 39aadba813..7c020c076b 100755
--- a/configure
+++ b/configure
@@ -6041,9 +6041,11 @@ TARGET_ABI_DIR=""
 
 case "$target_name" in
   i386)
+    gdb_xml_files="i386-32bit-core.xml"
   ;;
   x86_64)
     TARGET_BASE_ARCH=i386
+    gdb_xml_files="i386-64bit-core.xml"
   ;;
   alpha)
     mttcg="yes"
diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c
index af4faad60b..61e1657e41 100644
--- a/contrib/libvhost-user/libvhost-user.c
+++ b/contrib/libvhost-user/libvhost-user.c
@@ -81,7 +81,7 @@ vu_panic(VuDev *dev, const char *msg, ...)
     va_list ap;
 
     va_start(ap, msg);
-    (void)vasprintf(&buf, msg, ap);
+    buf = g_strdup_vprintf(msg, ap);
     va_end(ap);
 
     dev->broken = true;
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index d5a31bbaeb..2b97d89a69 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -473,9 +473,9 @@ qcrypto_block_luks_load_key(QCryptoBlock *block,
      * then encrypted.
      */
     rv = readfunc(block,
-                  opaque,
                   slot->key_offset * QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
                   splitkey, splitkeylen,
+                  opaque,
                   errp);
     if (rv < 0) {
         goto cleanup;
@@ -676,9 +676,10 @@ qcrypto_block_luks_open(QCryptoBlock *block,
 
     /* Read the entire LUKS header, minus the key material from
      * the underlying device */
-    rv = readfunc(block, opaque, 0,
+    rv = readfunc(block, 0,
                   (uint8_t *)&luks->header,
                   sizeof(luks->header),
+                  opaque,
                   errp);
     if (rv < 0) {
         ret = rv;
@@ -1245,7 +1246,7 @@ qcrypto_block_luks_create(QCryptoBlock *block,
         QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;
 
     /* Reserve header space to match payload offset */
-    initfunc(block, opaque, block->payload_offset, &local_err);
+    initfunc(block, block->payload_offset, opaque, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto error;
@@ -1267,9 +1268,10 @@ qcrypto_block_luks_create(QCryptoBlock *block,
 
 
     /* Write out the partition header and key slot headers */
-    writefunc(block, opaque, 0,
+    writefunc(block, 0,
               (const uint8_t *)&luks->header,
               sizeof(luks->header),
+              opaque,
               &local_err);
 
     /* Delay checking local_err until we've byte-swapped */
@@ -1295,10 +1297,11 @@ qcrypto_block_luks_create(QCryptoBlock *block,
 
     /* Write out the master key material, starting at the
      * sector immediately following the partition header. */
-    if (writefunc(block, opaque,
+    if (writefunc(block,
                   luks->header.key_slots[0].key_offset *
                   QCRYPTO_BLOCK_LUKS_SECTOR_SIZE,
                   splitkey, splitkeylen,
+                  opaque,
                   errp) != splitkeylen) {
         goto error;
     }
diff --git a/crypto/init.c b/crypto/init.c
index f65207e57d..f131c42306 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -32,6 +32,8 @@
 #include <gcrypt.h>
 #endif
 
+#include "crypto/random.h"
+
 /* #define DEBUG_GNUTLS */
 
 /*
@@ -146,5 +148,9 @@ int qcrypto_init(Error **errp)
     gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
 #endif
 
+    if (qcrypto_random_init(errp) < 0) {
+        return -1;
+    }
+
     return 0;
 }
diff --git a/crypto/random-gcrypt.c b/crypto/random-gcrypt.c
index 0de9a096df..9f1c9ee60e 100644
--- a/crypto/random-gcrypt.c
+++ b/crypto/random-gcrypt.c
@@ -31,3 +31,5 @@ int qcrypto_random_bytes(uint8_t *buf,
     gcry_randomize(buf, buflen, GCRY_STRONG_RANDOM);
     return 0;
 }
+
+int qcrypto_random_init(Error **errp G_GNUC_UNUSED) { return 0; }
diff --git a/crypto/random-gnutls.c b/crypto/random-gnutls.c
index 04b45a8f8f..5350003a0b 100644
--- a/crypto/random-gnutls.c
+++ b/crypto/random-gnutls.c
@@ -41,3 +41,6 @@ int qcrypto_random_bytes(uint8_t *buf,
 
     return 0;
 }
+
+
+int qcrypto_random_init(Error **errp G_GNUC_UNUSED) { return 0; }
diff --git a/crypto/random-platform.c b/crypto/random-platform.c
index 82b755afad..0eddb915b7 100644
--- a/crypto/random-platform.c
+++ b/crypto/random-platform.c
@@ -22,14 +22,16 @@
 
 #include "crypto/random.h"
 
-int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
-                         size_t buflen G_GNUC_UNUSED,
-                         Error **errp)
-{
-    int fd;
-    int ret = -1;
-    int got;
+#ifdef _WIN32
+#include <Wincrypt.h>
+static HCRYPTPROV hCryptProv;
+#else
+static int fd; /* a file handle to either /dev/urandom or /dev/random */
+#endif
 
+int qcrypto_random_init(Error **errp)
+{
+#ifndef _WIN32
     /* TBD perhaps also add support for BSD getentropy / Linux
      * getrandom syscalls directly */
     fd = open("/dev/urandom", O_RDONLY);
@@ -41,6 +43,25 @@ int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
         error_setg(errp, "No /dev/urandom or /dev/random found");
         return -1;
     }
+#else
+    if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
+                             CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) {
+        error_setg_win32(errp, GetLastError(),
+                         "Unable to create cryptographic provider");
+        return -1;
+    }
+#endif
+
+    return 0;
+}
+
+int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
+                         size_t buflen G_GNUC_UNUSED,
+                         Error **errp)
+{
+#ifndef _WIN32
+    int ret = -1;
+    int got;
 
     while (buflen > 0) {
         got = read(fd, buf, buflen);
@@ -59,6 +80,14 @@ int qcrypto_random_bytes(uint8_t *buf G_GNUC_UNUSED,
 
     ret = 0;
  cleanup:
-    close(fd);
     return ret;
+#else
+    if (!CryptGenRandom(hCryptProv, buflen, buf)) {
+        error_setg_win32(errp, GetLastError(),
+                         "Unable to read random bytes");
+        return -1;
+    }
+
+    return 0;
+#endif
 }
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index 36e15de336..9615a48f80 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -2,6 +2,7 @@ CONFIG_PCI=y
 CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO=y
 CONFIG_SCLPCONSOLE=y
+CONFIG_TERMINAL3270=y
 CONFIG_S390_FLIC=y
 CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
 CONFIG_WDT_DIAG288=y
diff --git a/dump.c b/dump.c
index f7b80d856b..d9090a24cc 100644
--- a/dump.c
+++ b/dump.c
@@ -77,7 +77,13 @@ static int dump_cleanup(DumpState *s)
     memory_mapping_list_free(&s->list);
     close(s->fd);
     if (s->resume) {
+        if (s->detached) {
+            qemu_mutex_lock_iothread();
+        }
         vm_start();
+        if (s->detached) {
+            qemu_mutex_unlock_iothread();
+        }
     }
 
     return 0;
@@ -1804,6 +1810,7 @@ void qmp_dump_guest_memory(bool paging, const char *file,
 
     if (detach_p) {
         /* detached dump */
+        s->detached = true;
         qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread,
                            s, QEMU_THREAD_DETACHED);
     } else {
diff --git a/gdb-xml/i386-32bit-core.xml b/gdb-xml/i386-32bit-core.xml
new file mode 100644
index 0000000000..7aeeeca3b2
--- /dev/null
+++ b/gdb-xml/i386-32bit-core.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010-2015 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.core">
+  <flags id="i386_eflags" size="4">
+    <field name="CF" start="0" end="0"/>
+    <field name="" start="1" end="1"/>
+    <field name="PF" start="2" end="2"/>
+    <field name="AF" start="4" end="4"/>
+    <field name="ZF" start="6" end="6"/>
+    <field name="SF" start="7" end="7"/>
+    <field name="TF" start="8" end="8"/>
+    <field name="IF" start="9" end="9"/>
+    <field name="DF" start="10" end="10"/>
+    <field name="OF" start="11" end="11"/>
+    <field name="NT" start="14" end="14"/>
+    <field name="RF" start="16" end="16"/>
+    <field name="VM" start="17" end="17"/>
+    <field name="AC" start="18" end="18"/>
+    <field name="VIF" start="19" end="19"/>
+    <field name="VIP" start="20" end="20"/>
+    <field name="ID" start="21" end="21"/>
+  </flags>
+
+  <reg name="eax" bitsize="32" type="int32"/>
+  <reg name="ecx" bitsize="32" type="int32"/>
+  <reg name="edx" bitsize="32" type="int32"/>
+  <reg name="ebx" bitsize="32" type="int32"/>
+  <reg name="esp" bitsize="32" type="data_ptr"/>
+  <reg name="ebp" bitsize="32" type="data_ptr"/>
+  <reg name="esi" bitsize="32" type="int32"/>
+  <reg name="edi" bitsize="32" type="int32"/>
+
+  <reg name="eip" bitsize="32" type="code_ptr"/>
+  <reg name="eflags" bitsize="32" type="i386_eflags"/>
+  <reg name="cs" bitsize="32" type="int32"/>
+  <reg name="ss" bitsize="32" type="int32"/>
+  <reg name="ds" bitsize="32" type="int32"/>
+  <reg name="es" bitsize="32" type="int32"/>
+  <reg name="fs" bitsize="32" type="int32"/>
+  <reg name="gs" bitsize="32" type="int32"/>
+
+  <reg name="st0" bitsize="80" type="i387_ext"/>
+  <reg name="st1" bitsize="80" type="i387_ext"/>
+  <reg name="st2" bitsize="80" type="i387_ext"/>
+  <reg name="st3" bitsize="80" type="i387_ext"/>
+  <reg name="st4" bitsize="80" type="i387_ext"/>
+  <reg name="st5" bitsize="80" type="i387_ext"/>
+  <reg name="st6" bitsize="80" type="i387_ext"/>
+  <reg name="st7" bitsize="80" type="i387_ext"/>
+
+  <reg name="fctrl" bitsize="32" type="int" group="float"/>
+  <reg name="fstat" bitsize="32" type="int" group="float"/>
+  <reg name="ftag" bitsize="32" type="int" group="float"/>
+  <reg name="fiseg" bitsize="32" type="int" group="float"/>
+  <reg name="fioff" bitsize="32" type="int" group="float"/>
+  <reg name="foseg" bitsize="32" type="int" group="float"/>
+  <reg name="fooff" bitsize="32" type="int" group="float"/>
+  <reg name="fop" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/gdb-xml/i386-64bit-core.xml b/gdb-xml/i386-64bit-core.xml
new file mode 100644
index 0000000000..5088d84ceb
--- /dev/null
+++ b/gdb-xml/i386-64bit-core.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2010-2015 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.i386.core">
+  <flags id="i386_eflags" size="4">
+    <field name="CF" start="0" end="0"/>
+    <field name="" start="1" end="1"/>
+    <field name="PF" start="2" end="2"/>
+    <field name="AF" start="4" end="4"/>
+    <field name="ZF" start="6" end="6"/>
+    <field name="SF" start="7" end="7"/>
+    <field name="TF" start="8" end="8"/>
+    <field name="IF" start="9" end="9"/>
+    <field name="DF" start="10" end="10"/>
+    <field name="OF" start="11" end="11"/>
+    <field name="NT" start="14" end="14"/>
+    <field name="RF" start="16" end="16"/>
+    <field name="VM" start="17" end="17"/>
+    <field name="AC" start="18" end="18"/>
+    <field name="VIF" start="19" end="19"/>
+    <field name="VIP" start="20" end="20"/>
+    <field name="ID" start="21" end="21"/>
+  </flags>
+
+  <reg name="rax" bitsize="64" type="int64"/>
+  <reg name="rbx" bitsize="64" type="int64"/>
+  <reg name="rcx" bitsize="64" type="int64"/>
+  <reg name="rdx" bitsize="64" type="int64"/>
+  <reg name="rsi" bitsize="64" type="int64"/>
+  <reg name="rdi" bitsize="64" type="int64"/>
+  <reg name="rbp" bitsize="64" type="data_ptr"/>
+  <reg name="rsp" bitsize="64" type="data_ptr"/>
+  <reg name="r8" bitsize="64" type="int64"/>
+  <reg name="r9" bitsize="64" type="int64"/>
+  <reg name="r10" bitsize="64" type="int64"/>
+  <reg name="r11" bitsize="64" type="int64"/>
+  <reg name="r12" bitsize="64" type="int64"/>
+  <reg name="r13" bitsize="64" type="int64"/>
+  <reg name="r14" bitsize="64" type="int64"/>
+  <reg name="r15" bitsize="64" type="int64"/>
+
+  <reg name="rip" bitsize="64" type="code_ptr"/>
+  <reg name="eflags" bitsize="32" type="i386_eflags"/>
+  <reg name="cs" bitsize="32" type="int32"/>
+  <reg name="ss" bitsize="32" type="int32"/>
+  <reg name="ds" bitsize="32" type="int32"/>
+  <reg name="es" bitsize="32" type="int32"/>
+  <reg name="fs" bitsize="32" type="int32"/>
+  <reg name="gs" bitsize="32" type="int32"/>
+
+  <reg name="st0" bitsize="80" type="i387_ext"/>
+  <reg name="st1" bitsize="80" type="i387_ext"/>
+  <reg name="st2" bitsize="80" type="i387_ext"/>
+  <reg name="st3" bitsize="80" type="i387_ext"/>
+  <reg name="st4" bitsize="80" type="i387_ext"/>
+  <reg name="st5" bitsize="80" type="i387_ext"/>
+  <reg name="st6" bitsize="80" type="i387_ext"/>
+  <reg name="st7" bitsize="80" type="i387_ext"/>
+
+  <reg name="fctrl" bitsize="32" type="int" group="float"/>
+  <reg name="fstat" bitsize="32" type="int" group="float"/>
+  <reg name="ftag" bitsize="32" type="int" group="float"/>
+  <reg name="fiseg" bitsize="32" type="int" group="float"/>
+  <reg name="fioff" bitsize="32" type="int" group="float"/>
+  <reg name="foseg" bitsize="32" type="int" group="float"/>
+  <reg name="fooff" bitsize="32" type="int" group="float"/>
+  <reg name="fop" bitsize="32" type="int" group="float"/>
+</feature>
diff --git a/gdbstub.c b/gdbstub.c
index 991115361e..86eed4f97c 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -286,6 +286,8 @@ enum RSState {
     RS_INACTIVE,
     RS_IDLE,
     RS_GETLINE,
+    RS_GETLINE_ESC,
+    RS_GETLINE_RLE,
     RS_CHKSUM1,
     RS_CHKSUM2,
 };
@@ -296,7 +298,8 @@ typedef struct GDBState {
     enum RSState state; /* parsing state */
     char line_buf[MAX_PACKET_LENGTH];
     int line_buf_index;
-    int line_csum;
+    int line_sum; /* running checksum */
+    int line_csum; /* checksum at the end of the packet */
     uint8_t last_packet[MAX_PACKET_LENGTH + 4];
     int last_packet_len;
     int signal;
@@ -1508,7 +1511,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
 
 static void gdb_read_byte(GDBState *s, int ch)
 {
-    int i, csum;
     uint8_t reply;
 
 #ifndef CONFIG_USER_ONLY
@@ -1542,35 +1544,123 @@ static void gdb_read_byte(GDBState *s, int ch)
         switch(s->state) {
         case RS_IDLE:
             if (ch == '$') {
+                /* start of command packet */
                 s->line_buf_index = 0;
+                s->line_sum = 0;
                 s->state = RS_GETLINE;
+            } else {
+#ifdef DEBUG_GDB
+                printf("gdbstub received garbage between packets: 0x%x\n", ch);
+#endif
             }
             break;
         case RS_GETLINE:
+            if (ch == '}') {
+                /* start escape sequence */
+                s->state = RS_GETLINE_ESC;
+                s->line_sum += ch;
+            } else if (ch == '*') {
+                /* start run length encoding sequence */
+                s->state = RS_GETLINE_RLE;
+                s->line_sum += ch;
+            } else if (ch == '#') {
+                /* end of command, start of checksum*/
+                s->state = RS_CHKSUM1;
+            } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+#ifdef DEBUG_GDB
+                printf("gdbstub command buffer overrun, dropping command\n");
+#endif
+                s->state = RS_IDLE;
+            } else {
+                /* unescaped command character */
+                s->line_buf[s->line_buf_index++] = ch;
+                s->line_sum += ch;
+            }
+            break;
+        case RS_GETLINE_ESC:
             if (ch == '#') {
-            s->state = RS_CHKSUM1;
+                /* unexpected end of command in escape sequence */
+                s->state = RS_CHKSUM1;
             } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+                /* command buffer overrun */
+#ifdef DEBUG_GDB
+                printf("gdbstub command buffer overrun, dropping command\n");
+#endif
                 s->state = RS_IDLE;
             } else {
-            s->line_buf[s->line_buf_index++] = ch;
+                /* parse escaped character and leave escape state */
+                s->line_buf[s->line_buf_index++] = ch ^ 0x20;
+                s->line_sum += ch;
+                s->state = RS_GETLINE;
+            }
+            break;
+        case RS_GETLINE_RLE:
+            if (ch < ' ') {
+                /* invalid RLE count encoding */
+#ifdef DEBUG_GDB
+                printf("gdbstub got invalid RLE count: 0x%x\n", ch);
+#endif
+                s->state = RS_GETLINE;
+            } else {
+                /* decode repeat length */
+                int repeat = (unsigned char)ch - ' ' + 3;
+                if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
+                    /* that many repeats would overrun the command buffer */
+#ifdef DEBUG_GDB
+                    printf("gdbstub command buffer overrun,"
+                           " dropping command\n");
+#endif
+                    s->state = RS_IDLE;
+                } else if (s->line_buf_index < 1) {
+                    /* got a repeat but we have nothing to repeat */
+#ifdef DEBUG_GDB
+                    printf("gdbstub got invalid RLE sequence\n");
+#endif
+                    s->state = RS_GETLINE;
+                } else {
+                    /* repeat the last character */
+                    memset(s->line_buf + s->line_buf_index,
+                           s->line_buf[s->line_buf_index - 1], repeat);
+                    s->line_buf_index += repeat;
+                    s->line_sum += ch;
+                    s->state = RS_GETLINE;
+                }
             }
             break;
         case RS_CHKSUM1:
+            /* get high hex digit of checksum */
+            if (!isxdigit(ch)) {
+#ifdef DEBUG_GDB
+                printf("gdbstub got invalid command checksum digit\n");
+#endif
+                s->state = RS_GETLINE;
+                break;
+            }
             s->line_buf[s->line_buf_index] = '\0';
             s->line_csum = fromhex(ch) << 4;
             s->state = RS_CHKSUM2;
             break;
         case RS_CHKSUM2:
-            s->line_csum |= fromhex(ch);
-            csum = 0;
-            for(i = 0; i < s->line_buf_index; i++) {
-                csum += s->line_buf[i];
+            /* get low hex digit of checksum */
+            if (!isxdigit(ch)) {
+#ifdef DEBUG_GDB
+                printf("gdbstub got invalid command checksum digit\n");
+#endif
+                s->state = RS_GETLINE;
+                break;
             }
-            if (s->line_csum != (csum & 0xff)) {
+            s->line_csum |= fromhex(ch);
+
+            if (s->line_csum != (s->line_sum & 0xff)) {
+                /* send NAK reply */
                 reply = '-';
                 put_buffer(s, &reply, 1);
+#ifdef DEBUG_GDB
+                printf("gdbstub got command packet with incorrect checksum\n");
+#endif
                 s->state = RS_IDLE;
             } else {
+                /* send ACK reply */
                 reply = '+';
                 put_buffer(s, &reply, 1);
                 s->state = gdb_handle_packet(s, s->line_buf);
@@ -1611,7 +1701,7 @@ void gdb_exit(CPUArchState *env, int code)
 
 #ifndef CONFIG_USER_ONLY
   qemu_chr_fe_deinit(&s->chr);
-  qemu_chr_delete(chr);
+  object_unparent(OBJECT(chr));
 #endif
 }
 
@@ -1912,7 +2002,7 @@ int gdbserver_start(const char *device)
         monitor_init(mon_chr, 0);
     } else {
         if (qemu_chr_fe_get_driver(&s->chr)) {
-            qemu_chr_delete(qemu_chr_fe_get_driver(&s->chr));
+            object_unparent(OBJECT(qemu_chr_fe_get_driver(&s->chr)));
         }
         mon_chr = s->mon_chr;
         memset(s, 0, sizeof(GDBState));
diff --git a/hmp.c b/hmp.c
index ab407d6fd0..524e5890de 100644
--- a/hmp.c
+++ b/hmp.c
@@ -19,6 +19,7 @@
 #include "net/eth.h"
 #include "sysemu/char.h"
 #include "sysemu/block-backend.h"
+#include "sysemu/sysemu.h"
 #include "qemu/config-file.h"
 #include "qemu/option.h"
 #include "qemu/timer.h"
@@ -33,6 +34,7 @@
 #include "qapi-visit.h"
 #include "qom/object_interfaces.h"
 #include "ui/console.h"
+#include "block/nbd.h"
 #include "block/qapi.h"
 #include "qemu-io.h"
 #include "qemu/cutils.h"
@@ -1268,6 +1270,179 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
     hmp_handle_error(mon, &err);
 }
 
+void hmp_loadvm(Monitor *mon, const QDict *qdict)
+{
+    int saved_vm_running  = runstate_is_running();
+    const char *name = qdict_get_str(qdict, "name");
+
+    vm_stop(RUN_STATE_RESTORE_VM);
+
+    if (load_vmstate(name) == 0 && saved_vm_running) {
+        vm_start();
+    }
+}
+
+void hmp_savevm(Monitor *mon, const QDict *qdict)
+{
+    save_vmstate(qdict_get_try_str(qdict, "name"));
+}
+
+void hmp_delvm(Monitor *mon, const QDict *qdict)
+{
+    BlockDriverState *bs;
+    Error *err;
+    const char *name = qdict_get_str(qdict, "name");
+
+    if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
+        error_reportf_err(err,
+                          "Error while deleting snapshot on device '%s': ",
+                          bdrv_get_device_name(bs));
+    }
+}
+
+void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
+{
+    BlockDriverState *bs, *bs1;
+    BdrvNextIterator it1;
+    QEMUSnapshotInfo *sn_tab, *sn;
+    bool no_snapshot = true;
+    int nb_sns, i;
+    int total;
+    int *global_snapshots;
+    AioContext *aio_context;
+
+    typedef struct SnapshotEntry {
+        QEMUSnapshotInfo sn;
+        QTAILQ_ENTRY(SnapshotEntry) next;
+    } SnapshotEntry;
+
+    typedef struct ImageEntry {
+        const char *imagename;
+        QTAILQ_ENTRY(ImageEntry) next;
+        QTAILQ_HEAD(, SnapshotEntry) snapshots;
+    } ImageEntry;
+
+    QTAILQ_HEAD(, ImageEntry) image_list =
+        QTAILQ_HEAD_INITIALIZER(image_list);
+
+    ImageEntry *image_entry, *next_ie;
+    SnapshotEntry *snapshot_entry;
+
+    bs = bdrv_all_find_vmstate_bs();
+    if (!bs) {
+        monitor_printf(mon, "No available block device supports snapshots\n");
+        return;
+    }
+    aio_context = bdrv_get_aio_context(bs);
+
+    aio_context_acquire(aio_context);
+    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+    aio_context_release(aio_context);
+
+    if (nb_sns < 0) {
+        monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
+        return;
+    }
+
+    for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
+        int bs1_nb_sns = 0;
+        ImageEntry *ie;
+        SnapshotEntry *se;
+        AioContext *ctx = bdrv_get_aio_context(bs1);
+
+        aio_context_acquire(ctx);
+        if (bdrv_can_snapshot(bs1)) {
+            sn = NULL;
+            bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
+            if (bs1_nb_sns > 0) {
+                no_snapshot = false;
+                ie = g_new0(ImageEntry, 1);
+                ie->imagename = bdrv_get_device_name(bs1);
+                QTAILQ_INIT(&ie->snapshots);
+                QTAILQ_INSERT_TAIL(&image_list, ie, next);
+                for (i = 0; i < bs1_nb_sns; i++) {
+                    se = g_new0(SnapshotEntry, 1);
+                    se->sn = sn[i];
+                    QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
+                }
+            }
+            g_free(sn);
+        }
+        aio_context_release(ctx);
+    }
+
+    if (no_snapshot) {
+        monitor_printf(mon, "There is no snapshot available.\n");
+        return;
+    }
+
+    global_snapshots = g_new0(int, nb_sns);
+    total = 0;
+    for (i = 0; i < nb_sns; i++) {
+        SnapshotEntry *next_sn;
+        if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) {
+            global_snapshots[total] = i;
+            total++;
+            QTAILQ_FOREACH(image_entry, &image_list, next) {
+                QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
+                                    next, next_sn) {
+                    if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
+                        QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
+                                      next);
+                        g_free(snapshot_entry);
+                    }
+                }
+            }
+        }
+    }
+
+    monitor_printf(mon, "List of snapshots present on all disks:\n");
+
+    if (total > 0) {
+        bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
+        monitor_printf(mon, "\n");
+        for (i = 0; i < total; i++) {
+            sn = &sn_tab[global_snapshots[i]];
+            /* The ID is not guaranteed to be the same on all images, so
+             * overwrite it.
+             */
+            pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
+            bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, sn);
+            monitor_printf(mon, "\n");
+        }
+    } else {
+        monitor_printf(mon, "None\n");
+    }
+
+    QTAILQ_FOREACH(image_entry, &image_list, next) {
+        if (QTAILQ_EMPTY(&image_entry->snapshots)) {
+            continue;
+        }
+        monitor_printf(mon,
+                       "\nList of partial (non-loadable) snapshots on '%s':\n",
+                       image_entry->imagename);
+        bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
+        monitor_printf(mon, "\n");
+        QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
+            bdrv_snapshot_dump((fprintf_function)monitor_printf, mon,
+                               &snapshot_entry->sn);
+            monitor_printf(mon, "\n");
+        }
+    }
+
+    QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
+        SnapshotEntry *next_sn;
+        QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
+                            next_sn) {
+            g_free(snapshot_entry);
+        }
+        g_free(image_entry);
+    }
+    g_free(sn_tab);
+    g_free(global_snapshots);
+
+}
+
 void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
 {
     qmp_migrate_cancel(NULL);
@@ -1947,7 +2122,7 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict)
         goto exit;
     }
 
-    qmp_nbd_server_start(addr, false, NULL, &local_err);
+    nbd_server_start(addr, NULL, &local_err);
     qapi_free_SocketAddress(addr);
     if (local_err != NULL) {
         goto exit;
diff --git a/hmp.h b/hmp.h
index 799fd371fa..37bb65a850 100644
--- a/hmp.h
+++ b/hmp.h
@@ -63,6 +63,10 @@ void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict);
 void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict);
 void hmp_drive_mirror(Monitor *mon, const QDict *qdict);
 void hmp_drive_backup(Monitor *mon, const QDict *qdict);
+void hmp_loadvm(Monitor *mon, const QDict *qdict);
+void hmp_savevm(Monitor *mon, const QDict *qdict);
+void hmp_delvm(Monitor *mon, const QDict *qdict);
+void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
 void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
 void hmp_migrate_incoming(Monitor *mon, const QDict *qdict);
 void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
diff --git a/hw/audio/Makefile.objs b/hw/audio/Makefile.objs
index 7ce85a2e88..bb6f07a91e 100644
--- a/hw/audio/Makefile.objs
+++ b/hw/audio/Makefile.objs
@@ -14,5 +14,3 @@ common-obj-$(CONFIG_PL041) += pl041.o lm4549.o
 common-obj-$(CONFIG_CS4231) += cs4231.o
 common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o
 common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o
-
-$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index 7836446fc8..09b8248cda 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -33,11 +33,7 @@
 
 #define ADLIB_KILL_TIMERS 1
 
-#ifdef HAS_YMF262
-#define ADLIB_DESC "Yamaha YMF262 (OPL3)"
-#else
 #define ADLIB_DESC "Yamaha YM3812 (OPL2)"
-#endif
 
 #ifdef DEBUG
 #include "qemu/timer.h"
@@ -50,14 +46,8 @@
 #define ldebug(...)
 #endif
 
-#ifdef HAS_YMF262
-#include "ymf262.h"
-void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
-#define SHIFT 2
-#else
 #include "fmopl.h"
 #define SHIFT 1
-#endif
 
 #define TYPE_ADLIB "adlib"
 #define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB)
@@ -80,9 +70,7 @@ typedef struct {
     SWVoiceOut *voice;
     int left, pos, samples;
     QEMUAudioTimeStamp ats;
-#ifndef HAS_YMF262
     FM_OPL *opl;
-#endif
     PortioList port_list;
 } AdlibState;
 
@@ -90,11 +78,7 @@ static AdlibState *glob_adlib;
 
 static void adlib_stop_opl_timer (AdlibState *s, size_t n)
 {
-#ifdef HAS_YMF262
-    YMF262TimerOver (0, n);
-#else
     OPLTimerOver (s->opl, n);
-#endif
     s->ticking[n] = 0;
 }
 
@@ -131,11 +115,7 @@ static void adlib_write(void *opaque, uint32_t nport, uint32_t val)
 
     adlib_kill_timers (s);
 
-#ifdef HAS_YMF262
-    YMF262Write (0, a, val);
-#else
     OPLWrite (s->opl, a, val);
-#endif
 }
 
 static uint32_t adlib_read(void *opaque, uint32_t nport)
@@ -145,12 +125,8 @@ static uint32_t adlib_read(void *opaque, uint32_t nport)
     int a = nport & 3;
 
     adlib_kill_timers (s);
-
-#ifdef HAS_YMF262
-    data = YMF262Read (0, a);
-#else
     data = OPLRead (s->opl, a);
-#endif
+
     return data;
 }
 
@@ -240,11 +216,7 @@ static void adlib_callback (void *opaque, int free)
         return;
     }
 
-#ifdef HAS_YMF262
-    YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
-#else
     YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
-#endif
 
     while (samples) {
         written = write_audio (s, samples);
@@ -263,14 +235,10 @@ static void adlib_callback (void *opaque, int free)
 
 static void Adlib_fini (AdlibState *s)
 {
-#ifdef HAS_YMF262
-    YMF262Shutdown ();
-#else
     if (s->opl) {
         OPLDestroy (s->opl);
         s->opl = NULL;
     }
-#endif
 
     g_free(s->mixbuf);
 
@@ -297,17 +265,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
     }
     glob_adlib = s;
 
-#ifdef HAS_YMF262
-    if (YMF262Init (1, 14318180, s->freq)) {
-        error_setg (errp, "YMF262Init %d failed", s->freq);
-        return;
-    }
-    else {
-        YMF262SetTimerHandler (0, timer_handler, 0);
-        s->enabled = 1;
-    }
-#else
-    s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, s->freq);
+    s->opl = OPLCreate (3579545, s->freq);
     if (!s->opl) {
         error_setg (errp, "OPLCreate %d failed", s->freq);
         return;
@@ -316,7 +274,6 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
         OPLSetTimerHandler (s->opl, timer_handler, 0);
         s->enabled = 1;
     }
-#endif
 
     as.freq = s->freq;
     as.nchannels = SHIFT;
diff --git a/hw/audio/fmopl.c b/hw/audio/fmopl.c
index 731110fe86..202f752c5d 100644
--- a/hw/audio/fmopl.c
+++ b/hw/audio/fmopl.c
@@ -30,21 +30,15 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#define HAS_YM3812	1
-
 #include "qemu/osdep.h"
 #include <math.h>
 //#include "driver.h"		/* use M.A.M.E. */
 #include "fmopl.h"
-
+#include "qemu/osdep.h"
 #ifndef PI
 #define PI 3.14159265358979323846
 #endif
 
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#endif
-
 /* -------------------- for debug --------------------- */
 /* #define OPL_OUTPUT_LOG */
 #ifdef OPL_OUTPUT_LOG
@@ -124,7 +118,7 @@ static const int slot_array[32]=
 /* key scale level */
 /* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
 #define DV (EG_STEP/2)
-static const UINT32 KSL_TABLE[8*16]=
+static const uint32_t KSL_TABLE[8*16]=
 {
 	/* OCT 0 */
 	 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
@@ -172,7 +166,7 @@ static const UINT32 KSL_TABLE[8*16]=
 /* sustain lebel table (3db per step) */
 /* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
 #define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
-static const INT32 SL_TABLE[16]={
+static const int32_t SL_TABLE[16]={
  SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
  SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
 };
@@ -182,22 +176,22 @@ static const INT32 SL_TABLE[16]={
 /* TotalLevel : 48 24 12  6  3 1.5 0.75 (dB) */
 /* TL_TABLE[ 0      to TL_MAX          ] : plus  section */
 /* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
-static INT32 *TL_TABLE;
+static int32_t *TL_TABLE;
 
 /* pointers to TL_TABLE with sinwave output offset */
-static INT32 **SIN_TABLE;
+static int32_t **SIN_TABLE;
 
 /* LFO table */
-static INT32 *AMS_TABLE;
-static INT32 *VIB_TABLE;
+static int32_t *AMS_TABLE;
+static int32_t *VIB_TABLE;
 
 /* envelope output curve table */
 /* attack + decay + OFF */
-static INT32 ENV_CURVE[2*EG_ENT+1];
+static int32_t ENV_CURVE[2*EG_ENT+1];
 
 /* multiple table */
 #define ML 2
-static const UINT32 MUL_TABLE[16]= {
+static const uint32_t MUL_TABLE[16]= {
 /* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
    0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
    8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
@@ -205,7 +199,7 @@ static const UINT32 MUL_TABLE[16]= {
 #undef ML
 
 /* dummy attack / decay rate ( when rate == 0 ) */
-static INT32 RATE_0[16]=
+static int32_t RATE_0[16]=
 {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
 
 /* -------------------- static state --------------------- */
@@ -221,14 +215,14 @@ static OPL_CH *S_CH;
 static OPL_CH *E_CH;
 static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2;
 
-static INT32 outd[1];
-static INT32 ams;
-static INT32 vib;
-static INT32 *ams_table;
-static INT32 *vib_table;
-static INT32 amsIncr;
-static INT32 vibIncr;
-static INT32 feedback2;		/* connect for SLOT 2 */
+static int32_t outd[1];
+static int32_t ams;
+static int32_t vib;
+static int32_t *ams_table;
+static int32_t *vib_table;
+static int32_t amsIncr;
+static int32_t vibIncr;
+static int32_t feedback2;		/* connect for SLOT 2 */
 
 /* log output level */
 #define LOG_ERR  3      /* ERROR       */
@@ -262,8 +256,6 @@ static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag)
 		if(OPL->status & OPL->statusmask)
 		{	/* IRQ on */
 			OPL->status |= 0x80;
-			/* callback user interrupt handler (IRQ is OFF to ON) */
-			if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
 		}
 	}
 }
@@ -278,8 +270,6 @@ static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
 		if (!(OPL->status & OPL->statusmask) )
 		{
 			OPL->status &= 0x7f;
-			/* callback user interrupt handler (IRQ is ON to OFF) */
-			if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
 		}
 	}
 }
@@ -321,7 +311,7 @@ static inline void OPL_KEYOFF(OPL_SLOT *SLOT)
 
 /* ---------- calcrate Envelope Generator & Phase Generator ---------- */
 /* return : envelope output */
-static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
+static inline uint32_t OPL_CALC_SLOT( OPL_SLOT *SLOT )
 {
 	/* calcrate envelope generator */
 	if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
@@ -361,7 +351,7 @@ static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
 /* set algorithm connection */
 static void set_algorithm( OPL_CH *CH)
 {
-	INT32 *carrier = &outd[0];
+	int32_t *carrier = &outd[0];
 	CH->connect1 = CH->CON ? carrier : &feedback2;
 	CH->connect2 = carrier;
 }
@@ -453,7 +443,7 @@ static inline void set_sl_rr(FM_OPL *OPL,int slot,int v)
 /* ---------- calcrate one of channel ---------- */
 static inline void OPL_CALC_CH( OPL_CH *CH )
 {
-	UINT32 env_out;
+	uint32_t env_out;
 	OPL_SLOT *SLOT;
 
 	feedback2 = 0;
@@ -498,9 +488,9 @@ static inline void OPL_CALC_CH( OPL_CH *CH )
 #define WHITE_NOISE_db 6.0
 static inline void OPL_CALC_RH( OPL_CH *CH )
 {
-	UINT32 env_tam,env_sd,env_top,env_hh;
+	uint32_t env_tam,env_sd,env_top,env_hh;
 	int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
-	INT32 tone8;
+	int32_t tone8;
 
 	OPL_SLOT *SLOT;
 	int env_out;
@@ -618,20 +608,20 @@ static int OPLOpenTable( void )
 	double pom;
 
 	/* allocate dynamic tables */
-	if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
+	if( (TL_TABLE = malloc(TL_MAX*2*sizeof(int32_t))) == NULL)
 		return 0;
-	if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
+	if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(int32_t *))) == NULL)
 	{
 		free(TL_TABLE);
 		return 0;
 	}
-	if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
+	if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(int32_t))) == NULL)
 	{
 		free(TL_TABLE);
 		free(SIN_TABLE);
 		return 0;
 	}
-	if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
+	if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(int32_t))) == NULL)
 	{
 		free(TL_TABLE);
 		free(SIN_TABLE);
@@ -763,18 +753,15 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
 		{
 		case 0x01:
 			/* wave selector enable */
-			if(OPL->type&OPL_TYPE_WAVESEL)
+			OPL->wavesel = v&0x20;
+                        if(!OPL->wavesel)
 			{
-				OPL->wavesel = v&0x20;
-				if(!OPL->wavesel)
+				/* preset compatible mode */
+				int c;
+				for(c=0;c<OPL->max_ch;c++)
 				{
-					/* preset compatible mode */
-					int c;
-					for(c=0;c<OPL->max_ch;c++)
-					{
-						OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
-						OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
-					}
+					OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
+					OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
 				}
 			}
 			return;
@@ -791,8 +778,8 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
 			}
 			else
 			{	/* set IRQ mask ,timer enable*/
-				UINT8 st1 = v&1;
-				UINT8 st2 = (v>>1)&1;
+				uint8_t st1 = v&1;
+				uint8_t st2 = (v>>1)&1;
 				/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
 				OPL_STATUS_RESET(OPL,v&0x78);
 				OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
@@ -812,57 +799,6 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
 				}
 			}
 			return;
-#if BUILD_Y8950
-		case 0x06:		/* Key Board OUT */
-			if(OPL->type&OPL_TYPE_KEYBOARD)
-			{
-				if(OPL->keyboardhandler_w)
-					OPL->keyboardhandler_w(OPL->keyboard_param,v);
-				else
-					LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
-			}
-			return;
-		case 0x07:	/* DELTA-T control : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
-			if(OPL->type&OPL_TYPE_ADPCM)
-				YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
-			return;
-		case 0x08:	/* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
-			OPL->mode = v;
-			v&=0x1f;	/* for DELTA-T unit */
-		case 0x09:		/* START ADD */
-		case 0x0a:
-		case 0x0b:		/* STOP ADD  */
-		case 0x0c:
-		case 0x0d:		/* PRESCALE   */
-		case 0x0e:
-		case 0x0f:		/* ADPCM data */
-		case 0x10: 		/* DELTA-N    */
-		case 0x11: 		/* DELTA-N    */
-		case 0x12: 		/* EG-CTRL    */
-			if(OPL->type&OPL_TYPE_ADPCM)
-				YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
-			return;
-#if 0
-		case 0x15:		/* DAC data    */
-		case 0x16:
-		case 0x17:		/* SHIFT    */
-			return;
-		case 0x18:		/* I/O CTRL (Direction) */
-			if(OPL->type&OPL_TYPE_IO)
-				OPL->portDirection = v&0x0f;
-			return;
-		case 0x19:		/* I/O DATA */
-			if(OPL->type&OPL_TYPE_IO)
-			{
-				OPL->portLatch = v;
-				if(OPL->porthandler_w)
-					OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
-			}
-			return;
-		case 0x1a:		/* PCM data */
-			return;
-#endif
-#endif
 		}
 		break;
 	case 0x20:	/* am,vib,ksr,eg type,mul */
@@ -891,7 +827,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
 		case 0xbd:
 			/* amsep,vibdep,r,bd,sd,tom,tc,hh */
 			{
-			UINT8 rkey = OPL->rhythm^v;
+			uint8_t rkey = OPL->rhythm^v;
 			OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
 			OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
 			OPL->rhythm  = v&0x3f;
@@ -1032,20 +968,19 @@ static void OPL_UnLockTable(void)
 	OPLCloseTable();
 }
 
-#if (BUILD_YM3812 || BUILD_YM3526)
 /*******************************************************************************/
 /*		YM3812 local section                                                   */
 /*******************************************************************************/
 
 /* ---------- update one of chip ----------- */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
+void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length)
 {
     int i;
 	int data;
-	OPLSAMPLE *buf = buffer;
-	UINT32 amsCnt  = OPL->amsCnt;
-	UINT32 vibCnt  = OPL->vibCnt;
-	UINT8 rhythm = OPL->rhythm&0x20;
+	int16_t *buf = buffer;
+	uint32_t amsCnt  = OPL->amsCnt;
+	uint32_t  vibCnt  = OPL->vibCnt;
+	uint8_t rhythm = OPL->rhythm&0x20;
 	OPL_CH *CH,*R_CH;
 
 	if( (void *)OPL != cur_chip ){
@@ -1095,72 +1030,9 @@ void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
 	}
 #endif
 }
-#endif /* (BUILD_YM3812 || BUILD_YM3526) */
-
-#if BUILD_Y8950
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
-{
-    int i;
-	int data;
-	OPLSAMPLE *buf = buffer;
-	UINT32 amsCnt  = OPL->amsCnt;
-	UINT32 vibCnt  = OPL->vibCnt;
-	UINT8 rhythm = OPL->rhythm&0x20;
-	OPL_CH *CH,*R_CH;
-	YM_DELTAT *DELTAT = OPL->deltat;
-
-	/* setup DELTA-T unit */
-	YM_DELTAT_DECODE_PRESET(DELTAT);
-
-	if( (void *)OPL != cur_chip ){
-		cur_chip = (void *)OPL;
-		/* channel pointers */
-		S_CH = OPL->P_CH;
-		E_CH = &S_CH[9];
-		/* rhythm slot */
-		SLOT7_1 = &S_CH[7].SLOT[SLOT1];
-		SLOT7_2 = &S_CH[7].SLOT[SLOT2];
-		SLOT8_1 = &S_CH[8].SLOT[SLOT1];
-		SLOT8_2 = &S_CH[8].SLOT[SLOT2];
-		/* LFO state */
-		amsIncr = OPL->amsIncr;
-		vibIncr = OPL->vibIncr;
-		ams_table = OPL->ams_table;
-		vib_table = OPL->vib_table;
-	}
-	R_CH = rhythm ? &S_CH[6] : E_CH;
-    for( i=0; i < length ; i++ )
-	{
-		/*            channel A         channel B         channel C      */
-		/* LFO */
-		ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
-		vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
-		outd[0] = 0;
-		/* deltaT ADPCM */
-		if( DELTAT->portstate )
-			YM_DELTAT_ADPCM_CALC(DELTAT);
-		/* FM part */
-		for(CH=S_CH ; CH < R_CH ; CH++)
-			OPL_CALC_CH(CH);
-		/* Rythn part */
-		if(rhythm)
-			OPL_CALC_RH(S_CH);
-		/* limit check */
-		data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
-		/* store to sound buffer */
-		buf[i] = data >> OPL_OUTSB;
-	}
-	OPL->amsCnt = amsCnt;
-	OPL->vibCnt = vibCnt;
-	/* deltaT START flag */
-	if( !DELTAT->portstate )
-		OPL->status &= 0xfe;
-}
-#endif
 
 /* ---------- reset one of chip ---------- */
-void OPLResetChip(FM_OPL *OPL)
+static void OPLResetChip(FM_OPL *OPL)
 {
 	int c,s;
 	int i;
@@ -1189,23 +1061,11 @@ void OPLResetChip(FM_OPL *OPL)
 			CH->SLOT[s].evs = 0;
 		}
 	}
-#if BUILD_Y8950
-	if(OPL->type&OPL_TYPE_ADPCM)
-	{
-		YM_DELTAT *DELTAT = OPL->deltat;
-
-		DELTAT->freqbase = OPL->freqbase;
-		DELTAT->output_pointer = outd;
-		DELTAT->portshift = 5;
-		DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
-		YM_DELTAT_ADPCM_Reset(DELTAT,0);
-	}
-#endif
 }
 
 /* ----------  Create one of vietual YM3812 ----------       */
 /* 'rate'  is sampling rate and 'bufsiz' is the size of the  */
-FM_OPL *OPLCreate(int type, int clock, int rate)
+FM_OPL *OPLCreate(int clock, int rate)
 {
 	char *ptr;
 	FM_OPL *OPL;
@@ -1216,9 +1076,6 @@ FM_OPL *OPLCreate(int type, int clock, int rate)
 	/* allocate OPL state space */
 	state_size  = sizeof(FM_OPL);
 	state_size += sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
-	if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
-#endif
 	/* allocate memory block */
 	ptr = malloc(state_size);
 	if(ptr==NULL) return NULL;
@@ -1226,11 +1083,7 @@ FM_OPL *OPLCreate(int type, int clock, int rate)
 	memset(ptr,0,state_size);
 	OPL        = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
 	OPL->P_CH  = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
-	if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
-#endif
 	/* set channel state pointer */
-	OPL->type  = type;
 	OPL->clock = clock;
 	OPL->rate  = rate;
 	OPL->max_ch = max_ch;
@@ -1280,31 +1133,7 @@ void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOff
 	OPL->TimerHandler   = TimerHandler;
 	OPL->TimerParam = channelOffset;
 }
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
-{
-	OPL->IRQHandler     = IRQHandler;
-	OPL->IRQParam = param;
-}
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
-{
-	OPL->UpdateHandler = UpdateHandler;
-	OPL->UpdateParam = param;
-}
-#if BUILD_Y8950
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
-{
-	OPL->porthandler_w = PortHandler_w;
-	OPL->porthandler_r = PortHandler_r;
-	OPL->port_param = param;
-}
 
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
-{
-	OPL->keyboardhandler_w = KeyboardHandler_w;
-	OPL->keyboardhandler_r = KeyboardHandler_r;
-	OPL->keyboard_param = param;
-}
-#endif
 /* ---------- YM3812 I/O interface ---------- */
 int OPLWrite(FM_OPL *OPL,int a,int v)
 {
@@ -1314,7 +1143,6 @@ int OPLWrite(FM_OPL *OPL,int a,int v)
 	}
 	else
 	{	/* data port */
-		if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
 #ifdef OPL_OUTPUT_LOG
 	if(opl_dbg_fp)
 	{
@@ -1338,28 +1166,12 @@ unsigned char OPLRead(FM_OPL *OPL,int a)
 	switch(OPL->address)
 	{
 	case 0x05: /* KeyBoard IN */
-		if(OPL->type&OPL_TYPE_KEYBOARD)
-		{
-			if(OPL->keyboardhandler_r)
-				return OPL->keyboardhandler_r(OPL->keyboard_param);
-			else {
-				LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
-			}
-		}
 		return 0;
 #if 0
 	case 0x0f: /* ADPCM-DATA  */
 		return 0;
 #endif
 	case 0x19: /* I/O DATA    */
-		if(OPL->type&OPL_TYPE_IO)
-		{
-			if(OPL->porthandler_r)
-				return OPL->porthandler_r(OPL->port_param);
-			else {
-				LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
-			}
-		}
 		return 0;
 	case 0x1a: /* PCM-DATA    */
 		return 0;
@@ -1380,7 +1192,6 @@ int OPLTimerOver(FM_OPL *OPL,int c)
 		if( OPL->mode & 0x80 )
 		{	/* CSM mode total level latch and auto key on */
 			int ch;
-			if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
 			for(ch=0;ch<9;ch++)
 				CSMKeyControll( &OPL->P_CH[ch] );
 		}
diff --git a/hw/audio/fmopl.h b/hw/audio/fmopl.h
index fdda7f9f51..fc9f16b58a 100644
--- a/hw/audio/fmopl.h
+++ b/hw/audio/fmopl.h
@@ -1,174 +1,103 @@
 #ifndef FMOPL_H
 #define FMOPL_H
 
-/* --- select emulation chips --- */
-#define BUILD_YM3812 (HAS_YM3812)
-//#define BUILD_YM3526 (HAS_YM3526)
-//#define BUILD_Y8950  (HAS_Y8950)
-
-/* --- system optimize --- */
-/* select bit size of output : 8 or 16 */
-#define OPL_OUTPUT_BIT 16
-
-/* compiler dependence */
-#ifndef OSD_CPU_H
-#define OSD_CPU_H
-typedef unsigned char	UINT8;   /* unsigned  8bit */
-typedef unsigned short	UINT16;  /* unsigned 16bit */
-typedef unsigned int	UINT32;  /* unsigned 32bit */
-typedef signed char		INT8;    /* signed  8bit   */
-typedef signed short	INT16;   /* signed 16bit   */
-typedef signed int		INT32;   /* signed 32bit   */
-#endif
-
-#if (OPL_OUTPUT_BIT==16)
-typedef INT16 OPLSAMPLE;
-#endif
-#if (OPL_OUTPUT_BIT==8)
-typedef unsigned char  OPLSAMPLE;
-#endif
-
-
-#if BUILD_Y8950
-#include "ymdeltat.h"
-#endif
+#include <stdint.h>
 
 typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
-typedef void (*OPL_IRQHANDLER)(int param,int irq);
-typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
-typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
-typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
 
 /* !!!!! here is private section , do not access there member direct !!!!! */
 
-#define OPL_TYPE_WAVESEL   0x01  /* waveform select    */
-#define OPL_TYPE_ADPCM     0x02  /* DELTA-T ADPCM unit */
-#define OPL_TYPE_KEYBOARD  0x04  /* keyboard interface */
-#define OPL_TYPE_IO        0x08  /* I/O port */
-
 /* Saving is necessary for member of the 'R' mark for suspend/resume */
 /* ---------- OPL one of slot  ---------- */
 typedef struct fm_opl_slot {
-	INT32 TL;		/* total level     :TL << 8            */
-	INT32 TLL;		/* adjusted now TL                     */
-	UINT8  KSR;		/* key scale rate  :(shift down bit)   */
-	INT32 *AR;		/* attack rate     :&AR_TABLE[AR<<2]   */
-	INT32 *DR;		/* decay rate      :&DR_TALBE[DR<<2]   */
-	INT32 SL;		/* sustin level    :SL_TALBE[SL]       */
-	INT32 *RR;		/* release rate    :&DR_TABLE[RR<<2]   */
-	UINT8 ksl;		/* keyscale level  :(shift down bits)  */
-	UINT8 ksr;		/* key scale rate  :kcode>>KSR         */
-	UINT32 mul;		/* multiple        :ML_TABLE[ML]       */
-	UINT32 Cnt;		/* frequency count :                   */
-	UINT32 Incr;	/* frequency step  :                   */
+	int32_t TL;		/* total level     :TL << 8            */
+	int32_t TLL;		/* adjusted now TL                     */
+	uint8_t  KSR;		/* key scale rate  :(shift down bit)   */
+	int32_t *AR;		/* attack rate     :&AR_TABLE[AR<<2]   */
+	int32_t *DR;		/* decay rate      :&DR_TALBE[DR<<2]   */
+	int32_t SL;		/* sustin level    :SL_TALBE[SL]       */
+	int32_t *RR;		/* release rate    :&DR_TABLE[RR<<2]   */
+	uint8_t ksl;		/* keyscale level  :(shift down bits)  */
+	uint8_t ksr;		/* key scale rate  :kcode>>KSR         */
+	uint32_t mul;		/* multiple        :ML_TABLE[ML]       */
+	uint32_t Cnt;		/* frequency count :                   */
+	uint32_t Incr;	/* frequency step  :                   */
 	/* envelope generator state */
-	UINT8 eg_typ;	/* envelope type flag                  */
-	UINT8 evm;		/* envelope phase                      */
-	INT32 evc;		/* envelope counter                    */
-	INT32 eve;		/* envelope counter end point          */
-	INT32 evs;		/* envelope counter step               */
-	INT32 evsa;	/* envelope step for AR :AR[ksr]           */
-	INT32 evsd;	/* envelope step for DR :DR[ksr]           */
-	INT32 evsr;	/* envelope step for RR :RR[ksr]           */
+	uint8_t eg_typ;	/* envelope type flag                  */
+	uint8_t evm;		/* envelope phase                      */
+	int32_t evc;		/* envelope counter                    */
+	int32_t eve;		/* envelope counter end point          */
+	int32_t evs;		/* envelope counter step               */
+	int32_t evsa;	/* envelope step for AR :AR[ksr]           */
+	int32_t evsd;	/* envelope step for DR :DR[ksr]           */
+	int32_t evsr;	/* envelope step for RR :RR[ksr]           */
 	/* LFO */
-	UINT8 ams;		/* ams flag                            */
-	UINT8 vib;		/* vibrate flag                        */
+	uint8_t ams;		/* ams flag                            */
+	uint8_t vib;		/* vibrate flag                        */
 	/* wave selector */
-	INT32 **wavetable;
+	int32_t **wavetable;
 }OPL_SLOT;
 
 /* ---------- OPL one of channel  ---------- */
 typedef struct fm_opl_channel {
 	OPL_SLOT SLOT[2];
-	UINT8 CON;			/* connection type                     */
-	UINT8 FB;			/* feed back       :(shift down bit)   */
-	INT32 *connect1;	/* slot1 output pointer                */
-	INT32 *connect2;	/* slot2 output pointer                */
-	INT32 op1_out[2];	/* slot1 output for selfeedback        */
+	uint8_t CON;			/* connection type                     */
+	uint8_t FB;			/* feed back       :(shift down bit)   */
+	int32_t *connect1;	/* slot1 output pointer                */
+	int32_t *connect2;	/* slot2 output pointer                */
+	int32_t op1_out[2];	/* slot1 output for selfeedback        */
 	/* phase generator state */
-	UINT32  block_fnum;	/* block+fnum      :                   */
-	UINT8 kcode;		/* key code        : KeyScaleCode      */
-	UINT32  fc;			/* Freq. Increment base                */
-	UINT32  ksl_base;	/* KeyScaleLevel Base step             */
-	UINT8 keyon;		/* key on/off flag                     */
+	uint32_t  block_fnum;	/* block+fnum      :                   */
+	uint8_t kcode;		/* key code        : KeyScaleCode      */
+	uint32_t  fc;			/* Freq. Increment base                */
+	uint32_t  ksl_base;	/* KeyScaleLevel Base step             */
+	uint8_t keyon;		/* key on/off flag                     */
 } OPL_CH;
 
 /* OPL state */
 typedef struct fm_opl_f {
-	UINT8 type;			/* chip type                         */
 	int clock;			/* master clock  (Hz)                */
 	int rate;			/* sampling rate (Hz)                */
 	double freqbase;	/* frequency base                    */
 	double TimerBase;	/* Timer base time (==sampling time) */
-	UINT8 address;		/* address register                  */
-	UINT8 status;		/* status flag                       */
-	UINT8 statusmask;	/* status mask                       */
-	UINT32 mode;		/* Reg.08 : CSM , notesel,etc.       */
+	uint8_t address;		/* address register                  */
+	uint8_t status;		/* status flag                       */
+	uint8_t statusmask;	/* status mask                       */
+	uint32_t mode;		/* Reg.08 : CSM , notesel,etc.       */
 	/* Timer */
 	int T[2];			/* timer counter                     */
-	UINT8 st[2];		/* timer enable                      */
+	uint8_t st[2];		/* timer enable                      */
 	/* FM channel slots */
 	OPL_CH *P_CH;		/* pointer of CH                     */
 	int	max_ch;			/* maximum channel                   */
 	/* Rhythm sention */
-	UINT8 rhythm;		/* Rhythm mode , key flag */
-#if BUILD_Y8950
-	/* Delta-T ADPCM unit (Y8950) */
-	YM_DELTAT *deltat;			/* DELTA-T ADPCM       */
-#endif
-	/* Keyboard / I/O interface unit (Y8950) */
-	UINT8 portDirection;
-	UINT8 portLatch;
-	OPL_PORTHANDLER_R porthandler_r;
-	OPL_PORTHANDLER_W porthandler_w;
-	int port_param;
-	OPL_PORTHANDLER_R keyboardhandler_r;
-	OPL_PORTHANDLER_W keyboardhandler_w;
-	int keyboard_param;
+	uint8_t rhythm;		/* Rhythm mode , key flag */
 	/* time tables */
-	INT32 AR_TABLE[75];	/* atttack rate tables */
-	INT32 DR_TABLE[75];	/* decay rate tables   */
-	UINT32 FN_TABLE[1024];  /* fnumber -> increment counter */
+	int32_t AR_TABLE[75];	/* atttack rate tables */
+	int32_t DR_TABLE[75];	/* decay rate tables   */
+	uint32_t FN_TABLE[1024];  /* fnumber -> increment counter */
 	/* LFO */
-	INT32 *ams_table;
-	INT32 *vib_table;
-	INT32 amsCnt;
-	INT32 amsIncr;
-	INT32 vibCnt;
-	INT32 vibIncr;
+	int32_t *ams_table;
+	int32_t *vib_table;
+	int32_t amsCnt;
+	int32_t amsIncr;
+	int32_t vibCnt;
+	int32_t vibIncr;
 	/* wave selector enable flag */
-	UINT8 wavesel;
+	uint8_t wavesel;
 	/* external event callback handler */
 	OPL_TIMERHANDLER  TimerHandler;		/* TIMER handler   */
 	int TimerParam;						/* TIMER parameter */
-	OPL_IRQHANDLER    IRQHandler;		/* IRQ handler    */
-	int IRQParam;						/* IRQ parameter  */
-	OPL_UPDATEHANDLER UpdateHandler;	/* stream update handler   */
-	int UpdateParam;					/* stream update parameter */
 } FM_OPL;
 
 /* ---------- Generic interface section ---------- */
-#define OPL_TYPE_YM3526 (0)
-#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
-#define OPL_TYPE_Y8950  (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
-
-FM_OPL *OPLCreate(int type, int clock, int rate);
+FM_OPL *OPLCreate(int clock, int rate);
 void OPLDestroy(FM_OPL *OPL);
 void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
-/* Y8950 port handlers */
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
 
-void OPLResetChip(FM_OPL *OPL);
 int OPLWrite(FM_OPL *OPL,int a,int v);
 unsigned char OPLRead(FM_OPL *OPL,int a);
 int OPLTimerOver(FM_OPL *OPL,int c);
 
-/* YM3626/YM3812 local section */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
+void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length);
 #endif
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index 3d08a6576a..ec103a4db9 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -53,7 +53,7 @@ typedef struct GUSState {
     uint32_t freq;
     uint32_t port;
     int pos, left, shift, irqs;
-    GUSsample *mixbuf;
+    int16_t *mixbuf;
     uint8_t himem[1024 * 1024 + 32 + 4096];
     int samples;
     SWVoiceOut *voice;
diff --git a/hw/audio/gusemu.h b/hw/audio/gusemu.h
index 9aec7bf8e7..ab591eefb7 100644
--- a/hw/audio/gusemu.h
+++ b/hw/audio/gusemu.h
@@ -25,26 +25,10 @@
 #ifndef GUSEMU_H
 #define GUSEMU_H
 
-/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
-
-#if defined _WIN32 && defined _MSC_VER /* doesn't support other win32 compilers yet, do it yourself... */
- typedef unsigned char GUSbyte;
- typedef unsigned short GUSword;
- typedef unsigned int GUSdword;
- typedef signed char GUSchar;
- typedef signed short GUSsample;
-#else
- typedef int8_t GUSchar;
- typedef uint8_t GUSbyte;
- typedef uint16_t GUSword;
- typedef uint32_t GUSdword;
- typedef int16_t GUSsample;
-#endif
-
 typedef struct _GUSEmuState
 {
- GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
- GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
+ uint8_t *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
+ uint8_t *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
  uint32_t gusirq;
  uint32_t gusdma;
  unsigned int timer1fraction;
@@ -92,7 +76,7 @@ void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count
 /* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
 /* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
 
-void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos);
+void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, int16_t *bufferpos);
 /* recommended range: 10 < numsamples < 100 */
 /* lower values may result in increased rounding error, higher values often cause audible timing delays */
 
diff --git a/hw/audio/gusemu_hal.c b/hw/audio/gusemu_hal.c
index 973d6b9f4f..1150fc4426 100644
--- a/hw/audio/gusemu_hal.c
+++ b/hw/audio/gusemu_hal.c
@@ -31,15 +31,15 @@
 #include "gusemu.h"
 
 #define GUSregb(position) (*            (gusptr+(position)))
-#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
+#define GUSregw(position) (*(uint16_t *) (gusptr+(position)))
+#define GUSregd(position) (*(uint16_t *)(gusptr+(position)))
 
 /* size given in bytes */
 unsigned int gus_read(GUSEmuState * state, int port, int size)
 {
     int             value_read = 0;
 
-    GUSbyte        *gusptr;
+    uint8_t        *gusptr;
     gusptr = state->gusdatapos;
     GUSregd(portaccesses)++;
 
@@ -125,7 +125,7 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
                 if (!GUSregb(IRQStatReg2x6))
                     GUS_irqclear(state, state->gusirq);
             }
-            return (GUSbyte) value_read;
+            return (uint8_t) value_read;
             /* DramDMAmemPosReg */
             /* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
             /* 43h+44h write only */
@@ -173,12 +173,12 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
                 value_read = value_read >> 8;
             value_read &= 0xff;
         }
-        return (GUSword) value_read;
+        return (uint16_t) value_read;
     /* case 0x306:                                  */ /* Mixer/Version info */
         /*  return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
     case 0x307:                                     /* DRAMaccess */
         {
-            GUSbyte        *adr;
+            uint8_t        *adr;
             adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
             return *adr;
         }
@@ -189,14 +189,14 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
 
 void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
 {
-    GUSbyte        *gusptr;
+    uint8_t        *gusptr;
     gusptr = state->gusdatapos;
     GUSregd(portaccesses)++;
 
     switch (port & 0xff0f)
     {
     case 0x200:                 /* MixerCtrlReg */
-        GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
+        GUSregb(MixerCtrlReg2x0) = (uint8_t) data;
         break;
     case 0x206:                 /* IRQstatReg / SB2x6IRQ */
         if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
@@ -208,7 +208,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
         break;
     case 0x308:                /* AdLib 388h */
     case 0x208:                /* AdLibCommandReg */
-        GUSregb(AdLibCommand2xA) = (GUSbyte) data;
+        GUSregb(AdLibCommand2xA) = (uint8_t) data;
         break;
     case 0x309:                /* AdLib 389h */
     case 0x209:                /* AdLibDataReg */
@@ -217,11 +217,11 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
             if (data & 0x80)
                 GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
             else
-                GUSregb(TimerDataReg2x9) = (GUSbyte) data;
+                GUSregb(TimerDataReg2x9) = (uint8_t) data;
         }
         else
         {
-            GUSregb(AdLibData2x9) = (GUSbyte) data;
+            GUSregb(AdLibData2x9) = (uint8_t) data;
             if (GUSregb(GUS45TimerCtrl) & 0x02)
             {
                 GUSregb(TimerStatus2x8) |= 0x01;
@@ -231,16 +231,16 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
         }
         break;
     case 0x20A:
-        GUSregb(AdLibStatus2x8) = (GUSbyte) data;
+        GUSregb(AdLibStatus2x8) = (uint8_t) data;
         break;                 /* AdLibStatus2x8 */
     case 0x20B:                /* GUS hidden registers */
         switch (GUSregb(RegCtrl_2xF) & 0x7)
         {
         case 0:
             if (GUSregb(MixerCtrlReg2x0) & 0x40)
-                GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
+                GUSregb(IRQ_2xB) = (uint8_t) data; /* control register select bit */
             else
-                GUSregb(DMA_2xB) = (GUSbyte) data;
+                GUSregb(DMA_2xB) = (uint8_t) data;
             break;
             /* case 1-4: general purpose emulation regs */
         case 5:                                    /* clear stat reg 2xF */
@@ -249,7 +249,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
                 GUS_irqclear(state, state->gusirq);
             break;
         case 6:                                    /* Jumper reg (Joystick/MIDI enable) */
-            GUSregb(Jumper_2xB) = (GUSbyte) data;
+            GUSregb(Jumper_2xB) = (uint8_t) data;
             break;
         default:;
         }
@@ -262,20 +262,20 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
             GUS_irqrequest(state, state->gusirq, 1);
         }
     case 0x20D:                /* SB2xCd no IRQ */
-        GUSregb(SB2xCd) = (GUSbyte) data;
+        GUSregb(SB2xCd) = (uint8_t) data;
         break;
     case 0x20E:                /* SB2xE */
-        GUSregb(SB2xE) = (GUSbyte) data;
+        GUSregb(SB2xE) = (uint8_t) data;
         break;
     case 0x20F:
-        GUSregb(RegCtrl_2xF) = (GUSbyte) data;
+        GUSregb(RegCtrl_2xF) = (uint8_t) data;
         break;                 /* CtrlReg2xF */
     case 0x302:                /* VoiceSelReg */
-        GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
+        GUSregb(VoiceSelReg3x2) = (uint8_t) data;
         break;
     case 0x303:                /* FunkSelReg */
-        GUSregb(FunkSelReg3x3) = (GUSbyte) data;
-        if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
+        GUSregb(FunkSelReg3x3) = (uint8_t) data;
+        if ((uint8_t) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
         {
             int             voice;
             if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
@@ -318,15 +318,15 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
     case 0x304:
     case 0x305:
         {
-            GUSword         writedata = (GUSword) data;
-            GUSword         readmask = 0x0000;
+            uint16_t         writedata = (uint16_t) data;
+            uint16_t         readmask = 0x0000;
             if (size == 1)
             {
                 readmask = 0xff00;
                 writedata &= 0xff;
                 if ((port & 0xff0f) == 0x305)
                 {
-                    writedata = (GUSword) (writedata << 8);
+                    writedata = (uint16_t) (writedata << 8);
                     readmask = 0x00ff;
                 }
             }
@@ -353,17 +353,17 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
                         break;  /* reset flag active? */
                     offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
                     offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /*  = Voice*32 + Funktion*2 */
-                    GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
+                    GUSregw(offset) = (uint16_t) ((GUSregw(offset) & readmask) | writedata);
                 }
                 break;
                 /* voice unspecific functions */
             case 0x0e:         /* NumVoices */
-                GUSregb(NumVoices) = (GUSbyte) data;
+                GUSregb(NumVoices) = (uint8_t) data;
                 break;
             /* case 0x0f:      */ /* read only */
                 /* common functions */
             case 0x41:         /* DramDMAContrReg */
-                GUSregb(GUS41DMACtrl) = (GUSbyte) data;
+                GUSregb(GUS41DMACtrl) = (uint8_t) data;
                 if (data & 0x01)
                     GUS_dmarequest(state);
                 break;
@@ -380,7 +380,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
                     (GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
                 break;
             case 0x45:         /* TCtrlReg */
-                GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
+                GUSregb(GUS45TimerCtrl) = (uint8_t) data;
                 if (!(data & 0x20))
                     GUSregb(TimerStatus2x8) &= 0xe7;    /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
                 if (!(data & 0x02))
@@ -434,18 +434,18 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
                     GUS_irqclear(state, state->gusirq);
                 break;
             case 0x46:          /* Counter1 */
-                GUSregb(GUS46Counter1) = (GUSbyte) data;
+                GUSregb(GUS46Counter1) = (uint8_t) data;
                 break;
             case 0x47:          /* Counter2 */
-                GUSregb(GUS47Counter2) = (GUSbyte) data;
+                GUSregb(GUS47Counter2) = (uint8_t) data;
                 break;
             /* case 0x48:       */ /* sampling freq reg not emulated (same as interwave) */
             case 0x49:          /* SampCtrlReg */
-                GUSregb(GUS49SampCtrl) = (GUSbyte) data;
+                GUSregb(GUS49SampCtrl) = (uint8_t) data;
                 break;
             /* case 0x4b:       */ /* joystick trim not emulated */
             case 0x4c:          /* GUSreset */
-                GUSregb(GUS4cReset) = (GUSbyte) data;
+                GUSregb(GUS4cReset) = (uint8_t) data;
                 if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
                 {
                     GUSregd(voicewavetableirq) = 0;
@@ -471,9 +471,9 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
         break;
     case 0x307:                /* DRAMaccess */
         {
-            GUSbyte        *adr;
+            uint8_t        *adr;
             adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
-            *adr = (GUSbyte) data;
+            *adr = (uint8_t) data;
         }
         break;
     }
@@ -510,7 +510,7 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun
     char           *srcaddr;
     char           *destaddr;
     char            msbmask = 0;
-    GUSbyte        *gusptr;
+    uint8_t        *gusptr;
     gusptr = state->gusdatapos;
 
     srcaddr = dma_addr; /* system memory address */
@@ -521,8 +521,8 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun
         destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */
     }
 
-    GUSregw(GUS42DMAStart) += (GUSword)  (count >> 4);                           /* ToDo: add 16bit GUS page limit? */
-    GUSregb(GUS50DMAHigh)   = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
+    GUSregw(GUS42DMAStart) += (uint16_t)  (count >> 4);                           /* ToDo: add 16bit GUS page limit? */
+    GUSregb(GUS50DMAHigh)   = (uint8_t) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
 
     if (GUSregb(GUS41DMACtrl) & 0x02)   /* direction, 0 := sysram->gusram */
     {
diff --git a/hw/audio/gusemu_mixer.c b/hw/audio/gusemu_mixer.c
index 701e8fb0ed..00b9861b92 100644
--- a/hw/audio/gusemu_mixer.c
+++ b/hw/audio/gusemu_mixer.c
@@ -27,26 +27,26 @@
 #include "gustate.h"
 
 #define GUSregb(position)  (*            (gusptr+(position)))
-#define GUSregw(position)  (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position)  (*(GUSdword *)(gusptr+(position)))
+#define GUSregw(position)  (*(uint16_t *) (gusptr+(position)))
+#define GUSregd(position)  (*(uint16_t *)(gusptr+(position)))
 
-#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
+#define GUSvoice(position) (*(uint16_t *)(voiceptr+(position)))
 
 /* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
 void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
-                   GUSsample *bufferpos)
+                   int16_t *bufferpos)
 {
     /* note that byte registers are stored in the upper half of each voice register! */
-    GUSbyte        *gusptr;
+    uint8_t        *gusptr;
     int             Voice;
-    GUSword        *voiceptr;
+    uint16_t       *voiceptr;
 
     unsigned int    count;
     for (count = 0; count < numsamples * 2; count++)
         *(bufferpos + count) = 0;       /* clear */
 
     gusptr = state->gusdatapos;
-    voiceptr = (GUSword *) gusptr;
+    voiceptr = (uint16_t *) gusptr;
     if (!(GUSregb(GUS4cReset) & 0x01))  /* reset flag active? */
         return;
 
@@ -85,16 +85,16 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int
                 if (GUSvoice(wVSRControl) & 0x400)      /* 16bit */
                 {
                     int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
-                    GUSchar *adr;
-                    adr = (GUSchar *) state->himemaddr + offset;
+                    int8_t *adr;
+                    adr = (int8_t *) state->himemaddr + offset;
                     sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
                     sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
                 }
                 else            /* 8bit */
                 {
                     int offset = (CurrPos >> 9) & 0xfffff;
-                    GUSchar *adr;
-                    adr = (GUSchar *) state->himemaddr + offset;
+                    int8_t *adr;
+                    adr = (int8_t *) state->himemaddr + offset;
                     sample1 = (*adr) * 256;
                     sample2 = (*(adr + 1)) * 256;
                 }
@@ -171,8 +171,8 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int
                 }
 
                 /* mix samples into buffer */
-                *(bufferpos + 2 * sample)     += (GUSsample) ((sample1 * PanningPos) >> 4);        /* right */
-                *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */
+                *(bufferpos + 2 * sample)     += (int16_t) ((sample1 * PanningPos) >> 4);        /* right */
+                *(bufferpos + 2 * sample + 1) += (int16_t) ((sample1 * (15 - PanningPos)) >> 4); /* left */
             }
             /* write back voice and volume */
             GUSvoice(wVSRCurrVol)   = Volume32 / 32;
@@ -187,7 +187,7 @@ void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
 /* time given in microseconds */
 {
     int             requestedIRQs = 0;
-    GUSbyte        *gusptr;
+    uint8_t        *gusptr;
     gusptr = state->gusdatapos;
     if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
     {
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 52d4640e60..5402cd196c 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -520,7 +520,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
     return 0;
 }
 
-static int hda_audio_exit(HDACodecDevice *hda)
+static void hda_audio_exit(HDACodecDevice *hda)
 {
     HDAAudioState *a = HDA_AUDIO(hda);
     HDAAudioStream *st;
@@ -539,7 +539,6 @@ static int hda_audio_exit(HDACodecDevice *hda)
         }
     }
     AUD_remove_card(&a->card);
-    return 0;
 }
 
 static int hda_audio_post_load(void *opaque, int version)
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index 537face94d..2c497eb174 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -70,7 +70,7 @@ static void hda_codec_dev_realize(DeviceState *qdev, Error **errp)
     }
 }
 
-static int hda_codec_dev_exit(DeviceState *qdev)
+static void hda_codec_dev_unrealize(DeviceState *qdev, Error **errp)
 {
     HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
     HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
@@ -78,7 +78,6 @@ static int hda_codec_dev_exit(DeviceState *qdev)
     if (cdc->exit) {
         cdc->exit(dev);
     }
-    return 0;
 }
 
 HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
@@ -1318,7 +1317,7 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *k = DEVICE_CLASS(klass);
     k->realize = hda_codec_dev_realize;
-    k->exit = hda_codec_dev_exit;
+    k->unrealize = hda_codec_dev_unrealize;
     set_bit(DEVICE_CATEGORY_SOUND, k->categories);
     k->bus_type = TYPE_HDA_BUS;
     k->props = hda_props;
diff --git a/hw/audio/intel-hda.h b/hw/audio/intel-hda.h
index d784bcf5fc..53b78da4df 100644
--- a/hw/audio/intel-hda.h
+++ b/hw/audio/intel-hda.h
@@ -38,7 +38,7 @@ typedef struct HDACodecDeviceClass
     DeviceClass parent_class;
 
     int (*init)(HDACodecDevice *dev);
-    int (*exit)(HDACodecDevice *dev);
+    void (*exit)(HDACodecDevice *dev);
     void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
     void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
 } HDACodecDeviceClass;
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 27df0486d9..3a22805fbc 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -1082,7 +1082,7 @@ static int blk_connect(struct XenDevice *xendev)
 
         if (strcmp(blkdev->fileproto, "<unset>")) {
             options = qdict_new();
-            qdict_put(options, "driver", qstring_from_str(blkdev->fileproto));
+            qdict_put_str(options, "driver", blkdev->fileproto);
         }
 
         /* setup via xenbus -> create new block driver instance */
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 725fdc46f4..55fcb68fd2 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -29,3 +29,4 @@ common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o
 common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o
 
 obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o
+obj-$(CONFIG_TERMINAL3270) += terminal3270.o
diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c
new file mode 100644
index 0000000000..b2dda01baa
--- /dev/null
+++ b/hw/char/terminal3270.c
@@ -0,0 +1,293 @@
+/*
+ * Terminal 3270 implementation
+ *
+ * Copyright 2017 IBM Corp.
+ *
+ * Authors: Yang Chen <bjcyang@linux.vnet.ibm.com>
+ *          Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "sysemu/char.h"
+#include "hw/s390x/3270-ccw.h"
+
+/* Enough spaces for different window sizes. */
+#define INPUT_BUFFER_SIZE  1000
+/*
+ * 1 for header, 1024*2 for datastream, 2 for tail
+ * Reserve enough spaces for telnet IAC escape.
+ */
+#define OUTPUT_BUFFER_SIZE 2051
+
+typedef struct Terminal3270 {
+    EmulatedCcw3270Device cdev;
+    CharBackend chr;
+    uint8_t inv[INPUT_BUFFER_SIZE];
+    uint8_t outv[OUTPUT_BUFFER_SIZE];
+    int in_len;
+    int out_len;
+    bool handshake_done;
+    guint timer_tag;
+} Terminal3270;
+
+#define TYPE_TERMINAL_3270 "x-terminal3270"
+#define TERMINAL_3270(obj) \
+        OBJECT_CHECK(Terminal3270, (obj), TYPE_TERMINAL_3270)
+
+static int terminal_can_read(void *opaque)
+{
+    Terminal3270 *t = opaque;
+
+    return INPUT_BUFFER_SIZE - t->in_len;
+}
+
+/*
+ * Protocol handshake done,
+ * signal guest by an unsolicited DE irq.
+ */
+static void TN3270_handshake_done(Terminal3270 *t)
+{
+    CcwDevice *ccw_dev = CCW_DEVICE(t);
+    SubchDev *sch = ccw_dev->sch;
+
+    t->handshake_done = true;
+    sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END;
+    css_conditional_io_interrupt(sch);
+}
+
+/*
+ * Called when the interval is timeout to detect
+ * if the client is still alive by Timing Mark.
+ */
+static gboolean send_timing_mark_cb(gpointer opaque)
+{
+    Terminal3270 *t = opaque;
+    const uint8_t timing[] = {0xff, 0xfd, 0x06};
+
+    qemu_chr_fe_write_all(&t->chr, timing, sizeof(timing));
+    return true;
+}
+
+/*
+ * Receive inbound data from socket.
+ * For data given to guest, drop the data boundary IAC, IAC_EOR.
+ * TODO:
+ * Using "Reset" key on x3270 may result multiple commands in one packet.
+ * This usually happens when the user meets a poor traffic of the network.
+ * As of now, for such case, we simply terminate the connection,
+ * and we should come back here later with a better solution.
+ */
+static void terminal_read(void *opaque, const uint8_t *buf, int size)
+{
+    Terminal3270 *t = opaque;
+    CcwDevice *ccw_dev = CCW_DEVICE(t);
+    SubchDev *sch = ccw_dev->sch;
+    int end;
+
+    assert(size <= (INPUT_BUFFER_SIZE - t->in_len));
+
+    if (t->timer_tag) {
+        g_source_remove(t->timer_tag);
+        t->timer_tag = 0;
+    }
+    t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t);
+
+    memcpy(&t->inv[t->in_len], buf, size);
+    t->in_len += size;
+    if (t->in_len < 2) {
+        return;
+    }
+
+    if (!t->handshake_done) {
+        /*
+         * Receiving Terminal Type is the last step of handshake.
+         * The data format: IAC SB Terminal-Type IS <terminal type> IAC SE
+         * The code for Terminal-Type is 0x18, for IS is 0.
+         * Simply check the data format and mark handshake_done.
+         */
+        if (t->in_len > 6 && t->inv[2] == 0x18 && t->inv[3] == 0x0 &&
+            t->inv[t->in_len - 2] == IAC && t->inv[t->in_len - 1] == IAC_SE) {
+            TN3270_handshake_done(t);
+            t->in_len = 0;
+        }
+        return;
+    }
+
+    for (end = 0; end < t->in_len - 1; end++) {
+        if (t->inv[end] == IAC && t->inv[end + 1] == IAC_EOR) {
+            break;
+        }
+    }
+    if (end == t->in_len - 2) {
+        /* Data is valid for consuming. */
+        t->in_len -= 2;
+        sch->curr_status.scsw.dstat = SCSW_DSTAT_ATTENTION;
+        css_conditional_io_interrupt(sch);
+    } else if (end < t->in_len - 2) {
+        /* "Reset" key is used. */
+        qemu_chr_fe_disconnect(&t->chr);
+    } else {
+        /* Gathering data. */
+        return;
+    }
+}
+
+static void chr_event(void *opaque, int event)
+{
+    Terminal3270 *t = opaque;
+    CcwDevice *ccw_dev = CCW_DEVICE(t);
+    SubchDev *sch = ccw_dev->sch;
+
+    /* Ensure the initial status correct, always reset them. */
+    t->in_len = 0;
+    t->out_len = 0;
+    t->handshake_done = false;
+    if (t->timer_tag) {
+        g_source_remove(t->timer_tag);
+        t->timer_tag = 0;
+    }
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        /*
+         * 3270 does handshake firstly by the negotiate options in
+         * char-socket.c. Once qemu receives the terminal-type of the
+         * client, mark handshake done and trigger everything rolling again.
+         */
+        t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t);
+        break;
+    case CHR_EVENT_CLOSED:
+        sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END;
+        css_conditional_io_interrupt(sch);
+        break;
+    }
+}
+
+static void terminal_init(EmulatedCcw3270Device *dev, Error **errp)
+{
+    Terminal3270 *t = TERMINAL_3270(dev);
+    static bool terminal_available;
+
+    if (terminal_available) {
+        error_setg(errp, "Multiple 3270 terminals are not supported.");
+        return;
+    }
+    terminal_available = true;
+    qemu_chr_fe_set_handlers(&t->chr, terminal_can_read,
+                             terminal_read, chr_event, t, NULL, true);
+}
+
+static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda,
+                             uint16_t count)
+{
+    Terminal3270 *t = TERMINAL_3270(dev);
+    int len;
+
+    len = MIN(count, t->in_len);
+    cpu_physical_memory_write(cda, t->inv, len);
+    t->in_len -= len;
+
+    return len;
+}
+
+/* TN3270 uses binary transmission, which needs escape IAC to IAC IAC */
+static int insert_IAC_escape_char(uint8_t *outv, int out_len)
+{
+    int IAC_num = 0, new_out_len, i, j;
+
+    for (i = 0; i < out_len; i++) {
+        if (outv[i] == IAC) {
+            IAC_num++;
+        }
+    }
+    if (IAC_num == 0) {
+        return out_len;
+    }
+    new_out_len = out_len + IAC_num;
+    for (i = out_len - 1, j = new_out_len - 1; j > i && i >= 0; i--, j--) {
+        outv[j] = outv[i];
+        if (outv[i] == IAC) {
+            outv[--j] = IAC;
+        }
+    }
+    return new_out_len;
+}
+
+/*
+ * Write 3270 outbound to socket.
+ * Return the count of 3270 data field if succeeded, zero if failed.
+ */
+static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd,
+                              uint32_t cda, uint16_t count)
+{
+    Terminal3270 *t = TERMINAL_3270(dev);
+    int retval = 0;
+
+    assert(count <= (OUTPUT_BUFFER_SIZE - 3) / 2);
+
+    if (!t->handshake_done) {
+        if (!(t->outv[0] == IAC && t->outv[1] != IAC)) {
+            /*
+             * Before having finished 3270 negotiation,
+             * sending outbound data except protocol options is prohibited.
+             */
+            return 0;
+        }
+    }
+    if (!qemu_chr_fe_get_driver(&t->chr)) {
+        /* We just say we consumed all data if there's no backend. */
+        return count;
+    }
+    t->outv[0] = cmd;
+    cpu_physical_memory_read(cda, &t->outv[1], count);
+    t->out_len = count + 1;
+
+    t->out_len = insert_IAC_escape_char(t->outv, t->out_len);
+    t->outv[t->out_len++] = IAC;
+    t->outv[t->out_len++] = IAC_EOR;
+
+    retval = qemu_chr_fe_write_all(&t->chr, t->outv, t->out_len);
+    return (retval <= 0) ? 0 : (retval - 3);
+}
+
+static Property terminal_properties[] = {
+    DEFINE_PROP_CHR("chardev", Terminal3270, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription terminal3270_vmstate = {
+    .name = TYPE_TERMINAL_3270,
+    .unmigratable = 1,
+};
+
+static void terminal_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    EmulatedCcw3270Class *ck = EMULATED_CCW_3270_CLASS(klass);
+
+    dc->props = terminal_properties;
+    dc->vmsd = &terminal3270_vmstate;
+    ck->init = terminal_init;
+    ck->read_payload_3270 = read_payload_3270;
+    ck->write_payload_3270 = write_payload_3270;
+}
+
+static const TypeInfo ccw_terminal_info = {
+    .name = TYPE_TERMINAL_3270,
+    .parent = TYPE_EMULATED_CCW_3270,
+    .instance_size = sizeof(Terminal3270),
+    .class_init = terminal_class_init,
+    .class_size = sizeof(EmulatedCcw3270Class),
+};
+
+static void register_types(void)
+{
+    type_register_static(&ccw_terminal_info);
+}
+
+type_init(register_types)
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 03d9197f71..7ef8a96496 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -113,7 +113,7 @@ static void cg3_update_display(void *opaque)
     for (y = 0; y < height; y++) {
         int update = s->full_update;
 
-        page = y * width;
+        page = (ram_addr_t)y * width;
         update |= memory_region_get_dirty(&s->vram_mem, page, width,
                                           DIRTY_MEMORY_VGA);
         if (update) {
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index 5a1115cc65..0e66dcd055 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -145,7 +145,6 @@ static void update_palette_entries(TCXState *s, int start, int end)
         } else {
             s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
         }
-        break;
     }
     tcx_set_dirty(s, 0, memory_region_size(&s->vram_mem));
 }
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 2073108577..1d8c645ed3 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -272,7 +272,7 @@ build_facs(GArray *table_data, BIOSLinker *linker)
 }
 
 /* Load chipset information in FADT */
-static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm)
+static void fadt_setup(AcpiFadtDescriptorRev3 *fadt, AcpiPmInfo *pm)
 {
     fadt->model = 1;
     fadt->reserved1 = 0;
@@ -304,6 +304,31 @@ static void fadt_setup(AcpiFadtDescriptorRev1 *fadt, AcpiPmInfo *pm)
         fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_FORCE_APIC_CLUSTER_MODEL);
     }
     fadt->century = RTC_CENTURY;
+
+    fadt->flags |= cpu_to_le32(1 << ACPI_FADT_F_RESET_REG_SUP);
+    fadt->reset_value = 0xf;
+    fadt->reset_register.space_id = AML_SYSTEM_IO;
+    fadt->reset_register.bit_width = 8;
+    fadt->reset_register.address = cpu_to_le64(ICH9_RST_CNT_IOPORT);
+    /* The above need not be conditional on machine type because the reset port
+     * happens to be the same on PIIX (pc) and ICH9 (q35). */
+    QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != RCR_IOPORT);
+
+    fadt->xpm1a_event_block.space_id = AML_SYSTEM_IO;
+    fadt->xpm1a_event_block.bit_width = fadt->pm1_evt_len * 8;
+    fadt->xpm1a_event_block.address = cpu_to_le64(pm->io_base);
+
+    fadt->xpm1a_control_block.space_id = AML_SYSTEM_IO;
+    fadt->xpm1a_control_block.bit_width = fadt->pm1_cnt_len * 8;
+    fadt->xpm1a_control_block.address = cpu_to_le64(pm->io_base + 0x4);
+
+    fadt->xpm_timer_block.space_id = AML_SYSTEM_IO;
+    fadt->xpm_timer_block.bit_width = fadt->pm_tmr_len * 8;
+    fadt->xpm_timer_block.address = cpu_to_le64(pm->io_base + 0x8);
+
+    fadt->xgpe0_block.space_id = AML_SYSTEM_IO;
+    fadt->xgpe0_block.bit_width = pm->gpe0_blk_len * 8;
+    fadt->xgpe0_block.address = cpu_to_le64(pm->gpe0_blk);
 }
 
 
@@ -313,9 +338,10 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm,
            unsigned facs_tbl_offset, unsigned dsdt_tbl_offset,
            const char *oem_id, const char *oem_table_id)
 {
-    AcpiFadtDescriptorRev1 *fadt = acpi_data_push(table_data, sizeof(*fadt));
+    AcpiFadtDescriptorRev3 *fadt = acpi_data_push(table_data, sizeof(*fadt));
     unsigned fw_ctrl_offset = (char *)&fadt->firmware_ctrl - table_data->data;
     unsigned dsdt_entry_offset = (char *)&fadt->dsdt - table_data->data;
+    unsigned xdsdt_entry_offset = (char *)&fadt->Xdsdt - table_data->data;
 
     /* FACS address to be filled by Guest linker */
     bios_linker_loader_add_pointer(linker,
@@ -327,9 +353,12 @@ build_fadt(GArray *table_data, BIOSLinker *linker, AcpiPmInfo *pm,
     bios_linker_loader_add_pointer(linker,
         ACPI_BUILD_TABLE_FILE, dsdt_entry_offset, sizeof(fadt->dsdt),
         ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
+    bios_linker_loader_add_pointer(linker,
+        ACPI_BUILD_TABLE_FILE, xdsdt_entry_offset, sizeof(fadt->Xdsdt),
+        ACPI_BUILD_TABLE_FILE, dsdt_tbl_offset);
 
     build_header(linker, table_data,
-                 (void *)fadt, "FACP", sizeof(*fadt), 1, oem_id, oem_table_id);
+                 (void *)fadt, "FACP", sizeof(*fadt), 3, oem_id, oem_table_id);
 }
 
 void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid,
diff --git a/hw/input/hid.c b/hw/input/hid.c
index fa9cc4c616..93887ecc43 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -256,6 +256,10 @@ static void hid_keyboard_process_keycode(HIDState *hs)
     slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
     keycode = hs->kbd.keycodes[slot];
 
+    if (!hs->n) {
+        trace_hid_kbd_queue_empty();
+    }
+
     key = keycode & 0x7f;
     index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
     hid_code = hid_usage_keys[index];
diff --git a/hw/input/trace-events b/hw/input/trace-events
index f3bfbede5c..5a87818b49 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -24,6 +24,7 @@ milkymist_softusb_pulse_irq(void) "Pulse IRQ"
 
 # hw/input/hid.c
 hid_kbd_queue_full(void) "queue full"
+hid_kbd_queue_empty(void) "queue empty"
 
 # hw/input/virtio
 virtio_input_queue_full(void) "queue full"
diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c
index a98c799de6..febc469170 100644
--- a/hw/openrisc/cputimer.c
+++ b/hw/openrisc/cputimer.c
@@ -61,6 +61,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu)
     }
     next = now + (uint64_t)wait * TIMER_PERIOD;
     timer_mod(cpu->env.timer, next);
+    qemu_cpu_kick(CPU(cpu));
 }
 
 void cpu_openrisc_count_start(OpenRISCCPU *cpu)
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index f9218aa952..bf4221d4bf 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -58,12 +58,6 @@ typedef struct I440FXState {
 #define XEN_PIIX_NUM_PIRQS      128ULL
 #define PIIX_PIRQC              0x60
 
-/*
- * Reset Control Register: PCI-accessible ISA-Compatible Register at address
- * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
- */
-#define RCR_IOPORT 0xcf9
-
 typedef struct PIIX3State {
     PCIDevice dev;
 
diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c
index a8c18203d6..828052b0c0 100644
--- a/hw/pci/pcie_aer.c
+++ b/hw/pci/pcie_aer.c
@@ -44,6 +44,13 @@
 #define PCI_ERR_SRC_COR_OFFS    0
 #define PCI_ERR_SRC_UNCOR_OFFS  2
 
+typedef struct PCIEErrorDetails {
+    const char *id;
+    const char *root_bus;
+    int bus;
+    int devfn;
+} PCIEErrorDetails;
+
 /* From 6.2.7 Error Listing and Rules. Table 6-2, 6-3 and 6-4 */
 static uint32_t pcie_aer_uncor_default_severity(uint32_t status)
 {
@@ -369,7 +376,7 @@ static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
  *
  * Walk up the bus tree from the device, propagate the error message.
  */
-void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
+static void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg)
 {
     uint8_t type;
 
@@ -624,7 +631,7 @@ static bool pcie_aer_inject_uncor_error(PCIEAERInject *inj, bool is_fatal)
  * Figure 6-2: Flowchart Showing Sequence of Device Error Signaling and Logging
  *             Operations
  */
-int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
+static int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err)
 {
     uint8_t *aer_cap = NULL;
     uint16_t devctl = 0;
@@ -942,8 +949,14 @@ static int pcie_aer_parse_error_string(const char *error_name,
     return -EINVAL;
 }
 
+/*
+ * Inject an error described by @qdict.
+ * On success, set @details to show where error was sent.
+ * Return negative errno if injection failed and a message was emitted.
+ */
 static int do_pcie_aer_inject_error(Monitor *mon,
-                                    const QDict *qdict, QObject **ret_data)
+                                    const QDict *qdict,
+                                    PCIEErrorDetails *details)
 {
     const char *id = qdict_get_str(qdict, "id");
     const char *error_name;
@@ -1005,33 +1018,28 @@ static int do_pcie_aer_inject_error(Monitor *mon,
     err.prefix[3] = qdict_get_try_int(qdict, "prefix3", 0);
 
     ret = pcie_aer_inject_error(dev, &err);
-    *ret_data = qobject_from_jsonf("{'id': %s, "
-                                   "'root_bus': %s, 'bus': %d, 'devfn': %d, "
-                                   "'ret': %d}",
-                                   id, pci_root_bus_path(dev),
-                                   pci_bus_num(dev->bus), dev->devfn,
-                                   ret);
-    assert(*ret_data);
+    if (ret < 0) {
+        monitor_printf(mon, "failed to inject error: %s\n",
+                       strerror(-ret));
+        return ret;
+    }
+    details->id = id;
+    details->root_bus = pci_root_bus_path(dev);
+    details->bus = pci_bus_num(dev->bus);
+    details->devfn = dev->devfn;
 
     return 0;
 }
 
 void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict)
 {
-    QObject *data;
-    int devfn;
+    PCIEErrorDetails data;
 
     if (do_pcie_aer_inject_error(mon, qdict, &data) < 0) {
         return;
     }
 
-    qdict = qobject_to_qdict(data);
-    assert(qdict);
-
-    devfn = (int)qdict_get_int(qdict, "devfn");
     monitor_printf(mon, "OK id: %s root bus: %s, bus: %x devfn: %x.%x\n",
-                   qdict_get_str(qdict, "id"),
-                   qdict_get_str(qdict, "root_bus"),
-                   (int) qdict_get_int(qdict, "bus"),
-                   PCI_SLOT(devfn), PCI_FUNC(devfn));
+                   data.id, data.root_bus, data.bus,
+                   PCI_SLOT(data.devfn), PCI_FUNC(data.devfn));
 }
diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c
new file mode 100644
index 0000000000..a7a5b412e4
--- /dev/null
+++ b/hw/s390x/3270-ccw.c
@@ -0,0 +1,174 @@
+/*
+ * Emulated ccw-attached 3270 implementation
+ *
+ * Copyright 2017 IBM Corp.
+ * Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com>
+ *            Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "cpu.h"
+#include "hw/s390x/css.h"
+#include "hw/s390x/css-bridge.h"
+#include "hw/s390x/3270-ccw.h"
+
+/* Handle READ ccw commands from guest */
+static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw)
+{
+    EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
+    CcwDevice *ccw_dev = CCW_DEVICE(dev);
+    int len;
+
+    if (!ccw->cda) {
+        return -EFAULT;
+    }
+
+    len = ck->read_payload_3270(dev, ccw->cda, ccw->count);
+    ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
+
+    return 0;
+}
+
+/* Handle WRITE ccw commands to write data to client */
+static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw)
+{
+    EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
+    CcwDevice *ccw_dev = CCW_DEVICE(dev);
+    int len;
+
+    if (!ccw->cda) {
+        return -EFAULT;
+    }
+
+    len = ck->write_payload_3270(dev, ccw->cmd_code, ccw->cda, ccw->count);
+
+    if (len <= 0) {
+        return -EIO;
+    }
+
+    ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
+    return 0;
+}
+
+static int emulated_ccw_3270_cb(SubchDev *sch, CCW1 ccw)
+{
+    int rc = 0;
+    EmulatedCcw3270Device *dev = sch->driver_data;
+
+    switch (ccw.cmd_code) {
+    case TC_WRITESF:
+    case TC_WRITE:
+    case TC_EWRITE:
+    case TC_EWRITEA:
+        rc = handle_payload_3270_write(dev, &ccw);
+        break;
+    case TC_RDBUF:
+    case TC_READMOD:
+        rc = handle_payload_3270_read(dev, &ccw);
+        break;
+    default:
+        rc = -ENOSYS;
+        break;
+    }
+
+    if (rc == -EIO) {
+        /* I/O error, specific devices generate specific conditions */
+        SCSW *s = &sch->curr_status.scsw;
+
+        sch->curr_status.scsw.dstat = SCSW_DSTAT_UNIT_CHECK;
+        sch->sense_data[0] = 0x40;    /* intervention-req */
+        s->ctrl &= ~SCSW_ACTL_START_PEND;
+        s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
+        s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
+                   SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
+    }
+
+    return rc;
+}
+
+static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
+{
+    uint16_t chpid;
+    EmulatedCcw3270Device *dev = EMULATED_CCW_3270(ds);
+    EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
+    CcwDevice *cdev = CCW_DEVICE(ds);
+    CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev);
+    SubchDev *sch = css_create_virtual_sch(cdev->devno, errp);
+    Error *err = NULL;
+
+    if (!sch) {
+        return;
+    }
+
+    if (!ck->init) {
+        goto out_err;
+    }
+
+    sch->driver_data = dev;
+    cdev->sch = sch;
+    chpid = css_find_free_chpid(sch->cssid);
+
+    if (chpid > MAX_CHPID) {
+        error_setg(&err, "No available chpid to use.");
+        goto out_err;
+    }
+
+    sch->id.reserved = 0xff;
+    sch->id.cu_type = EMULATED_CCW_3270_CU_TYPE;
+    css_sch_build_virtual_schib(sch, (uint8_t)chpid,
+                                EMULATED_CCW_3270_CHPID_TYPE);
+    sch->ccw_cb = emulated_ccw_3270_cb;
+
+    ck->init(dev, &err);
+    if (err) {
+        goto out_err;
+    }
+
+    cdk->realize(cdev, &err);
+    if (err) {
+        goto out_err;
+    }
+
+    return;
+
+out_err:
+    error_propagate(errp, err);
+    css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
+    cdev->sch = NULL;
+    g_free(sch);
+}
+
+static Property emulated_ccw_3270_properties[] = {
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = emulated_ccw_3270_properties;
+    dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
+    dc->realize = emulated_ccw_3270_realize;
+    dc->hotpluggable = false;
+}
+
+static const TypeInfo emulated_ccw_3270_info = {
+    .name = TYPE_EMULATED_CCW_3270,
+    .parent = TYPE_CCW_DEVICE,
+    .instance_size = sizeof(EmulatedCcw3270Device),
+    .class_init = emulated_ccw_3270_class_init,
+    .class_size = sizeof(EmulatedCcw3270Class),
+    .abstract = true,
+};
+
+static void emulated_ccw_register(void)
+{
+    type_register_static(&emulated_ccw_3270_info);
+}
+
+type_init(emulated_ccw_register)
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index 41ac4ec325..36bd4b1645 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -7,6 +7,7 @@ obj-y += sclpcpu.o
 obj-y += ipl.o
 obj-y += css.o
 obj-y += s390-virtio-ccw.o
+obj-y += 3270-ccw.o
 obj-y += virtio-ccw.o
 obj-y += css-bridge.o
 obj-y += ccw-device.o
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index c03bb20bc9..15c4f4b249 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -576,6 +576,9 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
             s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END;
             s->cpa = sch->channel_prog + 8;
             break;
+        case -EIO:
+            /* I/O errors, status depends on specific devices */
+            break;
         case -ENOSYS:
             /* unsupported command, generate unit check (command reject) */
             s->ctrl &= ~SCSW_ACTL_START_PEND;
@@ -1302,6 +1305,27 @@ bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid)
                                  (MAX_SCHID + 1) / sizeof(unsigned long));
 }
 
+unsigned int css_find_free_chpid(uint8_t cssid)
+{
+    CssImage *css = channel_subsys.css[cssid];
+    unsigned int chpid;
+
+    if (!css) {
+        return MAX_CHPID + 1;
+    }
+
+    for (chpid = 0; chpid <= MAX_CHPID; chpid++) {
+        /* skip reserved chpid */
+        if (chpid == VIRTIO_CCW_CHPID) {
+            continue;
+        }
+        if (!css->chpids[chpid].in_use) {
+            return chpid;
+        }
+    }
+    return MAX_CHPID + 1;
+}
+
 static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
 {
     CssImage *css;
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 7978c7d52a..75d3c681a4 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -17,8 +17,10 @@
 #include "cpu.h"
 #include "elf.h"
 #include "hw/loader.h"
+#include "hw/boards.h"
 #include "hw/s390x/virtio-ccw.h"
 #include "hw/s390x/css.h"
+#include "hw/s390x/ebcdic.h"
 #include "ipl.h"
 #include "qemu/error-report.h"
 
@@ -243,12 +245,17 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
             ipl->iplb.pbt = S390_IPL_TYPE_CCW;
             ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
             ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
-            return true;
         } else if (sd) {
             SCSIBus *bus = scsi_bus_from_device(sd);
             VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
             VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev);
-            CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw);
+            CcwDevice *ccw_dev;
+
+            ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
+                                                       TYPE_CCW_DEVICE);
+            if (!ccw_dev) {       /* It might be a PCI device instead */
+                return false;
+            }
 
             ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
             ipl->iplb.blk0_len =
@@ -259,13 +266,39 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
             ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
             ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
             ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
-            return true;
+        } else {
+            return false; /* unknown device */
         }
+
+        if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
+            ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
+        }
+        return true;
     }
 
     return false;
 }
 
+int s390_ipl_set_loadparm(uint8_t *loadparm)
+{
+    MachineState *machine = MACHINE(qdev_get_machine());
+    char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
+
+    if (lp) {
+        int i;
+
+        /* lp is an uppercase string without leading/embedded spaces */
+        for (i = 0; i < 8 && lp[i]; i++) {
+            loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
+        }
+
+        g_free(lp);
+        return 0;
+    }
+
+    return -1;
+}
+
 static int load_netboot_image(Error **errp)
 {
     S390IPLState *ipl = get_ipl_device();
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 46930e4c64..8a705e0428 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -57,6 +57,8 @@ struct IplBlockQemuScsi {
 } QEMU_PACKED;
 typedef struct IplBlockQemuScsi IplBlockQemuScsi;
 
+#define DIAG308_FLAGS_LP_VALID 0x80
+
 union IplParameterBlock {
     struct {
         uint32_t len;
@@ -82,6 +84,7 @@ union IplParameterBlock {
 } QEMU_PACKED;
 typedef union IplParameterBlock IplParameterBlock;
 
+int s390_ipl_set_loadparm(uint8_t *loadparm);
 void s390_ipl_update_diag308(IplParameterBlock *iplb);
 void s390_ipl_prepare_cpu(S390CPU *cpu);
 IplParameterBlock *s390_ipl_get_iplb(void);
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 04bd0ebe40..fdd4384ff0 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -274,6 +274,36 @@ bool cpu_model_allowed(void)
     return true;
 }
 
+static char *machine_get_loadparm(Object *obj, Error **errp)
+{
+    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+
+    return g_memdup(ms->loadparm, sizeof(ms->loadparm));
+}
+
+static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
+{
+    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+    int i;
+
+    for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
+        uint8_t c = toupper(val[i]); /* mimic HMC */
+
+        if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
+            (c == ' ')) {
+            ms->loadparm[i] = c;
+        } else {
+            error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
+                       c, c);
+            return;
+        }
+    }
+
+    for (; i < sizeof(ms->loadparm); i++) {
+        ms->loadparm[i] = ' '; /* pad right with spaces */
+    }
+}
+
 static inline void s390_machine_initfn(Object *obj)
 {
     object_property_add_bool(obj, "aes-key-wrap",
@@ -291,6 +321,13 @@ static inline void s390_machine_initfn(Object *obj)
             "enable/disable DEA key wrapping using the CPACF wrapping key",
             NULL);
     object_property_set_bool(obj, true, "dea-key-wrap", NULL);
+    object_property_add_str(obj, "loadparm",
+            machine_get_loadparm, machine_set_loadparm, NULL);
+    object_property_set_description(obj, "loadparm",
+            "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted"
+            " to upper case) to pass to machine loader, boot manager,"
+            " and guest kernel",
+            NULL);
 }
 
 static const TypeInfo ccw_machine_info = {
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 6996088584..83d6023894 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -23,6 +23,7 @@
 #include "hw/s390x/sclp.h"
 #include "hw/s390x/event-facility.h"
 #include "hw/s390x/s390-pci-bus.h"
+#include "hw/s390x/ipl.h"
 
 static inline SCLPDevice *get_sclp_device(void)
 {
@@ -57,6 +58,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
     int cpu_count = 0;
     int rnsize, rnmax;
     int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
+    IplParameterBlock *ipib = s390_ipl_get_iplb();
 
     CPU_FOREACH(cpu) {
         cpu_count++;
@@ -129,6 +131,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
         read_info->rnmax2 = cpu_to_be64(rnmax);
     }
 
+    if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
+        memcpy(&read_info->loadparm, &ipib->loadparm,
+               sizeof(read_info->loadparm));
+    } else {
+        s390_ipl_set_loadparm(read_info->loadparm);
+    }
+
     sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
 }
 
diff --git a/hw/scsi/Makefile.objs b/hw/scsi/Makefile.objs
index 5a2248be36..54d8754e9a 100644
--- a/hw/scsi/Makefile.objs
+++ b/hw/scsi/Makefile.objs
@@ -10,5 +10,5 @@ obj-$(CONFIG_PSERIES) += spapr_vscsi.o
 
 ifeq ($(CONFIG_VIRTIO),y)
 obj-y += virtio-scsi.o virtio-scsi-dataplane.o
-obj-$(CONFIG_VHOST_SCSI) += vhost-scsi.o
+obj-$(CONFIG_VHOST_SCSI) += vhost-scsi-common.o vhost-scsi.o
 endif
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 84b8caf901..804122ab05 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -2138,15 +2138,15 @@ static void megasas_mmio_write(void *opaque, hwaddr addr,
     case MFI_SEQ:
         trace_megasas_mmio_writel("MFI_SEQ", val);
         /* Magic sequence to start ADP reset */
-        if (adp_reset_seq[s->adp_reset] == val) {
-            s->adp_reset++;
+        if (adp_reset_seq[s->adp_reset++] == val) {
+            if (s->adp_reset == 6) {
+                s->adp_reset = 0;
+                s->diag = MFI_DIAG_WRITE_ENABLE;
+            }
         } else {
             s->adp_reset = 0;
             s->diag = 0;
         }
-        if (s->adp_reset == 6) {
-            s->diag = MFI_DIAG_WRITE_ENABLE;
-        }
         break;
     case MFI_DIAG:
         trace_megasas_mmio_writel("MFI_DIAG", val);
diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c
new file mode 100644
index 0000000000..e41c0314db
--- /dev/null
+++ b/hw/scsi/vhost-scsi-common.c
@@ -0,0 +1,143 @@
+/*
+ * vhost-scsi-common
+ *
+ * Copyright (c) 2016 Nutanix Inc. All rights reserved.
+ *
+ * Author:
+ *  Felipe Franciosi <felipe@nutanix.com>
+ *
+ * This work is largely based on the "vhost-scsi" implementation by:
+ *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
+ *  Nicholas Bellinger <nab@risingtidesystems.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 "qemu/osdep.h"
+#include <linux/vhost.h>
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "migration/migration.h"
+#include "hw/virtio/vhost.h"
+#include "hw/virtio/vhost-scsi-common.h"
+#include "hw/virtio/virtio-scsi.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/virtio-access.h"
+#include "hw/fw-path-provider.h"
+
+int vhost_scsi_common_start(VHostSCSICommon *vsc)
+{
+    int ret, i;
+    VirtIODevice *vdev = VIRTIO_DEVICE(vsc);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+
+    if (!k->set_guest_notifiers) {
+        error_report("binding does not support guest notifiers");
+        return -ENOSYS;
+    }
+
+    ret = vhost_dev_enable_notifiers(&vsc->dev, vdev);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, true);
+    if (ret < 0) {
+        error_report("Error binding guest notifier");
+        goto err_host_notifiers;
+    }
+
+    vsc->dev.acked_features = vdev->guest_features;
+    ret = vhost_dev_start(&vsc->dev, vdev);
+    if (ret < 0) {
+        error_report("Error start vhost dev");
+        goto err_guest_notifiers;
+    }
+
+    /* guest_notifier_mask/pending not used yet, so just unmask
+     * everything here.  virtio-pci will do the right thing by
+     * enabling/disabling irqfd.
+     */
+    for (i = 0; i < vsc->dev.nvqs; i++) {
+        vhost_virtqueue_mask(&vsc->dev, vdev, vsc->dev.vq_index + i, false);
+    }
+
+    return ret;
+
+err_guest_notifiers:
+    k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false);
+err_host_notifiers:
+    vhost_dev_disable_notifiers(&vsc->dev, vdev);
+    return ret;
+}
+
+void vhost_scsi_common_stop(VHostSCSICommon *vsc)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(vsc);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    int ret = 0;
+
+    vhost_dev_stop(&vsc->dev, vdev);
+
+    if (k->set_guest_notifiers) {
+        ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false);
+        if (ret < 0) {
+                error_report("vhost guest notifier cleanup failed: %d", ret);
+        }
+    }
+    assert(ret >= 0);
+
+    vhost_dev_disable_notifiers(&vsc->dev, vdev);
+}
+
+uint64_t vhost_scsi_common_get_features(VirtIODevice *vdev, uint64_t features,
+                                        Error **errp)
+{
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(vdev);
+
+    return vhost_get_features(&vsc->dev, vsc->feature_bits, features);
+}
+
+void vhost_scsi_common_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
+    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
+
+    if ((uint32_t)virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size ||
+        (uint32_t)virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) {
+        error_report("vhost-scsi does not support changing the sense data and "
+                     "CDB sizes");
+        exit(1);
+    }
+}
+
+/*
+ * Implementation of an interface to adjust firmware path
+ * for the bootindex property handling.
+ */
+char *vhost_scsi_common_get_fw_dev_path(FWPathProvider *p, BusState *bus,
+                                        DeviceState *dev)
+{
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
+    /* format: /channel@channel/vhost-scsi@target,lun */
+    return g_strdup_printf("/channel@%x/%s@%x,%x", vsc->channel,
+                           qdev_fw_name(dev), vsc->target, vsc->lun);
+}
+
+static const TypeInfo vhost_scsi_common_info = {
+    .name = TYPE_VHOST_SCSI_COMMON,
+    .parent = TYPE_VIRTIO_SCSI_COMMON,
+    .instance_size = sizeof(VHostSCSICommon),
+    .abstract = true,
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&vhost_scsi_common_info);
+}
+
+type_init(virtio_register_types)
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index f53bc179da..8f53ac3795 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -42,13 +42,14 @@ static const int kernel_feature_bits[] = {
 static int vhost_scsi_set_endpoint(VHostSCSI *s)
 {
     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
-    const VhostOps *vhost_ops = s->dev.vhost_ops;
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
+    const VhostOps *vhost_ops = vsc->dev.vhost_ops;
     struct vhost_scsi_target backend;
     int ret;
 
     memset(&backend, 0, sizeof(backend));
     pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
-    ret = vhost_ops->vhost_scsi_set_endpoint(&s->dev, &backend);
+    ret = vhost_ops->vhost_scsi_set_endpoint(&vsc->dev, &backend);
     if (ret < 0) {
         return -errno;
     }
@@ -58,130 +59,62 @@ static int vhost_scsi_set_endpoint(VHostSCSI *s)
 static void vhost_scsi_clear_endpoint(VHostSCSI *s)
 {
     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
     struct vhost_scsi_target backend;
-    const VhostOps *vhost_ops = s->dev.vhost_ops;
+    const VhostOps *vhost_ops = vsc->dev.vhost_ops;
 
     memset(&backend, 0, sizeof(backend));
     pstrcpy(backend.vhost_wwpn, sizeof(backend.vhost_wwpn), vs->conf.wwpn);
-    vhost_ops->vhost_scsi_clear_endpoint(&s->dev, &backend);
+    vhost_ops->vhost_scsi_clear_endpoint(&vsc->dev, &backend);
 }
 
 static int vhost_scsi_start(VHostSCSI *s)
 {
-    int ret, abi_version, i;
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
-    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
-    const VhostOps *vhost_ops = s->dev.vhost_ops;
-
-    if (!k->set_guest_notifiers) {
-        error_report("binding does not support guest notifiers");
-        return -ENOSYS;
-    }
+    int ret, abi_version;
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
+    const VhostOps *vhost_ops = vsc->dev.vhost_ops;
 
-    ret = vhost_ops->vhost_scsi_get_abi_version(&s->dev, &abi_version);
+    ret = vhost_ops->vhost_scsi_get_abi_version(&vsc->dev, &abi_version);
     if (ret < 0) {
         return -errno;
     }
     if (abi_version > VHOST_SCSI_ABI_VERSION) {
         error_report("vhost-scsi: The running tcm_vhost kernel abi_version:"
-                     " %d is greater than vhost_scsi userspace supports: %d, please"
-                     " upgrade your version of QEMU", abi_version,
+                     " %d is greater than vhost_scsi userspace supports: %d,"
+                     " please upgrade your version of QEMU", abi_version,
                      VHOST_SCSI_ABI_VERSION);
         return -ENOSYS;
     }
 
-    ret = vhost_dev_enable_notifiers(&s->dev, vdev);
+    ret = vhost_scsi_common_start(vsc);
     if (ret < 0) {
         return ret;
     }
 
-    s->dev.acked_features = vdev->guest_features;
-    ret = vhost_dev_start(&s->dev, vdev);
-    if (ret < 0) {
-        error_report("Error start vhost dev");
-        goto err_notifiers;
-    }
-
     ret = vhost_scsi_set_endpoint(s);
     if (ret < 0) {
-        error_report("Error set vhost-scsi endpoint");
-        goto err_vhost_stop;
-    }
-
-    ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
-    if (ret < 0) {
-        error_report("Error binding guest notifier");
-        goto err_endpoint;
-    }
-
-    /* guest_notifier_mask/pending not used yet, so just unmask
-     * everything here.  virtio-pci will do the right thing by
-     * enabling/disabling irqfd.
-     */
-    for (i = 0; i < s->dev.nvqs; i++) {
-        vhost_virtqueue_mask(&s->dev, vdev, s->dev.vq_index + i, false);
+        error_report("Error setting vhost-scsi endpoint");
+        vhost_scsi_common_stop(vsc);
     }
 
     return ret;
-
-err_endpoint:
-    vhost_scsi_clear_endpoint(s);
-err_vhost_stop:
-    vhost_dev_stop(&s->dev, vdev);
-err_notifiers:
-    vhost_dev_disable_notifiers(&s->dev, vdev);
-    return ret;
 }
 
 static void vhost_scsi_stop(VHostSCSI *s)
 {
-    VirtIODevice *vdev = VIRTIO_DEVICE(s);
-    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
-    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
-    int ret = 0;
-
-    if (k->set_guest_notifiers) {
-        ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
-        if (ret < 0) {
-                error_report("vhost guest notifier cleanup failed: %d", ret);
-        }
-    }
-    assert(ret >= 0);
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
 
     vhost_scsi_clear_endpoint(s);
-    vhost_dev_stop(&s->dev, vdev);
-    vhost_dev_disable_notifiers(&s->dev, vdev);
-}
-
-static uint64_t vhost_scsi_get_features(VirtIODevice *vdev,
-                                        uint64_t features,
-                                        Error **errp)
-{
-    VHostSCSI *s = VHOST_SCSI(vdev);
-
-    return vhost_get_features(&s->dev, kernel_feature_bits, features);
-}
-
-static void vhost_scsi_set_config(VirtIODevice *vdev,
-                                  const uint8_t *config)
-{
-    VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config;
-    VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev);
-
-    if ((uint32_t) virtio_ldl_p(vdev, &scsiconf->sense_size) != vs->sense_size ||
-        (uint32_t) virtio_ldl_p(vdev, &scsiconf->cdb_size) != vs->cdb_size) {
-        error_report("vhost-scsi does not support changing the sense data and CDB sizes");
-        exit(1);
-    }
+    vhost_scsi_common_stop(vsc);
 }
 
 static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
 {
-    VHostSCSI *s = (VHostSCSI *)vdev;
+    VHostSCSI *s = VHOST_SCSI(vdev);
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
     bool start = (val & VIRTIO_CONFIG_S_DRIVER_OK);
 
-    if (s->dev.started == start) {
+    if (vsc->dev.started == start) {
         return;
     }
 
@@ -190,10 +123,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
 
         ret = vhost_scsi_start(s);
         if (ret < 0) {
-            error_report("virtio-scsi: unable to start vhost: %s",
-                         strerror(-ret));
-
-            /* There is no userspace virtio-scsi fallback so exit */
+            error_report("unable to start vhost-scsi: %s", strerror(-ret));
             exit(1);
         }
     } else {
@@ -208,7 +138,7 @@ static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
 static void vhost_scsi_realize(DeviceState *dev, Error **errp)
 {
     VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
-    VHostSCSI *s = VHOST_SCSI(dev);
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
     Error *err = NULL;
     int vhostfd = -1;
     int ret;
@@ -243,21 +173,21 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
         goto close_fd;
     }
 
-    error_setg(&s->migration_blocker,
+    error_setg(&vsc->migration_blocker,
                "vhost-scsi does not support migration");
-    migrate_add_blocker(s->migration_blocker, &err);
+    migrate_add_blocker(vsc->migration_blocker, &err);
     if (err) {
         error_propagate(errp, err);
-        error_free(s->migration_blocker);
+        error_free(vsc->migration_blocker);
         goto close_fd;
     }
 
-    s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
-    s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs);
-    s->dev.vq_index = 0;
-    s->dev.backend_features = 0;
+    vsc->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues;
+    vsc->dev.vqs = g_new(struct vhost_virtqueue, vsc->dev.nvqs);
+    vsc->dev.vq_index = 0;
+    vsc->dev.backend_features = 0;
 
-    ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
+    ret = vhost_dev_init(&vsc->dev, (void *)(uintptr_t)vhostfd,
                          VHOST_BACKEND_TYPE_KERNEL, 0);
     if (ret < 0) {
         error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
@@ -266,16 +196,16 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
     }
 
     /* At present, channel and lun both are 0 for bootable vhost-scsi disk */
-    s->channel = 0;
-    s->lun = 0;
+    vsc->channel = 0;
+    vsc->lun = 0;
     /* Note: we can also get the minimum tpgt from kernel */
-    s->target = vs->conf.boot_tpgt;
+    vsc->target = vs->conf.boot_tpgt;
 
     return;
 
  free_vqs:
-    migrate_del_blocker(s->migration_blocker);
-    g_free(s->dev.vqs);
+    migrate_del_blocker(vsc->migration_blocker);
+    g_free(vsc->dev.vqs);
  close_fd:
     close(vhostfd);
     return;
@@ -284,42 +214,28 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
 static void vhost_scsi_unrealize(DeviceState *dev, Error **errp)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
-    VHostSCSI *s = VHOST_SCSI(dev);
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(dev);
 
-    migrate_del_blocker(s->migration_blocker);
-    error_free(s->migration_blocker);
+    migrate_del_blocker(vsc->migration_blocker);
+    error_free(vsc->migration_blocker);
 
     /* This will stop vhost backend. */
     vhost_scsi_set_status(vdev, 0);
 
-    vhost_dev_cleanup(&s->dev);
-    g_free(s->dev.vqs);
+    vhost_dev_cleanup(&vsc->dev);
+    g_free(vsc->dev.vqs);
 
     virtio_scsi_common_unrealize(dev, errp);
 }
 
-/*
- * Implementation of an interface to adjust firmware path
- * for the bootindex property handling.
- */
-static char *vhost_scsi_get_fw_dev_path(FWPathProvider *p, BusState *bus,
-                                        DeviceState *dev)
-{
-    VHostSCSI *s = VHOST_SCSI(dev);
-    /* format: channel@channel/vhost-scsi@target,lun */
-    return g_strdup_printf("/channel@%x/%s@%x,%x", s->channel,
-                           qdev_fw_name(dev), s->target, s->lun);
-}
-
 static Property vhost_scsi_properties[] = {
-    DEFINE_PROP_STRING("vhostfd", VHostSCSI, parent_obj.conf.vhostfd),
-    DEFINE_PROP_STRING("wwpn", VHostSCSI, parent_obj.conf.wwpn),
-    DEFINE_PROP_UINT32("boot_tpgt", VHostSCSI, parent_obj.conf.boot_tpgt, 0),
-    DEFINE_PROP_UINT32("num_queues", VHostSCSI, parent_obj.conf.num_queues, 1),
-    DEFINE_PROP_UINT32("max_sectors", VHostSCSI, parent_obj.conf.max_sectors,
-                                                 0xFFFF),
-    DEFINE_PROP_UINT32("cmd_per_lun", VHostSCSI, parent_obj.conf.cmd_per_lun,
-                                                 128),
+    DEFINE_PROP_STRING("vhostfd", VirtIOSCSICommon, conf.vhostfd),
+    DEFINE_PROP_STRING("wwpn", VirtIOSCSICommon, conf.wwpn),
+    DEFINE_PROP_UINT32("boot_tpgt", VirtIOSCSICommon, conf.boot_tpgt, 0),
+    DEFINE_PROP_UINT32("num_queues", VirtIOSCSICommon, conf.num_queues, 1),
+    DEFINE_PROP_UINT32("max_sectors", VirtIOSCSICommon, conf.max_sectors,
+                       0xFFFF),
+    DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSICommon, conf.cmd_per_lun, 128),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -333,23 +249,25 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data)
     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
     vdc->realize = vhost_scsi_realize;
     vdc->unrealize = vhost_scsi_unrealize;
-    vdc->get_features = vhost_scsi_get_features;
-    vdc->set_config = vhost_scsi_set_config;
+    vdc->get_features = vhost_scsi_common_get_features;
+    vdc->set_config = vhost_scsi_common_set_config;
     vdc->set_status = vhost_scsi_set_status;
-    fwc->get_dev_path = vhost_scsi_get_fw_dev_path;
+    fwc->get_dev_path = vhost_scsi_common_get_fw_dev_path;
 }
 
 static void vhost_scsi_instance_init(Object *obj)
 {
-    VHostSCSI *dev = VHOST_SCSI(obj);
+    VHostSCSICommon *vsc = VHOST_SCSI_COMMON(obj);
+
+    vsc->feature_bits = kernel_feature_bits;
 
-    device_add_bootindex_property(obj, &dev->bootindex, "bootindex", NULL,
-                                  DEVICE(dev), NULL);
+    device_add_bootindex_property(obj, &vsc->bootindex, "bootindex", NULL,
+                                  DEVICE(vsc), NULL);
 }
 
 static const TypeInfo vhost_scsi_info = {
     .name = TYPE_VHOST_SCSI,
-    .parent = TYPE_VIRTIO_SCSI_COMMON,
+    .parent = TYPE_VHOST_SCSI_COMMON,
     .instance_size = sizeof(VHostSCSI),
     .class_init = vhost_scsi_class_init,
     .instance_init = vhost_scsi_instance_init,
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index 75575461e2..4a106da856 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -202,7 +202,7 @@ pvscsi_ring_init_msg(PVSCSIRingInfo *m, PVSCSICmdDescSetupMsgRing *ri)
     uint32_t len_log2;
     uint32_t ring_size;
 
-    if (ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) {
+    if (!ri->numPages || ri->numPages > PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES) {
         return -1;
     }
     ring_size = ri->numPages * PVSCSI_MAX_NUM_MSG_ENTRIES_PER_PAGE;
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index daab0d56cf..a41b0d6ec5 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -267,7 +267,7 @@ static void ccid_card_vscard_drop_connection(PassthruState *card)
     Chardev *chr = qemu_chr_fe_get_driver(&card->cs);
 
     qemu_chr_fe_deinit(&card->cs);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
     card->vscard_in_pos = card->vscard_in_hdr = 0;
 }
 
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 0efe62f725..b001a27f05 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1433,7 +1433,7 @@ static void usbredir_unrealize(USBDevice *udev, Error **errp)
     Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
 
     qemu_chr_fe_deinit(&dev->cs);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
 
     /* Note must be done after qemu_chr_close, as that causes a close event */
     qemu_bh_delete(dev->chardev_close_bh);
diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c
index 370b3d9387..fe62183fe3 100644
--- a/hw/usb/xen-usb.c
+++ b/hw/usb/xen-usb.c
@@ -746,16 +746,16 @@ static void usbback_portid_add(struct usbback_info *usbif, unsigned port,
     portname++;
 
     qdict = qdict_new();
-    qdict_put(qdict, "driver", qstring_from_str("usb-host"));
+    qdict_put_str(qdict, "driver", "usb-host");
     tmp = g_strdup_printf("%s.0", usbif->xendev.qdev.id);
-    qdict_put(qdict, "bus", qstring_from_str(tmp));
+    qdict_put_str(qdict, "bus", tmp);
     g_free(tmp);
     tmp = g_strdup_printf("%s-%u", usbif->xendev.qdev.id, port);
-    qdict_put(qdict, "id", qstring_from_str(tmp));
+    qdict_put_str(qdict, "id", tmp);
     g_free(tmp);
-    qdict_put(qdict, "port", qint_from_int(port));
-    qdict_put(qdict, "hostbus", qint_from_int(atoi(busid)));
-    qdict_put(qdict, "hostport", qstring_from_str(portname));
+    qdict_put_int(qdict, "port", port);
+    qdict_put_int(qdict, "hostbus", atoi(busid));
+    qdict_put_str(qdict, "hostport", portname);
     opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err);
     if (local_err) {
         goto err;
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 6b33b9f55d..a8f12eeb35 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -119,6 +119,9 @@ void vfio_region_write(void *opaque, hwaddr addr,
     case 4:
         buf.dword = cpu_to_le32(data);
         break;
+    case 8:
+        buf.qword = cpu_to_le64(data);
+        break;
     default:
         hw_error("vfio: unsupported write size, %d bytes", size);
         break;
@@ -173,6 +176,9 @@ uint64_t vfio_region_read(void *opaque,
     case 4:
         data = le32_to_cpu(buf.dword);
         break;
+    case 8:
+        data = le64_to_cpu(buf.qword);
+        break;
     default:
         hw_error("vfio: unsupported read size, %d bytes", size);
         break;
@@ -190,6 +196,14 @@ const MemoryRegionOps vfio_region_ops = {
     .read = vfio_region_read,
     .write = vfio_region_write,
     .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 8,
+    },
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 8,
+    },
 };
 
 /*
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 03a3d01549..32aca77701 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2625,8 +2625,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
         if (!(~vdev->host.domain || ~vdev->host.bus ||
               ~vdev->host.slot || ~vdev->host.function)) {
             error_setg(errp, "No provided host device");
-            error_append_hint(errp, "Use -vfio-pci,host=DDDD:BB:DD.F "
-                              "or -vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
+            error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
+                              "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
             return;
         }
         vdev->vbasedev.sysfsdev =
diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c
index ae76150e8a..a9055e9eba 100644
--- a/hw/xen/xen-common.c
+++ b/hw/xen/xen-common.c
@@ -38,7 +38,7 @@ static int store_dev_info(int domid, Chardev *cs, const char *string)
     int ret = -1;
 
     /* Only continue if we're talking to a pty. */
-    if (strncmp(cs->filename, "pty:", 4)) {
+    if (!CHARDEV_IS_PTY(cs)) {
         return 0;
     }
     pts = cs->filename + 4;
diff --git a/include/block/nbd.h b/include/block/nbd.h
index 3e373f0498..0ed077502e 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -164,4 +164,7 @@ void nbd_client_new(NBDExport *exp,
 void nbd_client_get(NBDClient *client);
 void nbd_client_put(NBDClient *client);
 
+void nbd_server_start(SocketAddress *addr, const char *tls_creds,
+                      Error **errp);
+
 #endif
diff --git a/include/crypto/block.h b/include/crypto/block.h
index 4a053a3ffa..013a435f1b 100644
--- a/include/crypto/block.h
+++ b/include/crypto/block.h
@@ -30,22 +30,22 @@ typedef struct QCryptoBlock QCryptoBlock;
  * and QCryptoBlockOpenOptions in qapi/crypto.json */
 
 typedef ssize_t (*QCryptoBlockReadFunc)(QCryptoBlock *block,
-                                        void *opaque,
                                         size_t offset,
                                         uint8_t *buf,
                                         size_t buflen,
+                                        void *opaque,
                                         Error **errp);
 
 typedef ssize_t (*QCryptoBlockInitFunc)(QCryptoBlock *block,
-                                        void *opaque,
                                         size_t headerlen,
+                                        void *opaque,
                                         Error **errp);
 
 typedef ssize_t (*QCryptoBlockWriteFunc)(QCryptoBlock *block,
-                                         void *opaque,
                                          size_t offset,
                                          const uint8_t *buf,
                                          size_t buflen,
+                                         void *opaque,
                                          Error **errp);
 
 /**
diff --git a/include/crypto/random.h b/include/crypto/random.h
index a101353202..a07229ce96 100644
--- a/include/crypto/random.h
+++ b/include/crypto/random.h
@@ -40,5 +40,14 @@ int qcrypto_random_bytes(uint8_t *buf,
                          size_t buflen,
                          Error **errp);
 
+/**
+ * qcrypto_random_init:
+ * @errp: pointer to a NULL-initialized error object
+ *
+ * Initializes the handles used by qcrypto_random_bytes
+ *
+ * Returns 0 on success, -1 on error
+ */
+int qcrypto_random_init(Error **errp);
 
 #endif /* QCRYPTO_RANDOM_H */
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index dbe2f08d47..140efa840c 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -39,6 +39,14 @@ struct RAMBlock {
     QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
     int fd;
     size_t page_size;
+    /* dirty bitmap used during migration */
+    unsigned long *bmap;
+    /* bitmap of pages that haven't been sent even once
+     * only maintained and used in postcopy at the moment
+     * where it's used to send the dirtymap at the start
+     * of the postcopy phase
+     */
+    unsigned long *unsentmap;
 };
 
 static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset)
@@ -360,16 +368,15 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
 
 
 static inline
-uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest,
-                                               RAMBlock *rb,
+uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
                                                ram_addr_t start,
                                                ram_addr_t length,
                                                uint64_t *real_dirty_pages)
 {
     ram_addr_t addr;
-    start = rb->offset + start;
     unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
     uint64_t num_dirty = 0;
+    unsigned long *dest = rb->bmap;
 
     /* start address is aligned at the start of a word? */
     if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) {
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index 4cc3630e61..293ee4524b 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -131,17 +131,37 @@ typedef struct AcpiTableHeader AcpiTableHeader;
     uint8_t  duty_width;   /* Bit width of duty cycle field in p_cnt reg */ \
     uint8_t  day_alrm;     /* Index to day-of-month alarm in RTC CMOS RAM */ \
     uint8_t  mon_alrm;     /* Index to month-of-year alarm in RTC CMOS RAM */ \
-    uint8_t  century;      /* Index to century in RTC CMOS RAM */
-
-struct AcpiFadtDescriptorRev1
-{
-    ACPI_FADT_COMMON_DEF
-    uint8_t  reserved4;              /* Reserved */
-    uint8_t  reserved4a;             /* Reserved */
-    uint8_t  reserved4b;             /* Reserved */
-    uint32_t flags;
-} QEMU_PACKED;
-typedef struct AcpiFadtDescriptorRev1 AcpiFadtDescriptorRev1;
+    uint8_t  century;      /* Index to century in RTC CMOS RAM */ \
+    /* IA-PC Boot Architecture Flags (see below for individual flags) */ \
+    uint16_t boot_flags; \
+    uint8_t reserved;    /* Reserved, must be zero */ \
+    /* Miscellaneous flag bits (see below for individual flags) */ \
+    uint32_t flags; \
+    /* 64-bit address of the Reset register */ \
+    struct AcpiGenericAddress reset_register; \
+    /* Value to write to the reset_register port to reset the system */ \
+    uint8_t reset_value; \
+    /* ARM-Specific Boot Flags (see below for individual flags) (ACPI 5.1) */ \
+    uint16_t arm_boot_flags; \
+    uint8_t minor_revision;  /* FADT Minor Revision (ACPI 5.1) */ \
+    uint64_t Xfacs;          /* 64-bit physical address of FACS */ \
+    uint64_t Xdsdt;          /* 64-bit physical address of DSDT */ \
+    /* 64-bit Extended Power Mgt 1a Event Reg Blk address */ \
+    struct AcpiGenericAddress xpm1a_event_block; \
+    /* 64-bit Extended Power Mgt 1b Event Reg Blk address */ \
+    struct AcpiGenericAddress xpm1b_event_block; \
+    /* 64-bit Extended Power Mgt 1a Control Reg Blk address */ \
+    struct AcpiGenericAddress xpm1a_control_block; \
+    /* 64-bit Extended Power Mgt 1b Control Reg Blk address */ \
+    struct AcpiGenericAddress xpm1b_control_block; \
+    /* 64-bit Extended Power Mgt 2 Control Reg Blk address */ \
+    struct AcpiGenericAddress xpm2_control_block; \
+    /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */ \
+    struct AcpiGenericAddress xpm_timer_block; \
+    /* 64-bit Extended General Purpose Event 0 Reg Blk address */ \
+    struct AcpiGenericAddress xgpe0_block; \
+    /* 64-bit Extended General Purpose Event 1 Reg Blk address */ \
+    struct AcpiGenericAddress xgpe1_block; \
 
 struct AcpiGenericAddress {
     uint8_t space_id;        /* Address space where struct or register exists */
@@ -151,38 +171,13 @@ struct AcpiGenericAddress {
     uint64_t address;        /* 64-bit address of struct or register */
 } QEMU_PACKED;
 
+struct AcpiFadtDescriptorRev3 {
+    ACPI_FADT_COMMON_DEF
+} QEMU_PACKED;
+typedef struct AcpiFadtDescriptorRev3 AcpiFadtDescriptorRev3;
+
 struct AcpiFadtDescriptorRev5_1 {
     ACPI_FADT_COMMON_DEF
-    /* IA-PC Boot Architecture Flags (see below for individual flags) */
-    uint16_t boot_flags;
-    uint8_t reserved;    /* Reserved, must be zero */
-    /* Miscellaneous flag bits (see below for individual flags) */
-    uint32_t flags;
-    /* 64-bit address of the Reset register */
-    struct AcpiGenericAddress reset_register;
-    /* Value to write to the reset_register port to reset the system */
-    uint8_t reset_value;
-    /* ARM-Specific Boot Flags (see below for individual flags) (ACPI 5.1) */
-    uint16_t arm_boot_flags;
-    uint8_t minor_revision;  /* FADT Minor Revision (ACPI 5.1) */
-    uint64_t Xfacs;          /* 64-bit physical address of FACS */
-    uint64_t Xdsdt;          /* 64-bit physical address of DSDT */
-    /* 64-bit Extended Power Mgt 1a Event Reg Blk address */
-    struct AcpiGenericAddress xpm1a_event_block;
-    /* 64-bit Extended Power Mgt 1b Event Reg Blk address */
-    struct AcpiGenericAddress xpm1b_event_block;
-    /* 64-bit Extended Power Mgt 1a Control Reg Blk address */
-    struct AcpiGenericAddress xpm1a_control_block;
-    /* 64-bit Extended Power Mgt 1b Control Reg Blk address */
-    struct AcpiGenericAddress xpm1b_control_block;
-    /* 64-bit Extended Power Mgt 2 Control Reg Blk address */
-    struct AcpiGenericAddress xpm2_control_block;
-    /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */
-    struct AcpiGenericAddress xpm_timer_block;
-    /* 64-bit Extended General Purpose Event 0 Reg Blk address */
-    struct AcpiGenericAddress xgpe0_block;
-    /* 64-bit Extended General Purpose Event 1 Reg Blk address */
-    struct AcpiGenericAddress xgpe1_block;
     /* 64-bit Sleep Control register (ACPI 5.0) */
     struct AcpiGenericAddress sleep_control;
     /* 64-bit Sleep Status register (ACPI 5.0) */
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index f278b3ae89..416aaa56ea 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -303,6 +303,12 @@ typedef struct PCII440FXState PCII440FXState;
 
 #define TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE "igd-passthrough-i440FX"
 
+/*
+ * Reset Control Register: PCI-accessible ISA-Compatible Register at address
+ * 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
+ */
+#define RCR_IOPORT 0xcf9
+
 PCIBus *i440fx_init(const char *host_type, const char *pci_type,
                     PCII440FXState **pi440fx_state, int *piix_devfn,
                     ISABus **isa_bus, qemu_irq *pic,
diff --git a/include/hw/pci/pcie_aer.h b/include/hw/pci/pcie_aer.h
index 526802bd31..729a9439c8 100644
--- a/include/hw/pci/pcie_aer.h
+++ b/include/hw/pci/pcie_aer.h
@@ -100,8 +100,4 @@ void pcie_aer_root_write_config(PCIDevice *dev,
                                 uint32_t addr, uint32_t val, int len,
                                 uint32_t root_cmd_prev);
 
-/* error injection */
-int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err);
-void pcie_aer_msg(PCIDevice *dev, const PCIEAERMsg *msg);
-
 #endif /* QEMU_PCIE_AER_H */
diff --git a/include/hw/s390x/3270-ccw.h b/include/hw/s390x/3270-ccw.h
new file mode 100644
index 0000000000..46bee2533c
--- /dev/null
+++ b/include/hw/s390x/3270-ccw.h
@@ -0,0 +1,53 @@
+/*
+ * Emulated ccw-attached 3270 definitions
+ *
+ * Copyright 2017 IBM Corp.
+ * Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com>
+ *            Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef HW_S390X_3270_CCW_H
+#define HW_S390X_3270_CCW_H
+
+#include "hw/sysbus.h"
+#include "hw/s390x/css.h"
+#include "hw/s390x/ccw-device.h"
+
+#define EMULATED_CCW_3270_CU_TYPE 0x3270
+#define EMULATED_CCW_3270_CHPID_TYPE 0x1a
+
+#define TYPE_EMULATED_CCW_3270 "emulated-ccw-3270"
+
+/* Local Channel Commands */
+#define TC_WRITE   0x01         /* Write */
+#define TC_RDBUF   0x02         /* Read buffer */
+#define TC_EWRITE  0x05         /* Erase write */
+#define TC_READMOD 0x06         /* Read modified */
+#define TC_EWRITEA 0x0d         /* Erase write alternate */
+#define TC_WRITESF 0x11         /* Write structured field */
+
+#define EMULATED_CCW_3270(obj) \
+     OBJECT_CHECK(EmulatedCcw3270Device, (obj), TYPE_EMULATED_CCW_3270)
+#define EMULATED_CCW_3270_CLASS(klass) \
+     OBJECT_CLASS_CHECK(EmulatedCcw3270Class, (klass), TYPE_EMULATED_CCW_3270)
+#define EMULATED_CCW_3270_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(EmulatedCcw3270Class, (obj), TYPE_EMULATED_CCW_3270)
+
+typedef struct EmulatedCcw3270Device {
+    CcwDevice parent_obj;
+} EmulatedCcw3270Device;
+
+typedef struct EmulatedCcw3270Class {
+    CCWDeviceClass parent_class;
+
+    void (*init)(EmulatedCcw3270Device *, Error **);
+    int (*read_payload_3270)(EmulatedCcw3270Device *, uint32_t, uint16_t);
+    int (*write_payload_3270)(EmulatedCcw3270Device *, uint8_t, uint32_t,
+                              uint16_t);
+} EmulatedCcw3270Class;
+
+#endif
diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h
index f1f0d7f07a..e61fa74d9b 100644
--- a/include/hw/s390x/css.h
+++ b/include/hw/s390x/css.h
@@ -28,6 +28,7 @@
 #define MAX_CIWS 62
 
 #define VIRTUAL_CSSID 0xfe
+#define VIRTIO_CCW_CHPID 0   /* used by convention */
 
 typedef struct CIW {
     uint8_t type;
@@ -115,6 +116,7 @@ bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno);
 void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
                       uint16_t devno, SubchDev *sch);
 void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type);
+unsigned int css_find_free_chpid(uint8_t cssid);
 uint16_t css_build_subchannel_id(SubchDev *sch);
 void css_reset(void);
 void css_reset_sch(SubchDev *sch);
diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
index 6ecae00386..7b8a3e4d74 100644
--- a/include/hw/s390x/s390-virtio-ccw.h
+++ b/include/hw/s390x/s390-virtio-ccw.h
@@ -28,6 +28,7 @@ typedef struct S390CcwMachineState {
     /*< public >*/
     bool aes_key_wrap;
     bool dea_key_wrap;
+    uint8_t loadparm[8];
 } S390CcwMachineState;
 
 typedef struct S390CcwMachineClass {
diff --git a/include/hw/virtio/vhost-scsi-common.h b/include/hw/virtio/vhost-scsi-common.h
new file mode 100644
index 0000000000..4553be4bc3
--- /dev/null
+++ b/include/hw/virtio/vhost-scsi-common.h
@@ -0,0 +1,48 @@
+/*
+ * vhost_scsi host device
+ *
+ * Copyright (c) 2016 Nutanix Inc. All rights reserved.
+ *
+ * Author:
+ *  Felipe Franciosi <felipe@nutanix.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.
+ *
+ */
+
+#ifndef VHOST_SCSI_COMMON_H
+#define VHOST_SCSI_COMMON_H
+
+#include "qemu-common.h"
+#include "hw/qdev.h"
+#include "hw/virtio/virtio-scsi.h"
+#include "hw/virtio/vhost.h"
+#include "hw/fw-path-provider.h"
+
+#define TYPE_VHOST_SCSI_COMMON "vhost-scsi-common"
+#define VHOST_SCSI_COMMON(obj) \
+        OBJECT_CHECK(VHostSCSICommon, (obj), TYPE_VHOST_SCSI_COMMON)
+
+typedef struct VHostSCSICommon {
+    VirtIOSCSICommon parent_obj;
+
+    Error *migration_blocker;
+
+    struct vhost_dev dev;
+    const int *feature_bits;
+    int32_t bootindex;
+    int channel;
+    int target;
+    int lun;
+} VHostSCSICommon;
+
+int vhost_scsi_common_start(VHostSCSICommon *vsc);
+void vhost_scsi_common_stop(VHostSCSICommon *vsc);
+char *vhost_scsi_common_get_fw_dev_path(FWPathProvider *p, BusState *bus,
+                                        DeviceState *dev);
+void vhost_scsi_common_set_config(VirtIODevice *vdev, const uint8_t *config);
+uint64_t vhost_scsi_common_get_features(VirtIODevice *vdev, uint64_t features,
+                                        Error **errp);
+
+#endif /* VHOST_SCSI_COMMON_H */
diff --git a/include/hw/virtio/vhost-scsi.h b/include/hw/virtio/vhost-scsi.h
index 9fd63df12e..04658d14f5 100644
--- a/include/hw/virtio/vhost-scsi.h
+++ b/include/hw/virtio/vhost-scsi.h
@@ -18,6 +18,7 @@
 #include "hw/qdev.h"
 #include "hw/virtio/virtio-scsi.h"
 #include "hw/virtio/vhost.h"
+#include "hw/virtio/vhost-scsi-common.h"
 
 enum vhost_scsi_vq_list {
     VHOST_SCSI_VQ_CONTROL = 0,
@@ -30,15 +31,7 @@ enum vhost_scsi_vq_list {
         OBJECT_CHECK(VHostSCSI, (obj), TYPE_VHOST_SCSI)
 
 typedef struct VHostSCSI {
-    VirtIOSCSICommon parent_obj;
-
-    Error *migration_blocker;
-
-    struct vhost_dev dev;
-    int32_t bootindex;
-    int channel;
-    int target;
-    int lun;
+    VHostSCSICommon parent_obj;
 } VHostSCSI;
 
 #endif
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
index 8c8453cf19..eac2013ddd 100644
--- a/include/hw/virtio/virtio-scsi.h
+++ b/include/hw/virtio/virtio-scsi.h
@@ -49,8 +49,10 @@ struct VirtIOSCSIConf {
     uint32_t num_queues;
     uint32_t max_sectors;
     uint32_t cmd_per_lun;
+#ifdef CONFIG_VHOST_SCSI
     char *vhostfd;
     char *wwpn;
+#endif
     uint32_t boot_tpgt;
     IOThread *iothread;
 };
diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h
index 711f8bf7ce..53801f6042 100644
--- a/include/io/channel-socket.h
+++ b/include/io/channel-socket.h
@@ -205,7 +205,7 @@ void qio_channel_socket_dgram_async(QIOChannelSocket *ioc,
  * Get the string representation of the local socket
  * address. A pointer to the allocated address information
  * struct will be returned, which the caller is required to
- * release with a call qapi_free_SocketAddress when no
+ * release with a call qapi_free_SocketAddress() when no
  * longer required.
  *
  * Returns: 0 on success, -1 on error
@@ -222,7 +222,7 @@ qio_channel_socket_get_local_address(QIOChannelSocket *ioc,
  * Get the string representation of the local socket
  * address. A pointer to the allocated address information
  * struct will be returned, which the caller is required to
- * release with a call qapi_free_SocketAddress when no
+ * release with a call qapi_free_SocketAddress() when no
  * longer required.
  *
  * Returns: the socket address struct, or NULL on error
diff --git a/include/migration/cpu.h b/include/migration/cpu.h
index f3d5dfcf61..a40bd3549f 100644
--- a/include/migration/cpu.h
+++ b/include/migration/cpu.h
@@ -18,6 +18,8 @@
     VMSTATE_UINT64_EQUAL_V(_f, _s, _v)
 #define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v)                        \
     VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)
+#define VMSTATE_UINTTL_2DARRAY_V(_f, _s, _n1, _n2, _v)                \
+    VMSTATE_UINT64_2DARRAY_V(_f, _s, _n1, _n2, _v)
 #define VMSTATE_UINTTL_TEST(_f, _s, _t)                               \
     VMSTATE_UINT64_TEST(_f, _s, _t)
 #define vmstate_info_uinttl vmstate_info_uint64
@@ -37,6 +39,8 @@
     VMSTATE_UINT32_EQUAL_V(_f, _s, _v)
 #define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v)                        \
     VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)
+#define VMSTATE_UINTTL_2DARRAY_V(_f, _s, _n1, _n2, _v)                \
+    VMSTATE_UINT32_2DARRAY_V(_f, _s, _n1, _n2, _v)
 #define VMSTATE_UINTTL_TEST(_f, _s, _t)                               \
     VMSTATE_UINT32_TEST(_f, _s, _t)
 #define vmstate_info_uinttl vmstate_info_uint32
@@ -48,5 +52,8 @@
     VMSTATE_UINTTL_EQUAL_V(_f, _s, 0)
 #define VMSTATE_UINTTL_ARRAY(_f, _s, _n)                              \
     VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, 0)
+#define VMSTATE_UINTTL_2DARRAY(_f, _s, _n1, _n2)                      \
+    VMSTATE_UINTTL_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
 
 #endif
diff --git a/include/migration/migration.h b/include/migration/migration.h
index ba1a16cbc1..e29cb0144b 100644
--- a/include/migration/migration.h
+++ b/include/migration/migration.h
@@ -266,7 +266,8 @@ uint64_t xbzrle_mig_pages_cache_miss(void);
 double xbzrle_mig_cache_miss_rate(void);
 
 void ram_handle_compressed(void *host, uint8_t ch, uint64_t size);
-void ram_debug_dump_bitmap(unsigned long *todump, bool expected);
+void ram_debug_dump_bitmap(unsigned long *todump, bool expected,
+                           unsigned long pages);
 /* For outgoing discard bitmap */
 int ram_postcopy_send_discard_bitmap(MigrationState *ms);
 /* For incoming postcopy discard */
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index dad3984c07..f4bf3f1b4e 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -500,6 +500,19 @@ extern const VMStateInfo vmstate_info_qtailq;
     .offset       = vmstate_offset_array(_state, _field, _type, _num),\
 }
 
+#define VMSTATE_STRUCT_2DARRAY_TEST(_field, _state, _n1, _n2, _test, \
+                                    _version, _vmsd, _type) {        \
+    .name         = (stringify(_field)),                             \
+    .num          = (_n1) * (_n2),                                   \
+    .field_exists = (_test),                                         \
+    .version_id   = (_version),                                      \
+    .vmsd         = &(_vmsd),                                        \
+    .size         = sizeof(_type),                                   \
+    .flags        = VMS_STRUCT | VMS_ARRAY,                          \
+    .offset       = vmstate_offset_2darray(_state, _field, _type,    \
+                                           _n1, _n2),                \
+}
+
 #define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
     .name       = (stringify(_field)),                               \
     .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
@@ -747,6 +760,11 @@ extern const VMStateInfo vmstate_info_qtailq;
     VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version,   \
             _vmsd, _type)
 
+#define VMSTATE_STRUCT_2DARRAY(_field, _state, _n1, _n2, _version,    \
+            _vmsd, _type)                                             \
+    VMSTATE_STRUCT_2DARRAY_TEST(_field, _state, _n1, _n2, NULL,       \
+            _version, _vmsd, _type)
+
 #define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) \
     VMSTATE_BUFFER_UNSAFE_INFO_TEST(_field, _state, NULL, _version, _info, \
             _size)
diff --git a/include/qapi/clone-visitor.h b/include/qapi/clone-visitor.h
index b16177e1ee..a4915c7d57 100644
--- a/include/qapi/clone-visitor.h
+++ b/include/qapi/clone-visitor.h
@@ -24,6 +24,9 @@ typedef struct QapiCloneVisitor QapiCloneVisitor;
 
 void *qapi_clone(const void *src, void (*visit_type)(Visitor *, const char *,
                                                      void **, Error **));
+void qapi_clone_members(void *dst, const void *src, size_t sz,
+                        void (*visit_type_members)(Visitor *, void *,
+                                                   Error **));
 
 /*
  * Deep-clone QAPI object @src of the given @type, and return the result.
@@ -36,4 +39,15 @@ void *qapi_clone(const void *src, void (*visit_type)(Visitor *, const char *,
                         (void (*)(Visitor *, const char *, void**,      \
                                   Error **))visit_type_ ## type))
 
+/*
+ * Copy deep clones of @type members from @src to @dst.
+ *
+ * Not usable on QAPI scalars (integers, strings, enums), nor on a
+ * QAPI object that references the 'any' type.
+ */
+#define QAPI_CLONE_MEMBERS(type, dst, src)                              \
+    qapi_clone_members(dst, src, sizeof(type),                          \
+                       (void (*)(Visitor *, void *,                     \
+                                 Error **))visit_type_ ## type ## _members)
+
 #endif
diff --git a/include/qapi/qmp/qdict.h b/include/qapi/qmp/qdict.h
index fe9a4c5c60..188440a6a8 100644
--- a/include/qapi/qmp/qdict.h
+++ b/include/qapi/qmp/qdict.h
@@ -52,6 +52,14 @@ void qdict_destroy_obj(QObject *obj);
 #define qdict_put(qdict, key, obj) \
         qdict_put_obj(qdict, key, QOBJECT(obj))
 
+/* Helpers for int, bool, and string */
+#define qdict_put_int(qdict, key, value) \
+        qdict_put(qdict, key, qint_from_int(value))
+#define qdict_put_bool(qdict, key, value) \
+        qdict_put(qdict, key, qbool_from_bool(value))
+#define qdict_put_str(qdict, key, value) \
+        qdict_put(qdict, key, qstring_from_str(value))
+
 /* High level helpers */
 double qdict_get_double(const QDict *qdict, const char *key);
 int64_t qdict_get_int(const QDict *qdict, const char *key);
diff --git a/include/qapi/qmp/qlist.h b/include/qapi/qmp/qlist.h
index a84117ecb1..5dc4ed9616 100644
--- a/include/qapi/qmp/qlist.h
+++ b/include/qapi/qmp/qlist.h
@@ -29,6 +29,14 @@ typedef struct QList {
 #define qlist_append(qlist, obj) \
         qlist_append_obj(qlist, QOBJECT(obj))
 
+/* Helpers for int, bool, and string */
+#define qlist_append_int(qlist, value) \
+        qlist_append(qlist, qint_from_int(value))
+#define qlist_append_bool(qlist, value) \
+        qlist_append(qlist, qbool_from_bool(value))
+#define qlist_append_str(qlist, value) \
+        qlist_append(qlist, qstring_from_str(value))
+
 #define QLIST_FOREACH_ENTRY(qlist, var)             \
         for ((var) = ((qlist)->head.tqh_first);     \
             (var);                                  \
diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h
index 1a1b62012b..b0e233df76 100644
--- a/include/qapi/visitor.h
+++ b/include/qapi/visitor.h
@@ -63,8 +63,10 @@
  * The @name parameter of visit_type_FOO() describes the relation
  * between this QAPI value and its parent container.  When visiting
  * the root of a tree, @name is ignored; when visiting a member of an
- * object, @name is the key associated with the value; and when
- * visiting a member of a list, @name is NULL.
+ * object, @name is the key associated with the value; when visiting a
+ * member of a list, @name is NULL; and when visiting the member of an
+ * alternate, @name should equal the name used for visiting the
+ * alternate.
  *
  * The visit_type_FOO() functions expect a non-null @obj argument;
  * they allocate *@obj during input visits, leave it unchanged on
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index af285321b8..5c326db232 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -34,7 +34,7 @@ typedef void NonBlockingConnectHandler(int fd, Error *err, void *opaque);
 
 int inet_ai_family_from_address(InetSocketAddress *addr,
                                 Error **errp);
-InetSocketAddress *inet_parse(const char *str, Error **errp);
+int inet_parse(InetSocketAddress *addr, const char *str, Error **errp);
 int inet_connect(const char *str, Error **errp);
 int inet_connect_saddr(InetSocketAddress *saddr,
                        NonBlockingConnectHandler *callback, void *opaque,
@@ -65,7 +65,7 @@ int socket_init(void);
  * Get the string representation of the socket
  * address. A pointer to the allocated address information
  * struct will be returned, which the caller is required to
- * release with a call qapi_free_SocketAddress when no
+ * release with a call qapi_free_SocketAddress() when no
  * longer required.
  *
  * Returns: the socket address struct, or NULL on error
@@ -83,7 +83,7 @@ socket_sockaddr_to_address(struct sockaddr_storage *sa,
  * Get the string representation of the local socket
  * address. A pointer to the allocated address information
  * struct will be returned, which the caller is required to
- * release with a call qapi_free_SocketAddress when no
+ * release with a call qapi_free_SocketAddress() when no
  * longer required.
  *
  * Returns: the socket address struct, or NULL on error
@@ -98,7 +98,7 @@ SocketAddress *socket_local_address(int fd, Error **errp);
  * Get the string representation of the remote socket
  * address. A pointer to the allocated address information
  * struct will be returned, which the caller is required to
- * release with a call qapi_free_SocketAddress when no
+ * release with a call qapi_free_SocketAddress() when no
  * longer required.
  *
  * Returns: the socket address struct, or NULL on error
@@ -121,14 +121,14 @@ SocketAddress *socket_remote_address(int fd, Error **errp);
 char *socket_address_to_string(struct SocketAddress *addr, Error **errp);
 
 /**
- * socket_address_crumple:
- * @addr_flat: the socket address to crumple
+ * socket_address_flatten:
+ * @addr: the socket address to flatten
  *
- * Convert SocketAddressFlat to SocketAddress.  Caller is responsible
+ * Convert SocketAddressLegacy to SocketAddress.  Caller is responsible
  * for freeing with qapi_free_SocketAddress().
  *
  * Returns: the argument converted to SocketAddress.
  */
-SocketAddress *socket_address_crumple(SocketAddressFlat *addr_flat);
+SocketAddress *socket_address_flatten(SocketAddressLegacy *addr);
 
 #endif /* QEMU_SOCKETS_H */
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 450881d42c..fffc0f40d4 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -7,6 +7,14 @@
 #include "qemu/bitmap.h"
 #include "qom/object.h"
 
+#define IAC_EOR 239
+#define IAC_SE 240
+#define IAC_NOP 241
+#define IAC_BREAK 243
+#define IAC_IP 244
+#define IAC_SB 250
+#define IAC 255
+
 /* character device */
 
 typedef enum {
@@ -93,9 +101,8 @@ struct Chardev {
     char *filename;
     int logfd;
     int be_open;
-    guint fd_in_tag;
+    GSource *gsource;
     DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
-    QTAILQ_ENTRY(Chardev) next;
 };
 
 /**
@@ -171,14 +178,6 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp);
 Chardev *qemu_chr_new_noreplay(const char *label, const char *filename);
 
 /**
- * @qemu_chr_delete:
- *
- * Destroy a character backend and remove it from the list of
- * identified character backends.
- */
-void qemu_chr_delete(Chardev *chr);
-
-/**
  * @qemu_chr_fe_set_echo:
  *
  * Ask the backend to override its normal echo setting.  This only really
@@ -427,7 +426,6 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
  */
 void qemu_chr_fe_take_focus(CharBackend *b);
 
-void qemu_chr_be_generic_open(Chardev *s);
 void qemu_chr_fe_accept_input(CharBackend *be);
 int qemu_chr_add_client(Chardev *s, int fd);
 Chardev *qemu_chr_find(const char *name);
diff --git a/include/sysemu/dump.h b/include/sysemu/dump.h
index ef931be469..2672a15f8b 100644
--- a/include/sysemu/dump.h
+++ b/include/sysemu/dump.h
@@ -157,6 +157,7 @@ typedef struct DumpState {
     uint32_t sh_info;
     bool have_section;
     bool resume;
+    bool detached;
     ssize_t note_size;
     hwaddr memory_offset;
     int fd;
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 16175f7295..15656b7c36 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -75,11 +75,8 @@ void qemu_remove_exit_notifier(Notifier *notify);
 void qemu_add_machine_init_done_notifier(Notifier *notify);
 void qemu_remove_machine_init_done_notifier(Notifier *notify);
 
-void hmp_savevm(Monitor *mon, const QDict *qdict);
-int save_vmstate(Monitor *mon, const char *name);
+int save_vmstate(const char *name);
 int load_vmstate(const char *name);
-void hmp_delvm(Monitor *mon, const QDict *qdict);
-void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
 
 void qemu_announce_self(void);
 
diff --git a/io/dns-resolver.c b/io/dns-resolver.c
index 759d1b40d7..57a8896cbb 100644
--- a/io/dns-resolver.c
+++ b/io/dns-resolver.c
@@ -51,7 +51,7 @@ static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
                                              Error **errp)
 {
     struct addrinfo ai, *res, *e;
-    InetSocketAddress *iaddr = addr->u.inet.data;
+    InetSocketAddress *iaddr = &addr->u.inet;
     char port[33];
     char uaddr[INET6_ADDRSTRLEN + 1];
     char uport[33];
@@ -102,15 +102,14 @@ static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
     /* create socket + bind */
     for (i = 0, e = res; e != NULL; i++, e = e->ai_next) {
         SocketAddress *newaddr = g_new0(SocketAddress, 1);
-        InetSocketAddress *newiaddr = g_new0(InetSocketAddress, 1);
-        newaddr->u.inet.data = newiaddr;
-        newaddr->type = SOCKET_ADDRESS_KIND_INET;
+
+        newaddr->type = SOCKET_ADDRESS_TYPE_INET;
 
         getnameinfo((struct sockaddr *)e->ai_addr, e->ai_addrlen,
                     uaddr, INET6_ADDRSTRLEN, uport, 32,
                     NI_NUMERICHOST | NI_NUMERICSERV);
 
-        *newiaddr = (InetSocketAddress){
+        newaddr->u.inet = (InetSocketAddress){
             .host = g_strdup(uaddr),
             .port = g_strdup(uport),
             .has_numeric = true,
@@ -149,16 +148,16 @@ int qio_dns_resolver_lookup_sync(QIODNSResolver *resolver,
                                  Error **errp)
 {
     switch (addr->type) {
-    case SOCKET_ADDRESS_KIND_INET:
+    case SOCKET_ADDRESS_TYPE_INET:
         return qio_dns_resolver_lookup_sync_inet(resolver,
                                                  addr,
                                                  naddrs,
                                                  addrs,
                                                  errp);
 
-    case SOCKET_ADDRESS_KIND_UNIX:
-    case SOCKET_ADDRESS_KIND_VSOCK:
-    case SOCKET_ADDRESS_KIND_FD:
+    case SOCKET_ADDRESS_TYPE_UNIX:
+    case SOCKET_ADDRESS_TYPE_VSOCK:
+    case SOCKET_ADDRESS_TYPE_FD:
         return qio_dns_resolver_lookup_sync_nop(resolver,
                                                 addr,
                                                 naddrs,
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index f520d7723c..ce77317e09 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1052,7 +1052,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
     int i;
 
     for (i = 0; i < 32; i++) {
-        (*regs)[i] = tswapreg(env->gpr[i]);
+        (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
     }
     (*regs)[32] = tswapreg(env->pc);
     (*regs)[33] = tswapreg(cpu_get_sr(env));
diff --git a/linux-user/main.c b/linux-user/main.c
index 5f20769cb9..ad03c9e8b2 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2590,17 +2590,17 @@ void cpu_loop(CPUOpenRISCState *env)
         case EXCP_SYSCALL:
             env->pc += 4;   /* 0xc00; */
             ret = do_syscall(env,
-                             env->gpr[11], /* return value       */
-                             env->gpr[3],  /* r3 - r7 are params */
-                             env->gpr[4],
-                             env->gpr[5],
-                             env->gpr[6],
-                             env->gpr[7],
-                             env->gpr[8], 0, 0);
+                             cpu_get_gpr(env, 11), /* return value       */
+                             cpu_get_gpr(env, 3),  /* r3 - r7 are params */
+                             cpu_get_gpr(env, 4),
+                             cpu_get_gpr(env, 5),
+                             cpu_get_gpr(env, 6),
+                             cpu_get_gpr(env, 7),
+                             cpu_get_gpr(env, 8), 0, 0);
             if (ret == -TARGET_ERESTARTSYS) {
                 env->pc -= 4;
             } else if (ret != -TARGET_QEMU_ESIGRETURN) {
-                env->gpr[11] = ret;
+                cpu_set_gpr(env, 11, ret);
             }
             break;
         case EXCP_DPF:
@@ -4762,7 +4762,7 @@ int main(int argc, char **argv, char **envp)
         int i;
 
         for (i = 0; i < 32; i++) {
-            env->gpr[i] = regs->gpr[i];
+            cpu_set_gpr(env, i, regs->gpr[i]);
         }
         env->pc = regs->pc;
         cpu_set_sr(env, regs->sr);
diff --git a/linux-user/openrisc/target_cpu.h b/linux-user/openrisc/target_cpu.h
index f283d96a93..606ad6f695 100644
--- a/linux-user/openrisc/target_cpu.h
+++ b/linux-user/openrisc/target_cpu.h
@@ -23,14 +23,14 @@
 static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp)
 {
     if (newsp) {
-        env->gpr[1] = newsp;
+        cpu_set_gpr(env, 1, newsp);
     }
-    env->gpr[11] = 0;
+    cpu_set_gpr(env, 11, 0);
 }
 
 static inline void cpu_set_tls(CPUOpenRISCState *env, target_ulong newtls)
 {
-    env->gpr[10] = newtls;
+    cpu_set_gpr(env, 10, newtls);
 }
 
 #endif
diff --git a/linux-user/openrisc/target_signal.h b/linux-user/openrisc/target_signal.h
index 9f2c493f79..95a733e15a 100644
--- a/linux-user/openrisc/target_signal.h
+++ b/linux-user/openrisc/target_signal.h
@@ -20,7 +20,7 @@ typedef struct target_sigaltstack {
 
 static inline abi_ulong get_sp_from_cpustate(CPUOpenRISCState *state)
 {
-    return state->gpr[1];
+    return cpu_get_gpr(state, 1);
 }
 
 
diff --git a/linux-user/signal.c b/linux-user/signal.c
index a67db04e1a..3d18d1b3ee 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -4411,7 +4411,7 @@ static void setup_sigcontext(struct target_sigcontext *sc,
                              CPUOpenRISCState *regs,
                              unsigned long mask)
 {
-    unsigned long usp = regs->gpr[1];
+    unsigned long usp = cpu_get_gpr(regs, 1);
 
     /* copy the regs. they are first in sc so we can use sc directly */
 
@@ -4436,7 +4436,7 @@ static inline abi_ulong get_sigframe(struct target_sigaction *ka,
                                      CPUOpenRISCState *regs,
                                      size_t frame_size)
 {
-    unsigned long sp = regs->gpr[1];
+    unsigned long sp = cpu_get_gpr(regs, 1);
     int onsigstack = on_sig_stack(sp);
 
     /* redzone */
@@ -4489,7 +4489,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
     __put_user(0, &frame->uc.tuc_link);
     __put_user(target_sigaltstack_used.ss_sp,
                &frame->uc.tuc_stack.ss_sp);
-    __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
+    __put_user(sas_ss_flags(cpu_get_gpr(env, 1)),
+               &frame->uc.tuc_stack.ss_flags);
     __put_user(target_sigaltstack_used.ss_size,
                &frame->uc.tuc_stack.ss_size);
     setup_sigcontext(&frame->sc, env, set->sig[0]);
@@ -4512,13 +4513,13 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
 
     /* Set up registers for signal handler */
     env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
-    env->gpr[9] = (unsigned long)return_ip;     /* what we enter LATER */
-    env->gpr[3] = (unsigned long)sig;           /* arg 1: signo */
-    env->gpr[4] = (unsigned long)&frame->info;  /* arg 2: (siginfo_t*) */
-    env->gpr[5] = (unsigned long)&frame->uc;    /* arg 3: ucontext */
+    cpu_set_gpr(env, 9, (unsigned long)return_ip);     /* what we enter LATER */
+    cpu_set_gpr(env, 3, (unsigned long)sig);           /* arg 1: signo */
+    cpu_set_gpr(env, 4, (unsigned long)&frame->info);  /* arg 2: (siginfo_t*) */
+    cpu_set_gpr(env, 5, (unsigned long)&frame->uc);    /* arg 3: ucontext */
 
     /* actually move the usp to reflect the stacked frame */
-    env->gpr[1] = (unsigned long)frame;
+    cpu_set_gpr(env, 1, (unsigned long)frame);
 
     return;
 
diff --git a/migration/exec.c b/migration/exec.c
index 9157721dfe..aba9089466 100644
--- a/migration/exec.c
+++ b/migration/exec.c
@@ -32,7 +32,7 @@ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error
 
     trace_migration_exec_outgoing(command);
     ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
-                                                    O_WRONLY,
+                                                    O_RDWR,
                                                     errp));
     if (!ioc) {
         return;
@@ -59,7 +59,7 @@ void exec_start_incoming_migration(const char *command, Error **errp)
 
     trace_migration_exec_incoming(command);
     ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
-                                                    O_RDONLY,
+                                                    O_RDWR,
                                                     errp));
     if (!ioc) {
         return;
diff --git a/migration/migration.c b/migration/migration.c
index 353f2728cf..799952ce99 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -26,7 +26,7 @@
 #include "qemu/sockets.h"
 #include "qemu/rcu.h"
 #include "migration/block.h"
-#include "migration/postcopy-ram.h"
+#include "postcopy-ram.h"
 #include "qemu/thread.h"
 #include "qmp-commands.h"
 #include "trace.h"
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index 85fd8d72b3..cdadaf6578 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -20,7 +20,7 @@
 
 #include "qemu-common.h"
 #include "migration/migration.h"
-#include "migration/postcopy-ram.h"
+#include "postcopy-ram.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/balloon.h"
 #include "qemu/error-report.h"
@@ -33,7 +33,6 @@
 
 struct PostcopyDiscardState {
     const char *ramblock_name;
-    uint64_t offset; /* Bitmap entry for the 1st bit of this RAMBlock */
     uint16_t cur_entry;
     /*
      * Start and length of a discard range (bytes)
@@ -717,14 +716,12 @@ void *postcopy_get_tmp_page(MigrationIncomingState *mis)
  * returns: a new PDS.
  */
 PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms,
-                                                 unsigned long offset,
                                                  const char *name)
 {
     PostcopyDiscardState *res = g_malloc0(sizeof(PostcopyDiscardState));
 
     if (res) {
         res->ramblock_name = name;
-        res->offset = offset;
     }
 
     return res;
@@ -745,7 +742,7 @@ void postcopy_discard_send_range(MigrationState *ms, PostcopyDiscardState *pds,
 {
     size_t tp_size = qemu_target_page_size();
     /* Convert to byte offsets within the RAM block */
-    pds->start_list[pds->cur_entry] = (start - pds->offset) * tp_size;
+    pds->start_list[pds->cur_entry] = start  * tp_size;
     pds->length_list[pds->cur_entry] = length * tp_size;
     trace_postcopy_discard_send_range(pds->ramblock_name, start, length);
     pds->cur_entry++;
diff --git a/include/migration/postcopy-ram.h b/migration/postcopy-ram.h
index 8e036b95a2..4c25f03be2 100644
--- a/include/migration/postcopy-ram.h
+++ b/migration/postcopy-ram.h
@@ -43,12 +43,9 @@ int postcopy_ram_prepare_discard(MigrationIncomingState *mis);
 
 /*
  * Called at the start of each RAMBlock by the bitmap code.
- * 'offset' is the bitmap offset of the named RAMBlock in the migration
- * bitmap.
  * Returns a new PDS
  */
 PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms,
-                                                 unsigned long offset,
                                                  const char *name);
 
 /*
diff --git a/migration/ram.c b/migration/ram.c
index f48664ec62..293d27ce83 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -36,7 +36,7 @@
 #include "qemu/timer.h"
 #include "qemu/main-loop.h"
 #include "migration/migration.h"
-#include "migration/postcopy-ram.h"
+#include "postcopy-ram.h"
 #include "exec/address-spaces.h"
 #include "migration/page_cache.h"
 #include "qemu/error-report.h"
@@ -138,19 +138,6 @@ out:
     return ret;
 }
 
-struct RAMBitmap {
-    struct rcu_head rcu;
-    /* Main migration bitmap */
-    unsigned long *bmap;
-    /* bitmap of pages that haven't been sent even once
-     * only maintained and used in postcopy at the moment
-     * where it's used to send the dirtymap at the start
-     * of the postcopy phase
-     */
-    unsigned long *unsentmap;
-};
-typedef struct RAMBitmap RAMBitmap;
-
 /*
  * An outstanding page request, on the source, having been received
  * and queued
@@ -220,8 +207,6 @@ struct RAMState {
     uint64_t postcopy_requests;
     /* protects modification of the bitmap */
     QemuMutex bitmap_mutex;
-    /* Ram Bitmap protected by RCU */
-    RAMBitmap *ram_bitmap;
     /* The RAMBlock used in the last src_page_requests */
     RAMBlock *last_req_rb;
     /* Queue of outstanding page requests from the destination */
@@ -614,22 +599,17 @@ static inline
 unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb,
                                           unsigned long start)
 {
-    unsigned long base = rb->offset >> TARGET_PAGE_BITS;
-    unsigned long nr = base + start;
-    uint64_t rb_size = rb->used_length;
-    unsigned long size = base + (rb_size >> TARGET_PAGE_BITS);
-    unsigned long *bitmap;
-
+    unsigned long size = rb->used_length >> TARGET_PAGE_BITS;
+    unsigned long *bitmap = rb->bmap;
     unsigned long next;
 
-    bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
-    if (rs->ram_bulk_stage && nr > base) {
-        next = nr + 1;
+    if (rs->ram_bulk_stage && start > 0) {
+        next = start + 1;
     } else {
-        next = find_next_bit(bitmap, size, nr);
+        next = find_next_bit(bitmap, size, start);
     }
 
-    return next - base;
+    return next;
 }
 
 static inline bool migration_bitmap_clear_dirty(RAMState *rs,
@@ -637,10 +617,8 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
                                                 unsigned long page)
 {
     bool ret;
-    unsigned long *bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
-    unsigned long nr = (rb->offset >> TARGET_PAGE_BITS) + page;
 
-    ret = test_and_clear_bit(nr, bitmap);
+    ret = test_and_clear_bit(page, rb->bmap);
 
     if (ret) {
         rs->migration_dirty_pages--;
@@ -651,10 +629,8 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
 static void migration_bitmap_sync_range(RAMState *rs, RAMBlock *rb,
                                         ram_addr_t start, ram_addr_t length)
 {
-    unsigned long *bitmap;
-    bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
     rs->migration_dirty_pages +=
-        cpu_physical_memory_sync_dirty_bitmap(bitmap, rb, start, length,
+        cpu_physical_memory_sync_dirty_bitmap(rb, start, length,
                                               &rs->num_dirty_pages_period);
 }
 
@@ -812,6 +788,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage)
     ram_addr_t offset = pss->page << TARGET_PAGE_BITS;
 
     p = block->host + offset;
+    trace_ram_save_page(block->idstr, (uint64_t)offset, p);
 
     /* In doubt sent page as normal */
     bytes_xmit = 0;
@@ -1153,17 +1130,13 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss)
          * search already sent it.
          */
         if (block) {
-            unsigned long *bitmap;
             unsigned long page;
 
-            bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
-            page = (block->offset + offset) >> TARGET_PAGE_BITS;
-            dirty = test_bit(page, bitmap);
+            page = offset >> TARGET_PAGE_BITS;
+            dirty = test_bit(page, block->bmap);
             if (!dirty) {
                 trace_get_queued_page_not_dirty(block->idstr, (uint64_t)offset,
-                    page,
-                    test_bit(page,
-                             atomic_rcu_read(&rs->ram_bitmap)->unsentmap));
+                       page, test_bit(page, block->unsentmap));
             } else {
                 trace_get_queued_page(block->idstr, (uint64_t)offset, page);
             }
@@ -1301,16 +1274,13 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
 
     /* Check the pages is dirty and if it is send it */
     if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) {
-        unsigned long *unsentmap;
         /*
          * If xbzrle is on, stop using the data compression after first
          * round of migration even if compression is enabled. In theory,
          * xbzrle can do better than compression.
          */
-        unsigned long page =
-            (pss->block->offset >> TARGET_PAGE_BITS) + pss->page;
-        if (migrate_use_compression()
-            && (rs->ram_bulk_stage || !migrate_use_xbzrle())) {
+        if (migrate_use_compression() &&
+            (rs->ram_bulk_stage || !migrate_use_xbzrle())) {
             res = ram_save_compressed_page(rs, pss, last_stage);
         } else {
             res = ram_save_page(rs, pss, last_stage);
@@ -1319,9 +1289,8 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
         if (res < 0) {
             return res;
         }
-        unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap;
-        if (unsentmap) {
-            clear_bit(page, unsentmap);
+        if (pss->block->unsentmap) {
+            clear_bit(pss->page, pss->block->unsentmap);
         }
     }
 
@@ -1451,25 +1420,20 @@ void free_xbzrle_decoded_buf(void)
     xbzrle_decoded_buf = NULL;
 }
 
-static void migration_bitmap_free(RAMBitmap *bmap)
-{
-    g_free(bmap->bmap);
-    g_free(bmap->unsentmap);
-    g_free(bmap);
-}
-
 static void ram_migration_cleanup(void *opaque)
 {
-    RAMState *rs = opaque;
+    RAMBlock *block;
 
     /* caller have hold iothread lock or is in a bh, so there is
      * no writing race against this migration_bitmap
      */
-    RAMBitmap *bitmap = rs->ram_bitmap;
-    atomic_rcu_set(&rs->ram_bitmap, NULL);
-    if (bitmap) {
-        memory_global_dirty_log_stop();
-        call_rcu(bitmap, migration_bitmap_free, rcu);
+    memory_global_dirty_log_stop();
+
+    QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
+        g_free(block->bmap);
+        block->bmap = NULL;
+        g_free(block->unsentmap);
+        block->unsentmap = NULL;
     }
 
     XBZRLE_cache_lock();
@@ -1501,27 +1465,22 @@ static void ram_state_reset(RAMState *rs)
  * of; it won't bother printing lines that are all this value.
  * If 'todump' is null the migration bitmap is dumped.
  */
-void ram_debug_dump_bitmap(unsigned long *todump, bool expected)
+void ram_debug_dump_bitmap(unsigned long *todump, bool expected,
+                           unsigned long pages)
 {
-    unsigned long ram_pages = last_ram_page();
-    RAMState *rs = &ram_state;
     int64_t cur;
     int64_t linelen = 128;
     char linebuf[129];
 
-    if (!todump) {
-        todump = atomic_rcu_read(&rs->ram_bitmap)->bmap;
-    }
-
-    for (cur = 0; cur < ram_pages; cur += linelen) {
+    for (cur = 0; cur < pages; cur += linelen) {
         int64_t curb;
         bool found = false;
         /*
          * Last line; catch the case where the line length
          * is longer than remaining ram
          */
-        if (cur + linelen > ram_pages) {
-            linelen = ram_pages - cur;
+        if (cur + linelen > pages) {
+            linelen = pages - cur;
         }
         for (curb = 0; curb < linelen; curb++) {
             bool thisbit = test_bit(cur + curb, todump);
@@ -1539,14 +1498,12 @@ void ram_debug_dump_bitmap(unsigned long *todump, bool expected)
 
 void ram_postcopy_migrated_memory_release(MigrationState *ms)
 {
-    RAMState *rs = &ram_state;
     struct RAMBlock *block;
-    unsigned long *bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
 
     QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
-        unsigned long first = block->offset >> TARGET_PAGE_BITS;
-        unsigned long range = first + (block->used_length >> TARGET_PAGE_BITS);
-        unsigned long run_start = find_next_zero_bit(bitmap, range, first);
+        unsigned long *bitmap = block->bmap;
+        unsigned long range = block->used_length >> TARGET_PAGE_BITS;
+        unsigned long run_start = find_next_zero_bit(bitmap, range, 0);
 
         while (run_start < range) {
             unsigned long run_end = find_next_bit(bitmap, range, run_start + 1);
@@ -1573,16 +1530,13 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms)
  */
 static int postcopy_send_discard_bm_ram(MigrationState *ms,
                                         PostcopyDiscardState *pds,
-                                        unsigned long start,
-                                        unsigned long length)
+                                        RAMBlock *block)
 {
-    RAMState *rs = &ram_state;
-    unsigned long end = start + length; /* one after the end */
+    unsigned long end = block->used_length >> TARGET_PAGE_BITS;
     unsigned long current;
-    unsigned long *unsentmap;
+    unsigned long *unsentmap = block->unsentmap;
 
-    unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap;
-    for (current = start; current < end; ) {
+    for (current = 0; current < end; ) {
         unsigned long one = find_next_bit(unsentmap, end, current);
 
         if (one <= end) {
@@ -1625,18 +1579,15 @@ static int postcopy_each_ram_send_discard(MigrationState *ms)
     int ret;
 
     QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
-        unsigned long first = block->offset >> TARGET_PAGE_BITS;
-        PostcopyDiscardState *pds = postcopy_discard_send_init(ms,
-                                                               first,
-                                                               block->idstr);
+        PostcopyDiscardState *pds =
+            postcopy_discard_send_init(ms, block->idstr);
 
         /*
          * Postcopy sends chunks of bitmap over the wire, but it
          * just needs indexes at this point, avoids it having
          * target page specific code.
          */
-        ret = postcopy_send_discard_bm_ram(ms, pds, first,
-                                    block->used_length >> TARGET_PAGE_BITS);
+        ret = postcopy_send_discard_bm_ram(ms, pds, block);
         postcopy_discard_send_finish(ms, pds);
         if (ret) {
             return ret;
@@ -1667,12 +1618,10 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
                                           PostcopyDiscardState *pds)
 {
     RAMState *rs = &ram_state;
-    unsigned long *bitmap;
-    unsigned long *unsentmap;
+    unsigned long *bitmap = block->bmap;
+    unsigned long *unsentmap = block->unsentmap;
     unsigned int host_ratio = block->page_size / TARGET_PAGE_SIZE;
-    unsigned long first = block->offset >> TARGET_PAGE_BITS;
-    unsigned long len = block->used_length >> TARGET_PAGE_BITS;
-    unsigned long last = first + (len - 1);
+    unsigned long pages = block->used_length >> TARGET_PAGE_BITS;
     unsigned long run_start;
 
     if (block->page_size == TARGET_PAGE_SIZE) {
@@ -1680,18 +1629,15 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
         return;
     }
 
-    bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
-    unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap;
-
     if (unsent_pass) {
         /* Find a sent page */
-        run_start = find_next_zero_bit(unsentmap, last + 1, first);
+        run_start = find_next_zero_bit(unsentmap, pages, 0);
     } else {
         /* Find a dirty page */
-        run_start = find_next_bit(bitmap, last + 1, first);
+        run_start = find_next_bit(bitmap, pages, 0);
     }
 
-    while (run_start <= last) {
+    while (run_start < pages) {
         bool do_fixup = false;
         unsigned long fixup_start_addr;
         unsigned long host_offset;
@@ -1711,9 +1657,9 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
             /* Find the end of this run */
             unsigned long run_end;
             if (unsent_pass) {
-                run_end = find_next_bit(unsentmap, last + 1, run_start + 1);
+                run_end = find_next_bit(unsentmap, pages, run_start + 1);
             } else {
-                run_end = find_next_zero_bit(bitmap, last + 1, run_start + 1);
+                run_end = find_next_zero_bit(bitmap, pages, run_start + 1);
             }
             /*
              * If the end isn't at the start of a host page, then the
@@ -1770,11 +1716,10 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
 
         if (unsent_pass) {
             /* Find the next sent page for the next iteration */
-            run_start = find_next_zero_bit(unsentmap, last + 1,
-                                           run_start);
+            run_start = find_next_zero_bit(unsentmap, pages, run_start);
         } else {
             /* Find the next dirty page for the next iteration */
-            run_start = find_next_bit(bitmap, last + 1, run_start);
+            run_start = find_next_bit(bitmap, pages, run_start);
         }
     }
 }
@@ -1791,34 +1736,22 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
  * Returns zero on success
  *
  * @ms: current migration state
+ * @block: block we want to work with
  */
-static int postcopy_chunk_hostpages(MigrationState *ms)
+static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block)
 {
-    RAMState *rs = &ram_state;
-    struct RAMBlock *block;
-
-    /* Easiest way to make sure we don't resume in the middle of a host-page */
-    rs->last_seen_block = NULL;
-    rs->last_sent_block = NULL;
-    rs->last_page = 0;
-
-    QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
-        unsigned long first = block->offset >> TARGET_PAGE_BITS;
-
-        PostcopyDiscardState *pds =
-                         postcopy_discard_send_init(ms, first, block->idstr);
-
-        /* First pass: Discard all partially sent host pages */
-        postcopy_chunk_hostpages_pass(ms, true, block, pds);
-        /*
-         * Second pass: Ensure that all partially dirty host pages are made
-         * fully dirty.
-         */
-        postcopy_chunk_hostpages_pass(ms, false, block, pds);
+    PostcopyDiscardState *pds =
+        postcopy_discard_send_init(ms, block->idstr);
 
-        postcopy_discard_send_finish(ms, pds);
-    } /* ram_list loop */
+    /* First pass: Discard all partially sent host pages */
+    postcopy_chunk_hostpages_pass(ms, true, block, pds);
+    /*
+     * Second pass: Ensure that all partially dirty host pages are made
+     * fully dirty.
+     */
+    postcopy_chunk_hostpages_pass(ms, false, block, pds);
 
+    postcopy_discard_send_finish(ms, pds);
     return 0;
 }
 
@@ -1840,43 +1773,49 @@ static int postcopy_chunk_hostpages(MigrationState *ms)
 int ram_postcopy_send_discard_bitmap(MigrationState *ms)
 {
     RAMState *rs = &ram_state;
+    RAMBlock *block;
     int ret;
-    unsigned long *bitmap, *unsentmap;
 
     rcu_read_lock();
 
     /* This should be our last sync, the src is now paused */
     migration_bitmap_sync(rs);
 
-    unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap;
-    if (!unsentmap) {
-        /* We don't have a safe way to resize the sentmap, so
-         * if the bitmap was resized it will be NULL at this
-         * point.
-         */
-        error_report("migration ram resized during precopy phase");
-        rcu_read_unlock();
-        return -EINVAL;
-    }
-
-    /* Deal with TPS != HPS and huge pages */
-    ret = postcopy_chunk_hostpages(ms);
-    if (ret) {
-        rcu_read_unlock();
-        return ret;
-    }
-
-    /*
-     * Update the unsentmap to be unsentmap = unsentmap | dirty
-     */
-    bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
-    bitmap_or(unsentmap, unsentmap, bitmap, last_ram_page());
+    /* Easiest way to make sure we don't resume in the middle of a host-page */
+    rs->last_seen_block = NULL;
+    rs->last_sent_block = NULL;
+    rs->last_page = 0;
 
+    QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
+        unsigned long pages = block->used_length >> TARGET_PAGE_BITS;
+        unsigned long *bitmap = block->bmap;
+        unsigned long *unsentmap = block->unsentmap;
+
+        if (!unsentmap) {
+            /* We don't have a safe way to resize the sentmap, so
+             * if the bitmap was resized it will be NULL at this
+             * point.
+             */
+            error_report("migration ram resized during precopy phase");
+            rcu_read_unlock();
+            return -EINVAL;
+        }
+        /* Deal with TPS != HPS and huge pages */
+        ret = postcopy_chunk_hostpages(ms, block);
+        if (ret) {
+            rcu_read_unlock();
+            return ret;
+        }
 
-    trace_ram_postcopy_send_discard_bitmap();
+        /*
+         * Update the unsentmap to be unsentmap = unsentmap | dirty
+         */
+        bitmap_or(unsentmap, unsentmap, bitmap, pages);
 #ifdef DEBUG_POSTCOPY
-    ram_debug_dump_bitmap(unsentmap, true);
+        ram_debug_dump_bitmap(unsentmap, true, pages);
 #endif
+    }
+    trace_ram_postcopy_send_discard_bitmap();
 
     ret = postcopy_each_ram_send_discard(ms);
     rcu_read_unlock();
@@ -1918,8 +1857,6 @@ err:
 
 static int ram_state_init(RAMState *rs)
 {
-    unsigned long ram_bitmap_pages;
-
     memset(rs, 0, sizeof(*rs));
     qemu_mutex_init(&rs->bitmap_mutex);
     qemu_mutex_init(&rs->src_page_req_mutex);
@@ -1961,16 +1898,19 @@ static int ram_state_init(RAMState *rs)
     rcu_read_lock();
     ram_state_reset(rs);
 
-    rs->ram_bitmap = g_new0(RAMBitmap, 1);
     /* Skip setting bitmap if there is no RAM */
     if (ram_bytes_total()) {
-        ram_bitmap_pages = last_ram_page();
-        rs->ram_bitmap->bmap = bitmap_new(ram_bitmap_pages);
-        bitmap_set(rs->ram_bitmap->bmap, 0, ram_bitmap_pages);
+        RAMBlock *block;
 
-        if (migrate_postcopy_ram()) {
-            rs->ram_bitmap->unsentmap = bitmap_new(ram_bitmap_pages);
-            bitmap_set(rs->ram_bitmap->unsentmap, 0, ram_bitmap_pages);
+        QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
+            unsigned long pages = block->max_length >> TARGET_PAGE_BITS;
+
+            block->bmap = bitmap_new(pages);
+            bitmap_set(block->bmap, 0, pages);
+            if (migrate_postcopy_ram()) {
+                block->unsentmap = bitmap_new(pages);
+                bitmap_set(block->unsentmap, 0, pages);
+            }
         }
     }
 
@@ -2611,6 +2551,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
                 ret = -EINVAL;
                 break;
             }
+            trace_ram_load_loop(block->idstr, (uint64_t)addr, flags, host);
         }
 
         switch (flags & ~RAM_SAVE_FLAG_CONTINUE) {
diff --git a/migration/rdma.c b/migration/rdma.c
index fe0a4b5a83..7eaaf96479 100644
--- a/migration/rdma.c
+++ b/migration/rdma.c
@@ -2506,8 +2506,8 @@ static void *qemu_rdma_data_init(const char *host_port, Error **errp)
         rdma->current_index = -1;
         rdma->current_chunk = -1;
 
-        addr = inet_parse(host_port, NULL);
-        if (addr != NULL) {
+        addr = g_new(InetSocketAddress, 1);
+        if (!inet_parse(addr, host_port, NULL)) {
             rdma->port = atoi(addr->port);
             rdma->host = g_strdup(addr->host);
         } else {
diff --git a/migration/savevm.c b/migration/savevm.c
index a00c1ab0af..352a8f23b5 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -33,15 +33,12 @@
 #include "hw/qdev.h"
 #include "hw/xen/xen.h"
 #include "net/net.h"
-#include "monitor/monitor.h"
 #include "sysemu/sysemu.h"
 #include "qemu/timer.h"
-#include "audio/audio.h"
 #include "migration/migration.h"
-#include "migration/postcopy-ram.h"
+#include "postcopy-ram.h"
 #include "qapi/qmp/qerror.h"
 #include "qemu/error-report.h"
-#include "qemu/sockets.h"
 #include "qemu/queue.h"
 #include "sysemu/cpus.h"
 #include "exec/memory.h"
@@ -50,7 +47,6 @@
 #include "qemu/bitops.h"
 #include "qemu/iov.h"
 #include "block/snapshot.h"
-#include "block/qapi.h"
 #include "qemu/cutils.h"
 #include "io/channel-buffer.h"
 #include "io/channel-file.h"
@@ -2078,7 +2074,7 @@ int qemu_loadvm_state(QEMUFile *f)
     return ret;
 }
 
-int save_vmstate(Monitor *mon, const char *name)
+int save_vmstate(const char *name)
 {
     BlockDriverState *bs, *bs1;
     QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
@@ -2092,8 +2088,8 @@ int save_vmstate(Monitor *mon, const char *name)
     AioContext *aio_context;
 
     if (!bdrv_all_can_snapshot(&bs)) {
-        monitor_printf(mon, "Device '%s' is writable but does not "
-                       "support snapshots.\n", bdrv_get_device_name(bs));
+        error_report("Device '%s' is writable but does not support snapshots",
+                     bdrv_get_device_name(bs));
         return ret;
     }
 
@@ -2110,7 +2106,7 @@ int save_vmstate(Monitor *mon, const char *name)
 
     bs = bdrv_all_find_vmstate_bs();
     if (bs == NULL) {
-        monitor_printf(mon, "No block device can accept snapshots\n");
+        error_report("No block device can accept snapshots");
         return ret;
     }
     aio_context = bdrv_get_aio_context(bs);
@@ -2119,7 +2115,7 @@ int save_vmstate(Monitor *mon, const char *name)
 
     ret = global_state_store();
     if (ret) {
-        monitor_printf(mon, "Error saving global state\n");
+        error_report("Error saving global state");
         return ret;
     }
     vm_stop(RUN_STATE_SAVE_VM);
@@ -2151,7 +2147,7 @@ int save_vmstate(Monitor *mon, const char *name)
     /* save the VM state */
     f = qemu_fopen_bdrv(bs, 1);
     if (!f) {
-        monitor_printf(mon, "Could not open VM state file\n");
+        error_report("Could not open VM state file");
         goto the_end;
     }
     ret = qemu_savevm_state(f, &local_err);
@@ -2164,8 +2160,8 @@ int save_vmstate(Monitor *mon, const char *name)
 
     ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, &bs);
     if (ret < 0) {
-        monitor_printf(mon, "Error while creating snapshot on '%s'\n",
-                       bdrv_get_device_name(bs));
+        error_report("Error while creating snapshot on '%s'",
+                     bdrv_get_device_name(bs));
         goto the_end;
     }
 
@@ -2179,11 +2175,6 @@ int save_vmstate(Monitor *mon, const char *name)
     return ret;
 }
 
-void hmp_savevm(Monitor *mon, const QDict *qdict)
-{
-    save_vmstate(mon, qdict_get_try_str(qdict, "name"));
-}
-
 void qmp_xen_save_devices_state(const char *filename, Error **errp)
 {
     QEMUFile *f;
@@ -2253,7 +2244,7 @@ int load_vmstate(const char *name)
     MigrationIncomingState *mis = migration_incoming_get_current();
 
     if (!bdrv_all_can_snapshot(&bs)) {
-        error_report("Device '%s' is writable but does not support snapshots.",
+        error_report("Device '%s' is writable but does not support snapshots",
                      bdrv_get_device_name(bs));
         return -ENOTSUP;
     }
@@ -2317,162 +2308,6 @@ int load_vmstate(const char *name)
     return 0;
 }
 
-void hmp_delvm(Monitor *mon, const QDict *qdict)
-{
-    BlockDriverState *bs;
-    Error *err;
-    const char *name = qdict_get_str(qdict, "name");
-
-    if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
-        error_reportf_err(err,
-                          "Error while deleting snapshot on device '%s': ",
-                          bdrv_get_device_name(bs));
-    }
-}
-
-void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
-{
-    BlockDriverState *bs, *bs1;
-    BdrvNextIterator it1;
-    QEMUSnapshotInfo *sn_tab, *sn;
-    bool no_snapshot = true;
-    int nb_sns, i;
-    int total;
-    int *global_snapshots;
-    AioContext *aio_context;
-
-    typedef struct SnapshotEntry {
-        QEMUSnapshotInfo sn;
-        QTAILQ_ENTRY(SnapshotEntry) next;
-    } SnapshotEntry;
-
-    typedef struct ImageEntry {
-        const char *imagename;
-        QTAILQ_ENTRY(ImageEntry) next;
-        QTAILQ_HEAD(, SnapshotEntry) snapshots;
-    } ImageEntry;
-
-    QTAILQ_HEAD(, ImageEntry) image_list =
-        QTAILQ_HEAD_INITIALIZER(image_list);
-
-    ImageEntry *image_entry, *next_ie;
-    SnapshotEntry *snapshot_entry;
-
-    bs = bdrv_all_find_vmstate_bs();
-    if (!bs) {
-        monitor_printf(mon, "No available block device supports snapshots\n");
-        return;
-    }
-    aio_context = bdrv_get_aio_context(bs);
-
-    aio_context_acquire(aio_context);
-    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
-    aio_context_release(aio_context);
-
-    if (nb_sns < 0) {
-        monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
-        return;
-    }
-
-    for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
-        int bs1_nb_sns = 0;
-        ImageEntry *ie;
-        SnapshotEntry *se;
-        AioContext *ctx = bdrv_get_aio_context(bs1);
-
-        aio_context_acquire(ctx);
-        if (bdrv_can_snapshot(bs1)) {
-            sn = NULL;
-            bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
-            if (bs1_nb_sns > 0) {
-                no_snapshot = false;
-                ie = g_new0(ImageEntry, 1);
-                ie->imagename = bdrv_get_device_name(bs1);
-                QTAILQ_INIT(&ie->snapshots);
-                QTAILQ_INSERT_TAIL(&image_list, ie, next);
-                for (i = 0; i < bs1_nb_sns; i++) {
-                    se = g_new0(SnapshotEntry, 1);
-                    se->sn = sn[i];
-                    QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
-                }
-            }
-            g_free(sn);
-        }
-        aio_context_release(ctx);
-    }
-
-    if (no_snapshot) {
-        monitor_printf(mon, "There is no snapshot available.\n");
-        return;
-    }
-
-    global_snapshots = g_new0(int, nb_sns);
-    total = 0;
-    for (i = 0; i < nb_sns; i++) {
-        SnapshotEntry *next_sn;
-        if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) {
-            global_snapshots[total] = i;
-            total++;
-            QTAILQ_FOREACH(image_entry, &image_list, next) {
-                QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
-                                    next, next_sn) {
-                    if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
-                        QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
-                                      next);
-                        g_free(snapshot_entry);
-                    }
-                }
-            }
-        }
-    }
-
-    monitor_printf(mon, "List of snapshots present on all disks:\n");
-
-    if (total > 0) {
-        bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
-        monitor_printf(mon, "\n");
-        for (i = 0; i < total; i++) {
-            sn = &sn_tab[global_snapshots[i]];
-            /* The ID is not guaranteed to be the same on all images, so
-             * overwrite it.
-             */
-            pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
-            bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, sn);
-            monitor_printf(mon, "\n");
-        }
-    } else {
-        monitor_printf(mon, "None\n");
-    }
-
-    QTAILQ_FOREACH(image_entry, &image_list, next) {
-        if (QTAILQ_EMPTY(&image_entry->snapshots)) {
-            continue;
-        }
-        monitor_printf(mon,
-                       "\nList of partial (non-loadable) snapshots on '%s':\n",
-                       image_entry->imagename);
-        bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
-        monitor_printf(mon, "\n");
-        QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
-            bdrv_snapshot_dump((fprintf_function)monitor_printf, mon,
-                               &snapshot_entry->sn);
-            monitor_printf(mon, "\n");
-        }
-    }
-
-    QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
-        SnapshotEntry *next_sn;
-        QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
-                            next_sn) {
-            g_free(snapshot_entry);
-        }
-        g_free(image_entry);
-    }
-    g_free(sn_tab);
-    g_free(global_snapshots);
-
-}
-
 void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev)
 {
     qemu_ram_set_idstr(mr->ram_block,
diff --git a/migration/socket.c b/migration/socket.c
index 13966f1d26..1cfbe81e69 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -27,17 +27,16 @@
 
 static SocketAddress *tcp_build_address(const char *host_port, Error **errp)
 {
-    InetSocketAddress *iaddr = inet_parse(host_port, errp);
     SocketAddress *saddr;
 
-    if (!iaddr) {
+    saddr = g_new0(SocketAddress, 1);
+    saddr->type = SOCKET_ADDRESS_TYPE_INET;
+
+    if (inet_parse(&saddr->u.inet, host_port, errp)) {
+        qapi_free_SocketAddress(saddr);
         return NULL;
     }
 
-    saddr = g_new0(SocketAddress, 1);
-    saddr->type = SOCKET_ADDRESS_KIND_INET;
-    saddr->u.inet.data = iaddr;
-
     return saddr;
 }
 
@@ -47,9 +46,8 @@ static SocketAddress *unix_build_address(const char *path)
     SocketAddress *saddr;
 
     saddr = g_new0(SocketAddress, 1);
-    saddr->type = SOCKET_ADDRESS_KIND_UNIX;
-    saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
-    saddr->u.q_unix.data->path = g_strdup(path);
+    saddr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    saddr->u.q_unix.path = g_strdup(path);
 
     return saddr;
 }
@@ -79,7 +77,6 @@ static void socket_outgoing_migration(QIOTask *task,
 
     if (qio_task_propagate_error(task, &err)) {
         trace_migration_socket_outgoing_error(error_get_pretty(err));
-        data->s->to_dst_file = NULL;
         migrate_fd_error(data->s, err);
         error_free(err);
     } else {
@@ -97,8 +94,8 @@ static void socket_start_outgoing_migration(MigrationState *s,
     struct SocketConnectData *data = g_new0(struct SocketConnectData, 1);
 
     data->s = s;
-    if (saddr->type == SOCKET_ADDRESS_KIND_INET) {
-        data->hostname = g_strdup(saddr->u.inet.data->host);
+    if (saddr->type == SOCKET_ADDRESS_TYPE_INET) {
+        data->hostname = g_strdup(saddr->u.inet.host);
     }
 
     qio_channel_set_name(QIO_CHANNEL(sioc), "migration-socket-outgoing");
diff --git a/migration/tls.c b/migration/tls.c
index 45bec44ca4..a33ecb767e 100644
--- a/migration/tls.c
+++ b/migration/tls.c
@@ -116,7 +116,6 @@ static void migration_tls_outgoing_handshake(QIOTask *task,
 
     if (qio_task_propagate_error(task, &err)) {
         trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
-        s->to_dst_file = NULL;
         migrate_fd_error(s, err);
         error_free(err);
     } else {
diff --git a/migration/trace-events b/migration/trace-events
index b8f01a218c..5b8ccf301c 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -69,8 +69,10 @@ migration_bitmap_sync_start(void) ""
 migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
 migration_throttle(void) ""
 ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx"
+ram_load_loop(const char *rbname, uint64_t addr, int flags, void *host) "%s: addr: %" PRIx64 " flags: %x host: %p"
 ram_load_postcopy_loop(uint64_t addr, int flags) "@%" PRIx64 " %x"
 ram_postcopy_send_discard_bitmap(void) ""
+ram_save_page(const char *rbname, uint64_t offset, void *host) "%s: offset: %" PRIx64 " host: %p"
 ram_save_queue_pages(const char *rbname, size_t start, size_t len) "%s: start: %zx len: %zx"
 
 # migration/migration.c
diff --git a/monitor.c b/monitor.c
index 62c9f81e8e..078cba5c86 100644
--- a/monitor.c
+++ b/monitor.c
@@ -37,7 +37,6 @@
 #include "net/slirp.h"
 #include "sysemu/char.h"
 #include "ui/qemu-spice.h"
-#include "sysemu/sysemu.h"
 #include "sysemu/numa.h"
 #include "monitor/monitor.h"
 #include "qemu/config-file.h"
@@ -1954,18 +1953,6 @@ void qmp_closefd(const char *fdname, Error **errp)
     error_setg(errp, QERR_FD_NOT_FOUND, fdname);
 }
 
-static void hmp_loadvm(Monitor *mon, const QDict *qdict)
-{
-    int saved_vm_running  = runstate_is_running();
-    const char *name = qdict_get_str(qdict, "name");
-
-    vm_stop(RUN_STATE_RESTORE_VM);
-
-    if (load_vmstate(name) == 0 && saved_vm_running) {
-        vm_start();
-    }
-}
-
 int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
 {
     mon_fd_t *monfd;
@@ -2782,7 +2769,7 @@ static QDict *monitor_parse_arguments(Monitor *mon,
                     }
                     goto fail;
                 }
-                qdict_put(qdict, key, qstring_from_str(buf));
+                qdict_put_str(qdict, key, buf);
             }
             break;
         case 'O':
@@ -2884,9 +2871,9 @@ static QDict *monitor_parse_arguments(Monitor *mon,
                         size = -1;
                     }
                 }
-                qdict_put(qdict, "count", qint_from_int(count));
-                qdict_put(qdict, "format", qint_from_int(format));
-                qdict_put(qdict, "size", qint_from_int(size));
+                qdict_put_int(qdict, "count", count);
+                qdict_put_int(qdict, "format", format);
+                qdict_put_int(qdict, "size", size);
             }
             break;
         case 'i':
@@ -2929,7 +2916,7 @@ static QDict *monitor_parse_arguments(Monitor *mon,
                     }
                     val <<= 20;
                 }
-                qdict_put(qdict, key, qint_from_int(val));
+                qdict_put_int(qdict, key, val);
             }
             break;
         case 'o':
@@ -2952,7 +2939,7 @@ static QDict *monitor_parse_arguments(Monitor *mon,
                     monitor_printf(mon, "invalid size\n");
                     goto fail;
                 }
-                qdict_put(qdict, key, qint_from_int(val));
+                qdict_put_int(qdict, key, val);
                 p = end;
             }
             break;
@@ -3008,7 +2995,7 @@ static QDict *monitor_parse_arguments(Monitor *mon,
                     monitor_printf(mon, "Expected 'on' or 'off'\n");
                     goto fail;
                 }
-                qdict_put(qdict, key, qbool_from_bool(val));
+                qdict_put_bool(qdict, key, val);
             }
             break;
         case '-':
@@ -3039,7 +3026,7 @@ static QDict *monitor_parse_arguments(Monitor *mon,
                     } else {
                         /* has option */
                         p++;
-                        qdict_put(qdict, key, qbool_from_bool(true));
+                        qdict_put_bool(qdict, key, true);
                     }
                 }
             }
@@ -3065,7 +3052,7 @@ static QDict *monitor_parse_arguments(Monitor *mon,
                                    cmd->name);
                     goto fail;
                 }
-                qdict_put(qdict, key, qstring_from_str(p));
+                qdict_put_str(qdict, key, p);
                 p += len;
             }
             break;
@@ -3844,9 +3831,8 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
                     QapiErrorClass_lookup[ERROR_CLASS_COMMAND_NOT_FOUND])) {
             /* Provide a more useful error message */
             qdict_del(qdict, "desc");
-            qdict_put(qdict, "desc",
-                      qstring_from_str("Expecting capabilities negotiation"
-                                       " with 'qmp_capabilities'"));
+            qdict_put_str(qdict, "desc", "Expecting capabilities negotiation"
+                          " with 'qmp_capabilities'");
         }
     }
 
diff --git a/net/vhost-user.c b/net/vhost-user.c
index e7e63408a1..00a0c1cbc5 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -154,7 +154,7 @@ static void vhost_user_cleanup(NetClientState *nc)
         Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
 
         qemu_chr_fe_deinit(&s->chr);
-        qemu_chr_delete(chr);
+        object_unparent(OBJECT(chr));
     }
 
     qemu_purge_queued_packets(nc);
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 2a4adfa654..0b01d49495 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differdiff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index 0339c24789..79a46b6735 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
 
 .PHONY : all clean build-all
 
-OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o virtio-scsi.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o
 QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
 QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
 QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index b21c877b53..523fa78c5f 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -183,15 +183,21 @@ static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address)
 static void run_eckd_boot_script(block_number_t mbr_block_nr)
 {
     int i;
+    unsigned int loadparm = get_loadparm_index();
     block_number_t block_nr;
     uint64_t address;
-    ScsiMbr *scsi_mbr = (void *)sec;
+    ScsiMbr *bte = (void *)sec; /* Eckd bootmap table entry */
     BootMapScript *bms = (void *)sec;
 
+    debug_print_int("loadparm", loadparm);
+    IPL_assert(loadparm < 31, "loadparm value greater than"
+               " maximum number of boot entries allowed");
+
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
     read_block(mbr_block_nr, sec, "Cannot read MBR");
 
-    block_nr = eckd_block_num((void *)&(scsi_mbr->blockptr));
+    block_nr = eckd_block_num((void *)&(bte->blockptr[loadparm]));
+    IPL_assert(block_nr != -1, "No Boot Map");
 
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
     read_block(block_nr, sec, "Cannot read Boot Map Script");
@@ -444,7 +450,8 @@ static void ipl_scsi(void)
     uint8_t *ns, *ns_end;
     int program_table_entries = 0;
     const int pte_len = sizeof(ScsiBlockPtr);
-    ScsiBlockPtr *prog_table_entry;
+    ScsiBlockPtr *prog_table_entry = NULL;
+    unsigned int loadparm = get_loadparm_index();
 
     /* Grab the MBR */
     memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@@ -458,15 +465,16 @@ static void ipl_scsi(void)
     debug_print_int("MBR Version", mbr->version_id);
     IPL_check(mbr->version_id == 1,
               "Unknown MBR layout version, assuming version 1");
-    debug_print_int("program table", mbr->blockptr.blockno);
-    IPL_assert(mbr->blockptr.blockno, "No Program Table");
+    debug_print_int("program table", mbr->blockptr[0].blockno);
+    IPL_assert(mbr->blockptr[0].blockno, "No Program Table");
 
     /* Parse the program table */
-    read_block(mbr->blockptr.blockno, sec,
+    read_block(mbr->blockptr[0].blockno, sec,
                "Error reading Program Table");
 
     IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT");
 
+    debug_print_int("loadparm index", loadparm);
     ns_end = sec + virtio_get_block_size();
     for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns += pte_len) {
         prog_table_entry = (ScsiBlockPtr *)ns;
@@ -475,16 +483,15 @@ static void ipl_scsi(void)
         }
 
         program_table_entries++;
+        if (program_table_entries == loadparm + 1) {
+            break; /* selected entry found */
+        }
     }
 
     debug_print_int("program table entries", program_table_entries);
 
     IPL_assert(program_table_entries != 0, "Empty Program Table");
 
-    /* Run the default entry */
-
-    prog_table_entry = (ScsiBlockPtr *)(sec + pte_len);
-
     zipl_run(prog_table_entry); /* no return */
 }
 
@@ -648,6 +655,7 @@ static IsoBcSection *find_iso_bc_entry(void)
     IsoBcEntry *e = (IsoBcEntry *)sec;
     uint32_t offset = find_iso_bc();
     int i;
+    unsigned int loadparm = get_loadparm_index();
 
     if (!offset) {
         return NULL;
@@ -668,7 +676,11 @@ static IsoBcSection *find_iso_bc_entry(void)
     for (i = 1; i < ISO_BC_ENTRY_PER_SECTOR; i++) {
         if (e[i].id == ISO_BC_BOOTABLE_SECTION) {
             if (is_iso_bc_entry_compatible(&e[i].body.sect)) {
-                return &e[i].body.sect;
+                if (loadparm <= 1) {
+                    /* found, default, or unspecified */
+                    return &e[i].body.sect;
+                }
+                loadparm--;
             }
         }
     }
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index bea168714b..7f367820f3 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -70,7 +70,7 @@ typedef struct ScsiMbr {
     uint8_t magic[4];
     uint32_t version_id;
     uint8_t reserved[8];
-    ScsiBlockPtr blockptr;
+    ScsiBlockPtr blockptr[];
 } __attribute__ ((packed)) ScsiMbr;
 
 #define ZIPL_MAGIC              "zIPL"
@@ -264,28 +264,6 @@ typedef enum {
 
 /* utility code below */
 
-static const unsigned char ebc2asc[256] =
-      /* 0123456789abcdef0123456789abcdef */
-        "................................" /* 1F */
-        "................................" /* 3F */
-        " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
-        "-/.........,%_>?.........`:#@'=\""/* 7F */
-        ".abcdefghi.......jklmnopqr......" /* 9F */
-        "..stuvwxyz......................" /* BF */
-        ".ABCDEFGHI.......JKLMNOPQR......" /* DF */
-        "..STUVWXYZ......0123456789......";/* FF */
-
-static inline void ebcdic_to_ascii(const char *src,
-                                   char *dst,
-                                   unsigned int size)
-{
-    unsigned int i;
-    for (i = 0; i < size; i++) {
-        unsigned c = src[i];
-        dst[i] = ebc2asc[c];
-    }
-}
-
 static inline void print_volser(const void *volser)
 {
     char ascii[8];
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 0946766d86..1cacc1b46f 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -14,6 +14,18 @@
 char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
 static SubChannelId blk_schid = { .one = 1 };
 IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
+static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+const unsigned char ebc2asc[256] =
+      /* 0123456789abcdef0123456789abcdef */
+        "................................" /* 1F */
+        "................................" /* 3F */
+        " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
+        "-/.........,%_>?.........`:#@'=\""/* 7F */
+        ".abcdefghi.......jklmnopqr......" /* 9F */
+        "..stuvwxyz......................" /* BF */
+        ".ABCDEFGHI.......JKLMNOPQR......" /* DF */
+        "..STUVWXYZ......0123456789......";/* FF */
 
 /*
  * Priniciples of Operations (SA22-7832-09) chapter 17 requires that
@@ -29,7 +41,6 @@ void write_subsystem_identification(void)
     *zeroes = 0;
 }
 
-
 void panic(const char *string)
 {
     sclp_print(string);
@@ -37,6 +48,26 @@ void panic(const char *string)
     while (1) { }
 }
 
+unsigned int get_loadparm_index(void)
+{
+    const char *lp = loadparm;
+    int i;
+    unsigned int idx = 0;
+
+    for (i = 0; i < 8; i++) {
+        char c = lp[i];
+
+        if (c < '0' || c > '9') {
+            break;
+        }
+
+        idx *= 10;
+        idx += c - '0';
+    }
+
+    return idx;
+}
+
 static bool find_dev(Schib *schib, int dev_no)
 {
     int i, r;
@@ -73,6 +104,7 @@ static void virtio_setup(void)
     int ssid;
     bool found = false;
     uint16_t dev_no;
+    char ldp[] = "LOADPARM=[________]\n";
     VDev *vdev = virtio_get_device();
 
     /*
@@ -82,6 +114,10 @@ static void virtio_setup(void)
      */
     enable_mss_facility();
 
+    sclp_get_loadparm_ascii(loadparm);
+    memcpy(ldp + 10, loadparm, 8);
+    sclp_print(ldp);
+
     if (store_iplb(&iplb)) {
         switch (iplb.pbt) {
         case S390_IPL_TYPE_CCW:
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index ded67bcbc6..07d8cbcb20 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -62,10 +62,12 @@ void consume_sclp_int(void);
 void panic(const char *string);
 void write_subsystem_identification(void);
 extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
+unsigned int get_loadparm_index(void);
 
-/* sclp-ascii.c */
+/* sclp.c */
 void sclp_print(const char *string);
 void sclp_setup(void);
+void sclp_get_loadparm_ascii(char *loadparm);
 
 /* virtio.c */
 unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
@@ -189,4 +191,17 @@ static inline void IPL_check(bool term, const char *message)
     }
 }
 
+extern const unsigned char ebc2asc[256];
+static inline void ebcdic_to_ascii(const char *src,
+                                   char *dst,
+                                   unsigned int size)
+{
+    unsigned int i;
+
+    for (i = 0; i < size; i++) {
+        unsigned c = src[i];
+        dst[i] = ebc2asc[c];
+    }
+}
+
 #endif /* S390_CCW_H */
diff --git a/pc-bios/s390-ccw/sclp-ascii.c b/pc-bios/s390-ccw/sclp.c
index dc1c3e4f4d..a1639baed7 100644
--- a/pc-bios/s390-ccw/sclp-ascii.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -80,3 +80,15 @@ void sclp_print(const char *str)
 
     sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
 }
+
+void sclp_get_loadparm_ascii(char *loadparm)
+{
+
+    ReadInfo *sccb = (void *)_sccb;
+
+    memset((char *)_sccb, 0, sizeof(ReadInfo));
+    sccb->h.length = sizeof(ReadInfo);
+    if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
+        ebcdic_to_ascii((char *) sccb->loadparm, loadparm, 8);
+    }
+}
diff --git a/pc-bios/s390-ccw/sclp.h b/pc-bios/s390-ccw/sclp.h
index 3cbfb78930..0dd987ff5d 100644
--- a/pc-bios/s390-ccw/sclp.h
+++ b/pc-bios/s390-ccw/sclp.h
@@ -55,6 +55,8 @@ typedef struct ReadInfo {
     SCCBHeader h;
     uint16_t rnmax;
     uint8_t rnsize;
+    uint8_t reserved[13];
+    uint8_t loadparm[8];
 } __attribute__((packed)) ReadInfo;
 
 typedef struct SCCB {
diff --git a/pc-bios/sgabios.bin b/pc-bios/sgabios.bin
index c3da4c3d0a..6308f2e2d7 100644
--- a/pc-bios/sgabios.bin
+++ b/pc-bios/sgabios.bin
Binary files differdiff --git a/qapi-schema.json b/qapi-schema.json
index 01b087fa16..5728b7f363 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4122,13 +4122,19 @@
     'port': 'str' } }
 
 ##
-# @SocketAddress:
+# @SocketAddressLegacy:
 #
 # Captures the address of a socket, which could also be a named file descriptor
 #
+# Note: This type is deprecated in favor of SocketAddress.  The
+# difference between SocketAddressLegacy and SocketAddress is that the
+# latter is a flat union rather than a simple union. Flat is nicer
+# because it avoids nesting on the wire, i.e. that form has fewer {}.
+
+#
 # Since: 1.3
 ##
-{ 'union': 'SocketAddress',
+{ 'union': 'SocketAddressLegacy',
   'data': {
     'inet': 'InetSocketAddress',
     'unix': 'UnixSocketAddress',
@@ -4136,9 +4142,9 @@
     'fd': 'String' } }
 
 ##
-# @SocketAddressFlatType:
+# @SocketAddressType:
 #
-# Available SocketAddressFlat types
+# Available SocketAddress types
 #
 # @inet:  Internet address
 #
@@ -4146,24 +4152,21 @@
 #
 # Since: 2.9
 ##
-{ 'enum': 'SocketAddressFlatType',
+{ 'enum': 'SocketAddressType',
   'data': [ 'inet', 'unix', 'vsock', 'fd' ] }
 
 ##
-# @SocketAddressFlat:
+# @SocketAddress:
 #
-# Captures the address of a socket
+# Captures the address of a socket, which could also be a named file
+# descriptor
 #
 # @type:       Transport type
 #
-# This is just like SocketAddress, except it's a flat union rather
-# than a simple union.  Nicer because it avoids nesting on the wire,
-# i.e. this form has fewer {}.
-#
 # Since: 2.9
 ##
-{ 'union': 'SocketAddressFlat',
-  'base': { 'type': 'SocketAddressFlatType' },
+{ 'union': 'SocketAddress',
+  'base': { 'type': 'SocketAddressType' },
   'discriminator': 'type',
   'data': { 'inet': 'InetSocketAddress',
             'unix': 'UnixSocketAddress',
@@ -4877,6 +4880,8 @@
 # @nodelay: set TCP_NODELAY socket option (default: false)
 # @telnet: enable telnet protocol on server
 #          sockets (default: false)
+# @tn3270: enable tn3270 protocol on server
+#          sockets (default: false) (Since: 2.10)
 # @reconnect: For a client socket, if a socket is disconnected,
 #          then attempt a reconnect after the given number of seconds.
 #          Setting this to zero disables this function. (default: 0)
@@ -4884,12 +4889,13 @@
 #
 # Since: 1.4
 ##
-{ 'struct': 'ChardevSocket', 'data': { 'addr'       : 'SocketAddress',
+{ 'struct': 'ChardevSocket', 'data': { 'addr'       : 'SocketAddressLegacy',
                                      '*tls-creds'  : 'str',
                                      '*server'    : 'bool',
                                      '*wait'      : 'bool',
                                      '*nodelay'   : 'bool',
                                      '*telnet'    : 'bool',
+                                     '*tn3270'    : 'bool',
                                      '*reconnect' : 'int' },
   'base': 'ChardevCommon' }
 
@@ -4903,8 +4909,8 @@
 #
 # Since: 1.5
 ##
-{ 'struct': 'ChardevUdp', 'data': { 'remote' : 'SocketAddress',
-                                  '*local' : 'SocketAddress' },
+{ 'struct': 'ChardevUdp', 'data': { 'remote' : 'SocketAddressLegacy',
+                                  '*local' : 'SocketAddressLegacy' },
   'base': 'ChardevCommon' }
 
 ##
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 87fb747ab6..614181b553 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2522,7 +2522,7 @@
 { 'struct': 'BlockdevOptionsGluster',
   'data': { 'volume': 'str',
             'path': 'str',
-            'server': ['SocketAddressFlat'],
+            'server': ['SocketAddress'],
             '*debug': 'int',
             '*logfile': 'str' } }
 
@@ -2634,7 +2634,7 @@
 # Since: 2.9
 ##
 { 'struct': 'BlockdevOptionsSheepdog',
-  'data': { 'server': 'SocketAddressFlat',
+  'data': { 'server': 'SocketAddress',
             'vdi': 'str',
             '*snap-id': 'uint32',
             '*tag': 'str' } }
@@ -2849,7 +2849,7 @@
 # Since: 2.9
 ##
 { 'struct': 'BlockdevOptionsNbd',
-  'data': { 'server': 'SocketAddressFlat',
+  'data': { 'server': 'SocketAddress',
             '*export': 'str',
             '*tls-creds': 'str' } }
 
diff --git a/qapi/block.json b/qapi/block.json
index 46fca0e1f3..6a2fdc73f7 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -204,7 +204,7 @@
 # Since: 1.3.0
 ##
 { 'command': 'nbd-server-start',
-  'data': { 'addr': 'SocketAddress',
+  'data': { 'addr': 'SocketAddressLegacy',
             '*tls-creds': 'str'} }
 
 ##
diff --git a/qapi/qapi-clone-visitor.c b/qapi/qapi-clone-visitor.c
index 34086cbfc0..de756bfb33 100644
--- a/qapi/qapi-clone-visitor.c
+++ b/qapi/qapi-clone-visitor.c
@@ -180,3 +180,16 @@ void *qapi_clone(const void *src, void (*visit_type)(Visitor *, const char *,
     visit_free(v);
     return dst;
 }
+
+void qapi_clone_members(void *dst, const void *src, size_t sz,
+                        void (*visit_type_members)(Visitor *, void *,
+                                                   Error **))
+{
+    Visitor *v;
+
+    v = qapi_clone_visitor_new();
+    memcpy(dst, src, sz);
+    to_qcv(v)->depth++;
+    visit_type_members(v, dst, &error_abort);
+    visit_free(v);
+}
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index dc502129d8..5ad36f8a09 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -30,7 +30,7 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
 
     dict = qobject_to_qdict(request);
     if (!dict) {
-        error_setg(errp, "Expected '%s' in QMP input", "object");
+        error_setg(errp, "QMP input must be a JSON object");
         return NULL;
     }
 
@@ -41,26 +41,26 @@ static QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp)
 
         if (!strcmp(arg_name, "execute")) {
             if (qobject_type(arg_obj) != QTYPE_QSTRING) {
-                error_setg(errp, "QMP input object member '%s' expects '%s'",
-                           "execute", "string");
+                error_setg(errp,
+                           "QMP input member 'execute' must be a string");
                 return NULL;
             }
             has_exec_key = true;
         } else if (!strcmp(arg_name, "arguments")) {
             if (qobject_type(arg_obj) != QTYPE_QDICT) {
-                error_setg(errp, "QMP input object member '%s' expects '%s'",
-                           "arguments", "object");
+                error_setg(errp,
+                           "QMP input member 'arguments' must be an object");
                 return NULL;
             }
         } else {
-            error_setg(errp, "QMP input object member '%s' is unexpected",
+            error_setg(errp, "QMP input member '%s' is unexpected",
                        arg_name);
             return NULL;
         }
     }
 
     if (!has_exec_key) {
-        error_setg(errp, "Expected '%s' in QMP input", "execute");
+        error_setg(errp, "QMP input lacks member 'execute'");
         return NULL;
     }
 
diff --git a/qapi/qmp-event.c b/qapi/qmp-event.c
index 802ede48e3..ba3029cc89 100644
--- a/qapi/qmp-event.c
+++ b/qapi/qmp-event.c
@@ -51,7 +51,7 @@ static void timestamp_put(QDict *qdict)
 QDict *qmp_event_build_dict(const char *event_name)
 {
     QDict *dict = qdict_new();
-    qdict_put(dict, "event", qstring_from_str(event_name));
+    qdict_put_str(dict, "event", event_name);
     timestamp_put(dict);
     return dict;
 }
diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
index 865e948ac0..d0f0002317 100644
--- a/qapi/qobject-input-visitor.c
+++ b/qapi/qobject-input-visitor.c
@@ -55,6 +55,17 @@ static QObjectInputVisitor *to_qiv(Visitor *v)
     return container_of(v, QObjectInputVisitor, visitor);
 }
 
+/*
+ * Find the full name of something @qiv is currently visiting.
+ * @qiv is visiting something named @name in the stack of containers
+ * @qiv->stack.
+ * If @n is zero, return its full name.
+ * If @n is positive, return the full name of the @n-th container
+ * counting from the top.  The stack of containers must have at least
+ * @n elements.
+ * The returned string is valid until the next full_name_nth(@v) or
+ * destruction of @v.
+ */
 static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name,
                                  int n)
 {
@@ -280,6 +291,15 @@ static void qobject_input_start_struct(Visitor *v, const char *name, void **obj,
     }
 }
 
+static void qobject_input_end_struct(Visitor *v, void **obj)
+{
+    QObjectInputVisitor *qiv = to_qiv(v);
+    StackObject *tos = QSLIST_FIRST(&qiv->stack);
+
+    assert(qobject_type(tos->obj) == QTYPE_QDICT && tos->h);
+    qobject_input_pop(v, obj);
+}
+
 
 static void qobject_input_start_list(Visitor *v, const char *name,
                                      GenericList **list, size_t size,
@@ -335,6 +355,14 @@ static void qobject_input_check_list(Visitor *v, Error **errp)
     }
 }
 
+static void qobject_input_end_list(Visitor *v, void **obj)
+{
+    QObjectInputVisitor *qiv = to_qiv(v);
+    StackObject *tos = QSLIST_FIRST(&qiv->stack);
+
+    assert(qobject_type(tos->obj) == QTYPE_QLIST && !tos->h);
+    qobject_input_pop(v, obj);
+}
 
 static void qobject_input_start_alternate(Visitor *v, const char *name,
                                           GenericAlternate **obj, size_t size,
@@ -634,11 +662,11 @@ static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
     v->visitor.type = VISITOR_INPUT;
     v->visitor.start_struct = qobject_input_start_struct;
     v->visitor.check_struct = qobject_input_check_struct;
-    v->visitor.end_struct = qobject_input_pop;
+    v->visitor.end_struct = qobject_input_end_struct;
     v->visitor.start_list = qobject_input_start_list;
     v->visitor.next_list = qobject_input_next_list;
     v->visitor.check_list = qobject_input_check_list;
-    v->visitor.end_list = qobject_input_pop;
+    v->visitor.end_list = qobject_input_end_list;
     v->visitor.start_alternate = qobject_input_start_alternate;
     v->visitor.optional = qobject_input_optional;
     v->visitor.free = qobject_input_free;
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 50411bc0ff..3dd9eac4f3 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -1732,37 +1732,45 @@ SASL service config /etc/sasl2/qemu.conf. If running QEMU as an
 unprivileged user, an environment variable SASL_CONF_PATH can be used
 to make it search alternate locations for the service config.
 
-The default configuration might contain
+If the TLS option is enabled for VNC, then it will provide session encryption,
+otherwise the SASL mechanism will have to provide encryption. In the latter
+case the list of possible plugins that can be used is drastically reduced. In
+fact only the GSSAPI SASL mechanism provides an acceptable level of security
+by modern standards. Previous versions of QEMU referred to the DIGEST-MD5
+mechanism, however, it has multiple serious flaws described in detail in
+RFC 6331 and thus should never be used any more. The SCRAM-SHA-1 mechanism
+provides a simple username/password auth facility similar to DIGEST-MD5, but
+does not support session encryption, so can only be used in combination with
+TLS.
+
+When not using TLS the recommended configuration is
 
 @example
-mech_list: digest-md5
-sasldb_path: /etc/qemu/passwd.db
+mech_list: gssapi
+keytab: /etc/qemu/krb5.tab
 @end example
 
-This says to use the 'Digest MD5' mechanism, which is similar to the HTTP
-Digest-MD5 mechanism. The list of valid usernames & passwords is maintained
-in the /etc/qemu/passwd.db file, and can be updated using the saslpasswd2
-command. While this mechanism is easy to configure and use, it is not
-considered secure by modern standards, so only suitable for developers /
-ad-hoc testing.
+This says to use the 'GSSAPI' mechanism with the Kerberos v5 protocol, with
+the server principal stored in /etc/qemu/krb5.tab. For this to work the
+administrator of your KDC must generate a Kerberos principal for the server,
+with a name of 'qemu/somehost.example.com@@EXAMPLE.COM' replacing
+'somehost.example.com' with the fully qualified host name of the machine
+running QEMU, and 'EXAMPLE.COM' with the Kerberos Realm.
 
-A more serious deployment might use Kerberos, which is done with the 'gssapi'
-mechanism
+When using TLS, if username+password authentication is desired, then a
+reasonable configuration is
 
 @example
-mech_list: gssapi
-keytab: /etc/qemu/krb5.tab
+mech_list: scram-sha-1
+sasldb_path: /etc/qemu/passwd.db
 @end example
 
-For this to work the administrator of your KDC must generate a Kerberos
-principal for the server, with a name of  'qemu/somehost.example.com@@EXAMPLE.COM'
-replacing 'somehost.example.com' with the fully qualified host name of the
-machine running QEMU, and 'EXAMPLE.COM' with the Kerberos Realm.
+The saslpasswd2 program can be used to populate the passwd.db file with
+accounts.
 
-Other configurations will be left as an exercise for the reader. It should
-be noted that only Digest-MD5 and GSSAPI provides a SSF layer for data
-encryption. For all other mechanisms, VNC should always be configured to
-use TLS and x509 certificates to protect security credentials from snooping.
+Other SASL configurations will be left as an exercise for the reader. Note that
+all mechanisms except GSSAPI, should be combined with use of TLS to ensure a
+secure data channel.
 
 @node gdb_usage
 @section GDB usage
diff --git a/qemu-img.c b/qemu-img.c
index c7196362df..f3b0ab49cc 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -313,7 +313,7 @@ static BlockBackend *img_open_file(const char *filename,
 
     if (fmt) {
         options = qdict_new();
-        qdict_put(options, "driver", qstring_from_str(fmt));
+        qdict_put_str(options, "driver", fmt);
     }
 
     blk = blk_new_open(filename, NULL, options, flags, &local_err);
@@ -3094,7 +3094,7 @@ static int img_rebase(int argc, char **argv)
 
         if (bs->backing_format[0] != '\0') {
             options = qdict_new();
-            qdict_put(options, "driver", qstring_from_str(bs->backing_format));
+            qdict_put_str(options, "driver", bs->backing_format);
         }
 
         bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
@@ -3111,7 +3111,7 @@ static int img_rebase(int argc, char **argv)
         if (out_baseimg[0]) {
             if (out_basefmt) {
                 options = qdict_new();
-                qdict_put(options, "driver", qstring_from_str(out_basefmt));
+                qdict_put_str(options, "driver", out_basefmt);
             } else {
                 options = NULL;
             }
diff --git a/qemu-io.c b/qemu-io.c
index 427cbaef57..ed0e2dceaa 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -601,7 +601,7 @@ int main(int argc, char **argv)
         } else {
             if (format) {
                 opts = qdict_new();
-                qdict_put(opts, "driver", qstring_from_str(format));
+                qdict_put_str(opts, "driver", format);
             }
             if (openfile(argv[optind], flags, writethrough, opts)) {
                 exit(1);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index e080fb7c75..b7ab86bfa7 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -395,13 +395,12 @@ static SocketAddress *nbd_build_socket_address(const char *sockpath,
 
     saddr = g_new0(SocketAddress, 1);
     if (sockpath) {
-        saddr->type = SOCKET_ADDRESS_KIND_UNIX;
-        saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
-        saddr->u.q_unix.data->path = g_strdup(sockpath);
+        saddr->type = SOCKET_ADDRESS_TYPE_UNIX;
+        saddr->u.q_unix.path = g_strdup(sockpath);
     } else {
         InetSocketAddress *inet;
-        saddr->type = SOCKET_ADDRESS_KIND_INET;
-        inet = saddr->u.inet.data = g_new0(InetSocketAddress, 1);
+        saddr->type = SOCKET_ADDRESS_TYPE_INET;
+        inet = &saddr->u.inet;
         inet->host = g_strdup(bindto);
         if (port) {
             inet->port = g_strdup(port);
@@ -959,7 +958,7 @@ int main(int argc, char **argv)
     } else {
         if (fmt) {
             options = qdict_new();
-            qdict_put(options, "driver", qstring_from_str(fmt));
+            qdict_put_str(options, "driver", fmt);
         }
         blk = blk_new_open(srcpath, NULL, options, flags, &local_err);
     }
diff --git a/qemu-options.hx b/qemu-options.hx
index a5b0589cb7..f806af9f2d 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -31,7 +31,7 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "-machine [type=]name[,prop[=value][,...]]\n"
     "                selects emulated machine ('-machine help' for list)\n"
     "                property accel=accel1[:accel2[:...]] selects accelerator\n"
-    "                supported accelerators are kvm, xen, tcg (default: tcg)\n"
+    "                supported accelerators are kvm, xen, hax or tcg (default: tcg)\n"
     "                kernel_irqchip=on|off|split controls accelerated irqchip support (default=off)\n"
     "                vmport=on|off|auto controls emulation of vmport (default: auto)\n"
     "                kvm_shadow_mem=size of KVM shadow MMU in bytes\n"
@@ -52,9 +52,9 @@ available machines. Supported machine properties are:
 @table @option
 @item accel=@var{accels1}[:@var{accels2}[:...]]
 This is used to enable an accelerator. Depending on the target architecture,
-kvm, xen, or tcg can be available. By default, tcg is used. If there is more
-than one accelerator specified, the next one is used if the previous one fails
-to initialize.
+kvm, xen, hax or tcg can be available. By default, tcg is used. If there is
+more than one accelerator specified, the next one is used if the previous one
+fails to initialize.
 @item kernel_irqchip=on|off
 Controls in-kernel irqchip support for the chosen accelerator when available.
 @item gfx_passthru=on|off
@@ -97,15 +97,15 @@ ETEXI
 
 DEF("accel", HAS_ARG, QEMU_OPTION_accel,
     "-accel [accel=]accelerator[,thread=single|multi]\n"
-    "               select accelerator ('-accel help for list')\n"
-    "               thread=single|multi (enable multi-threaded TCG)", QEMU_ARCH_ALL)
+    "                select accelerator (kvm, xen, hax or tcg; use 'help' for a list)\n"
+    "                thread=single|multi (enable multi-threaded TCG)", QEMU_ARCH_ALL)
 STEXI
 @item -accel @var{name}[,prop=@var{value}[,...]]
 @findex -accel
 This is used to enable an accelerator. Depending on the target architecture,
-kvm, xen, or tcg can be available. By default, tcg is used. If there is more
-than one accelerator specified, the next one is used if the previous one fails
-to initialize.
+kvm, xen, hax or tcg can be available. By default, tcg is used. If there is
+more than one accelerator specified, the next one is used if the previous one
+fails to initialize.
 @table @option
 @item thread=single|multi
 Controls number of TCG threads. When the TCG is multi-threaded there will be one
diff --git a/qemu.sasl b/qemu.sasl
index 64fdef3d5b..fb8a92ba58 100644
--- a/qemu.sasl
+++ b/qemu.sasl
@@ -1,36 +1,44 @@
-# If you want to use the non-TLS socket, then you *must* include
-# the GSSAPI or DIGEST-MD5 mechanisms, because they are the only
-# ones that can offer session encryption as well as authentication.
+# If you want to use VNC remotely without TLS, then you *must*
+# pick a mechanism which provides session encryption as well
+# as authentication.
 #
-# If you're only using TLS, then you can turn on any mechanisms
+# If you are only using TLS, then you can turn on any mechanisms
 # you like for authentication, because TLS provides the encryption
 #
-# Default to a simple username+password mechanism
-# NB digest-md5 is no longer considered secure by current standards
-mech_list: digest-md5
+# If you are only using UNIX sockets then encryption is not
+# required at all.
+#
+# NB, previously DIGEST-MD5 was set as the default mechanism for
+# QEMU VNC. Per RFC 6331 this is vulnerable to many serious security
+# flaws as should no longer be used. Thus GSSAPI is now the default.
+#
+# To use GSSAPI requires that a QEMU service principal is
+# added to the Kerberos server for each host running QEMU.
+# This principal needs to be exported to the keytab file listed below
+mech_list: gssapi
 
-# Before you can use GSSAPI, you need a service principle on the
-# KDC server for libvirt, and that to be exported to the keytab
-# file listed below
-#mech_list: gssapi
+# If using TLS with VNC, or a UNIX socket only, it is possible to
+# enable plugins which don't provide session encryption. The
+# 'scram-sha-1' plugin allows plain username/password authentication
+# to be performed
 #
-# You can also list many mechanisms at once, then the user can choose
-# by adding  '?auth=sasl.gssapi' to their libvirt URI, eg
-#   qemu+tcp://hostname/system?auth=sasl.gssapi
-#mech_list: digest-md5 gssapi
+#mech_list: scram-sha-1
+
+# You can also list many mechanisms at once, and the VNC server will
+# negotiate which to use by considering the list enabled on the VNC
+# client.
+#mech_list: scram-sha-1 gssapi
 
 # Some older builds of MIT kerberos on Linux ignore this option &
 # instead need KRB5_KTNAME env var.
 # For modern Linux, and other OS, this should be sufficient
 #
-# There is no default value here, uncomment if you need this
-#keytab: /etc/qemu/krb5.tab
+# This file needs to be populated with the service principal that
+# was created on the Kerberos v5 server. If switching to a non-gssapi
+# mechanism this can be commented out.
+keytab: /etc/qemu/krb5.tab
 
-# If using digest-md5 for username/passwds, then this is the file
+# If using scram-sha-1 for username/passwds, then this is the file
 # containing the passwds. Use 'saslpasswd2 -a qemu [username]'
 # to add entries, and 'sasldblistusers2 -f [sasldb_path]' to browse it
-sasldb_path: /etc/qemu/passwd.db
-
-
-auxprop_plugin: sasldb
-
+#sasldb_path: /etc/qemu/passwd.db
diff --git a/qga/main.c b/qga/main.c
index ad6f68f187..cc58d2b53d 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -1388,9 +1388,9 @@ int main(int argc, char **argv)
 
         addr = socket_local_address(FIRST_SOCKET_ACTIVATION_FD, NULL);
         if (addr) {
-            if (addr->type == SOCKET_ADDRESS_KIND_UNIX) {
+            if (addr->type == SOCKET_ADDRESS_TYPE_UNIX) {
                 config->method = g_strdup("unix-listen");
-            } else if (addr->type == SOCKET_ADDRESS_KIND_VSOCK) {
+            } else if (addr->type == SOCKET_ADDRESS_TYPE_VSOCK) {
                 config->method = g_strdup("vsock-listen");
             }
 
diff --git a/qobject/qdict.c b/qobject/qdict.c
index 291eef1a19..88e2ecd658 100644
--- a/qobject/qdict.c
+++ b/qobject/qdict.c
@@ -463,7 +463,7 @@ void qdict_set_default_str(QDict *dst, const char *key, const char *val)
         return;
     }
 
-    qdict_put(dst, key, qstring_from_str(val));
+    qdict_put_str(dst, key, val);
 }
 
 static void qdict_flatten_qdict(QDict *qdict, QDict *target,
diff --git a/qom/container.c b/qom/container.c
index c9eb49b01e..f6ccaf7ea7 100644
--- a/qom/container.c
+++ b/qom/container.c
@@ -40,6 +40,7 @@ Object *container_get(Object *root, const char *path)
         if (!child) {
             child = object_new("container");
             object_property_add_child(obj, parts[i], child, NULL);
+            object_unref(child);
         }
     }
 
diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c
index 65e2d375c2..8cced4604f 100644
--- a/replay/replay-snapshot.c
+++ b/replay/replay-snapshot.c
@@ -64,7 +64,7 @@ void replay_vmstate_init(void)
 {
     if (replay_snapshot) {
         if (replay_mode == REPLAY_MODE_RECORD) {
-            if (save_vmstate(cur_mon, replay_snapshot) != 0) {
+            if (save_vmstate(replay_snapshot) != 0) {
                 error_report("Could not create snapshot for icount record");
                 exit(1);
             }
diff --git a/roms/sgabios b/roms/sgabios
-Subproject 23d474943dcd55d0550a3d20b3d30e9040a4f15
+Subproject cbaee52287e5f32373181cff50a00b6c4ac9015
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 3bb6fc95bd..45027b9281 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2572,6 +2572,27 @@ sub process {
 		if ($line =~ /\bbzero\(/) {
 			ERROR("use memset() instead of bzero()\n" . $herecurr);
 		}
+		my $non_exit_glib_asserts = qr{g_assert_cmpstr|
+						g_assert_cmpint|
+						g_assert_cmpuint|
+						g_assert_cmphex|
+						g_assert_cmpfloat|
+						g_assert_true|
+						g_assert_false|
+						g_assert_nonnull|
+						g_assert_null|
+						g_assert_no_error|
+						g_assert_error|
+						g_test_assert_expected_messages|
+						g_test_trap_assert_passed|
+						g_test_trap_assert_stdout|
+						g_test_trap_assert_stdout_unmatched|
+						g_test_trap_assert_stderr|
+						g_test_trap_assert_stderr_unmatched}x;
+		if ($realfile !~ /^tests\// &&
+			$line =~ /\b(?:$non_exit_glib_asserts)\(/) {
+			ERROR("Use g_assert or g_assert_not_reached\n". $herecurr);
+		}
 	}
 
 	# If we have no input at all, then there is nothing to report on
diff --git a/scripts/coccinelle/qobject.cocci b/scripts/coccinelle/qobject.cocci
new file mode 100644
index 0000000000..97703a438b
--- /dev/null
+++ b/scripts/coccinelle/qobject.cocci
@@ -0,0 +1,35 @@
+// Use QDict macros where they make sense
+@@
+expression Obj, Key, E;
+@@
+(
+- qdict_put_obj(Obj, Key, QOBJECT(E));
++ qdict_put(Obj, Key, E);
+|
+- qdict_put(Obj, Key, qint_from_int(E));
++ qdict_put_int(Obj, Key, E);
+|
+- qdict_put(Obj, Key, qbool_from_bool(E));
++ qdict_put_bool(Obj, Key, E);
+|
+- qdict_put(Obj, Key, qstring_from_str(E));
++ qdict_put_str(Obj, Key, E);
+)
+
+// Use QList macros where they make sense
+@@
+expression Obj, E;
+@@
+(
+- qlist_append_obj(Obj, QOBJECT(E));
++ qlist_append(Obj, E);
+|
+- qlist_append(Obj, qint_from_int(E));
++ qlist_append_int(Obj, E);
+|
+- qlist_append(Obj, qbool_from_bool(E));
++ qlist_append_bool(Obj, E);
+|
+- qlist_append(Obj, qstring_from_str(E));
++ qlist_append_str(Obj, E);
+)
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index d7c2311123..711a9a6bd0 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -22,6 +22,7 @@ my $lk_path = "./";
 my $email = 1;
 my $email_usename = 1;
 my $email_maintainer = 1;
+my $email_reviewer = 1;
 my $email_list = 1;
 my $email_subscriber_list = 0;
 my $email_git = 0;
@@ -181,6 +182,7 @@ if (!GetOptions(
 		'remove-duplicates!' => \$email_remove_duplicates,
 		'mailmap!' => \$email_use_mailmap,
 		'm!' => \$email_maintainer,
+		'r!' => \$email_reviewer,
 		'n!' => \$email_usename,
 		'l!' => \$email_list,
 		's!' => \$email_subscriber_list,
@@ -239,7 +241,8 @@ if ($sections) {
 }
 
 if ($email &&
-    ($email_maintainer + $email_list + $email_subscriber_list +
+    ($email_maintainer + $email_reviewer +
+     $email_list + $email_subscriber_list +
      $email_git + $email_git_blame) == 0) {
     die "$P: Please select at least 1 email option\n";
 }
@@ -719,6 +722,7 @@ MAINTAINER field selection options:
     --hg-since => hg history to use (default: $email_hg_since)
     --interactive => display a menu (mostly useful if used with the --git option)
     --m => include maintainer(s) if any
+    --r => include reviewer(s) if any
     --n => include name 'Full Name <addr\@domain.tld>'
     --l => include list(s) if any
     --s => include subscriber only list(s) if any
@@ -745,7 +749,7 @@ Other options:
   --help => show this help information
 
 Default options:
-  [--email --nogit --git-fallback --m --n --l --multiline -pattern-depth=0
+  [--email --nogit --git-fallback --m --r --n --l --multiline --pattern-depth=0
    --remove-duplicates --rolestats]
 
 Notes:
@@ -893,20 +897,29 @@ sub find_ending_index {
     return $index;
 }
 
-sub get_maintainer_role {
+sub get_subsystem_name {
     my ($index) = @_;
 
-    my $i;
     my $start = find_starting_index($index);
-    my $end = find_ending_index($index);
 
-    my $role = "unknown";
     my $subsystem = $typevalue[$start];
     if (length($subsystem) > 20) {
 	$subsystem = substr($subsystem, 0, 17);
 	$subsystem =~ s/\s*$//;
 	$subsystem = $subsystem . "...";
     }
+    return $subsystem;
+}
+
+sub get_maintainer_role {
+    my ($index) = @_;
+
+    my $i;
+    my $start = find_starting_index($index);
+    my $end = find_ending_index($index);
+
+    my $role = "unknown";
+    my $subsystem = get_subsystem_name($index);
 
     for ($i = $start + 1; $i < $end; $i++) {
 	my $tv = $typevalue[$i];
@@ -940,16 +953,7 @@ sub get_maintainer_role {
 sub get_list_role {
     my ($index) = @_;
 
-    my $i;
-    my $start = find_starting_index($index);
-    my $end = find_ending_index($index);
-
-    my $subsystem = $typevalue[$start];
-    if (length($subsystem) > 20) {
-	$subsystem = substr($subsystem, 0, 17);
-	$subsystem =~ s/\s*$//;
-	$subsystem = $subsystem . "...";
-    }
+    my $subsystem = get_subsystem_name($index);
 
     if ($subsystem eq "THE REST") {
 	$subsystem = "";
@@ -1023,6 +1027,23 @@ sub add_categories {
 		    my $role = get_maintainer_role($i);
 		    push_email_addresses($pvalue, $role);
 		}
+	    } elsif ($ptype eq "R") {
+		my ($name, $address) = parse_email($pvalue);
+		if ($name eq "") {
+		    if ($i > 0) {
+			my $tv = $typevalue[$i - 1];
+			if ($tv =~ m/^(.):\s*(.*)/) {
+			    if ($1 eq "P") {
+				$name = $2;
+				$pvalue = format_email($name, $address, $email_usename);
+			    }
+			}
+		    }
+		}
+		if ($email_reviewer) {
+		    my $subsystem = get_subsystem_name($i);
+		    push_email_addresses($pvalue, "reviewer:$subsystem");
+		}
 	    } elsif ($ptype eq "T") {
 		push(@scm, $pvalue);
 	    } elsif ($ptype eq "W") {
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index eccb88a4e8..860ffb27f2 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -70,6 +70,9 @@ import json
 import ast
 import readline
 import sys
+import os
+import errno
+import atexit
 
 class QMPCompleter(list):
     def complete(self, text, state):
@@ -109,6 +112,8 @@ class QMPShell(qmp.QEMUMonitorProtocol):
         self._pretty = pretty
         self._transmode = False
         self._actions = list()
+        self._histfile = os.path.join(os.path.expanduser('~'),
+                                      '.qmp-shell_history')
 
     def __get_address(self, arg):
         """
@@ -126,17 +131,36 @@ class QMPShell(qmp.QEMUMonitorProtocol):
         return arg
 
     def _fill_completion(self):
-        for cmd in self.cmd('query-commands')['return']:
+        cmds = self.cmd('query-commands')
+        if cmds.has_key('error'):
+            return
+        for cmd in cmds['return']:
             self._completer.append(cmd['name'])
 
     def __completer_setup(self):
         self._completer = QMPCompleter()
         self._fill_completion()
+        readline.set_history_length(1024)
         readline.set_completer(self._completer.complete)
         readline.parse_and_bind("tab: complete")
         # XXX: default delimiters conflict with some command names (eg. query-),
         # clearing everything as it doesn't seem to matter
         readline.set_completer_delims('')
+        try:
+            readline.read_history_file(self._histfile)
+        except Exception as e:
+            if isinstance(e, IOError) and e.errno == errno.ENOENT:
+                # File not found. No problem.
+                pass
+            else:
+                print "Failed to read history '%s'; %s" % (self._histfile, e)
+        atexit.register(self.__save_history)
+
+    def __save_history(self):
+        try:
+            readline.write_history_file(self._histfile)
+        except Exception as e:
+            print "Failed to save history file '%s'; %s" % (self._histfile, e)
 
     def __parse_value(self, val):
         try:
@@ -256,12 +280,15 @@ class QMPShell(qmp.QEMUMonitorProtocol):
         self._print(resp)
         return True
 
-    def connect(self):
-        self._greeting = qmp.QEMUMonitorProtocol.connect(self)
+    def connect(self, negotiate):
+        self._greeting = qmp.QEMUMonitorProtocol.connect(self, negotiate)
         self.__completer_setup()
 
     def show_banner(self, msg='Welcome to the QMP low-level shell!'):
         print msg
+        if not self._greeting:
+            print 'Connected'
+            return
         version = self._greeting['QMP']['version']['qemu']
         print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
 
@@ -369,7 +396,11 @@ def die(msg):
 def fail_cmdline(option=None):
     if option:
         sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
-    sys.stderr.write('qemu-shell [ -v ] [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n')
+    sys.stderr.write('qmp-shell [ -v ] [ -p ] [ -H ] [ -N ] < UNIX socket path> | < TCP address:port >\n')
+    sys.stderr.write('    -v     Verbose (echo command sent and received)\n')
+    sys.stderr.write('    -p     Pretty-print JSON\n')
+    sys.stderr.write('    -H     Use HMP interface\n')
+    sys.stderr.write('    -N     Skip negotiate (for qemu-ga)\n')
     sys.exit(1)
 
 def main():
@@ -378,6 +409,7 @@ def main():
     hmp = False
     pretty = False
     verbose = False
+    negotiate = True
 
     try:
         for arg in sys.argv[1:]:
@@ -387,6 +419,8 @@ def main():
                 hmp = True
             elif arg == "-p":
                 pretty = True
+            elif arg == "-N":
+                negotiate = False
             elif arg == "-v":
                 verbose = True
             else:
@@ -404,7 +438,7 @@ def main():
         die('bad port number in command-line')
 
     try:
-        qemu.connect()
+        qemu.connect(negotiate)
     except qmp.QMPConnectError:
         die('Didn\'t get QMP greeting message')
     except qmp.QMPCapabilitiesError:
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
index 365446fa53..1ffbc1dc40 100644
--- a/scripts/tracetool/__init__.py
+++ b/scripts/tracetool/__init__.py
@@ -191,6 +191,10 @@ class Event(object):
         self.event_trans = event_trans
         self.event_exec = event_exec
 
+        if len(args) > 10:
+            raise ValueError("Event '%s' has more than maximum permitted "
+                             "argument count" % name)
+
         if orig is None:
             self.original = weakref.ref(self)
         else:
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 13c0985f11..7e87031fad 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -2577,6 +2577,15 @@ out:
     return ret;
 }
 
+static gchar *x86_gdb_arch_name(CPUState *cs)
+{
+#ifdef TARGET_X86_64
+    return g_strdup("i386:x86-64");
+#else
+    return g_strdup("i386");
+#endif
+}
+
 X86CPU *cpu_x86_init(const char *cpu_model)
 {
     return X86_CPU(cpu_generic_init(TYPE_X86_CPU, cpu_model));
@@ -4056,10 +4065,14 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
     cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote;
     cc->vmsd = &vmstate_x86_cpu;
 #endif
-    /* CPU_NB_REGS * 2 = general regs + xmm regs
-     * 25 = eip, eflags, 6 seg regs, st[0-7], fctrl,...,fop, mxcsr.
-     */
-    cc->gdb_num_core_regs = CPU_NB_REGS * 2 + 25;
+    cc->gdb_arch_name = x86_gdb_arch_name;
+#ifdef TARGET_X86_64
+    cc->gdb_core_xml_file = "i386-64bit-core.xml";
+    cc->gdb_num_core_regs = 40;
+#else
+    cc->gdb_core_xml_file = "i386-32bit-core.xml";
+    cc->gdb_num_core_regs = 32;
+#endif
 #ifndef CONFIG_USER_ONLY
     cc->debug_excp_handler = breakpoint_handler;
 #endif
diff --git a/target/i386/hax-mem.c b/target/i386/hax-mem.c
index 2884040021..af090343f3 100644
--- a/target/i386/hax-mem.c
+++ b/target/i386/hax-mem.c
@@ -106,10 +106,10 @@ static void hax_update_mapping(uint64_t start_pa, uint32_t size,
                                uint64_t host_va, uint8_t flags)
 {
     uint64_t end_pa = start_pa + size;
-    uint32_t chunk_sz;
     HAXMapping *entry, *next;
 
     QTAILQ_FOREACH_SAFE(entry, &mappings, entry, next) {
+        uint32_t chunk_sz;
         if (start_pa >= entry->start_pa + entry->size) {
             continue;
         }
@@ -121,7 +121,16 @@ static void hax_update_mapping(uint64_t start_pa, uint32_t size,
             start_pa += chunk_sz;
             host_va += chunk_sz;
             size -= chunk_sz;
+        } else if (start_pa > entry->start_pa) {
+            /* split the existing chunk at start_pa */
+            chunk_sz = start_pa - entry->start_pa;
+            hax_insert_mapping_before(entry, entry->start_pa, chunk_sz,
+                                      entry->host_va, entry->flags);
+            entry->start_pa += chunk_sz;
+            entry->host_va += chunk_sz;
+            entry->size -= chunk_sz;
         }
+        /* now start_pa == entry->start_pa */
         chunk_sz = MIN(size, entry->size);
         if (chunk_sz) {
             bool nop = hax_mapping_is_opposite(entry, host_va, flags);
@@ -165,8 +174,14 @@ static void hax_process_section(MemoryRegionSection *section, uint8_t flags)
     unsigned int delta;
     uint64_t host_va;
 
-    /* We only care about RAM pages */
+    /* We only care about RAM and ROM regions */
     if (!memory_region_is_ram(mr)) {
+        if (memory_region_is_romd(mr)) {
+            /* HAXM kernel module does not support ROMD yet  */
+            fprintf(stderr, "%s: Warning: Ignoring ROMD region 0x%016" PRIx64
+                    "->0x%016" PRIx64 "\n", __func__, start_pa,
+                    start_pa + size);
+        }
         return;
     }
 
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
index 7fd2b9a216..1d6330cbcc 100644
--- a/target/openrisc/cpu.c
+++ b/target/openrisc/cpu.c
@@ -51,8 +51,8 @@ static void openrisc_cpu_reset(CPUState *s)
     cpu->env.lock_addr = -1;
     s->exception_index = -1;
 
-    cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP;
-    cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S;
+    cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP |
+                   UPR_PMP;
     cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) | (DMMUCFGR_NTS & (6 << 2));
     cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) | (IMMUCFGR_NTS & (6 << 2));
 
@@ -65,12 +65,6 @@ static void openrisc_cpu_reset(CPUState *s)
 #endif
 }
 
-static inline void set_feature(OpenRISCCPU *cpu, int feature)
-{
-    cpu->feature |= feature;
-    cpu->env.cpucfgr = cpu->feature;
-}
-
 static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     CPUState *cs = CPU(dev);
@@ -132,15 +126,15 @@ static void or1200_initfn(Object *obj)
 {
     OpenRISCCPU *cpu = OPENRISC_CPU(obj);
 
-    set_feature(cpu, OPENRISC_FEATURE_OB32S);
-    set_feature(cpu, OPENRISC_FEATURE_OF32S);
+    cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_OF32S |
+                       CPUCFGR_EVBARP;
 }
 
 static void openrisc_any_initfn(Object *obj)
 {
     OpenRISCCPU *cpu = OPENRISC_CPU(obj);
 
-    set_feature(cpu, OPENRISC_FEATURE_OB32S);
+    cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_EVBARP;
 }
 
 typedef struct OpenRISCCPUInfo {
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index 418a0e6960..2721432c4f 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -111,6 +111,11 @@ enum {
     CPUCFGR_OF32S = (1 << 7),
     CPUCFGR_OF64S = (1 << 8),
     CPUCFGR_OV64S = (1 << 9),
+    /* CPUCFGR_ND = (1 << 10), */
+    /* CPUCFGR_AVRP = (1 << 11), */
+    CPUCFGR_EVBARP = (1 << 12),
+    /* CPUCFGR_ISRP = (1 << 13), */
+    /* CPUCFGR_AECSRP = (1 << 14), */
 };
 
 /* DMMU configure register */
@@ -135,6 +140,15 @@ enum {
     IMMUCFGR_HTR = (1 << 11),
 };
 
+/* Power management register */
+enum {
+    PMR_SDF = (15 << 0),
+    PMR_DME = (1 << 4),
+    PMR_SME = (1 << 5),
+    PMR_DCGE = (1 << 6),
+    PMR_SUME = (1 << 7),
+};
+
 /* Float point control status register */
 enum {
     FPCSR_FPEE = 1,
@@ -191,17 +205,6 @@ enum {
     SR_SCE = (1 << 17),
 };
 
-/* OpenRISC Hardware Capabilities */
-enum {
-    OPENRISC_FEATURE_NSGF = (15 << 0),
-    OPENRISC_FEATURE_CGF = (1 << 4),
-    OPENRISC_FEATURE_OB32S = (1 << 5),
-    OPENRISC_FEATURE_OB64S = (1 << 6),
-    OPENRISC_FEATURE_OF32S = (1 << 7),
-    OPENRISC_FEATURE_OF64S = (1 << 8),
-    OPENRISC_FEATURE_OV64S = (1 << 9),
-};
-
 /* Tick Timer Mode Register */
 enum {
     TTMR_TP = (0xfffffff),
@@ -269,7 +272,8 @@ typedef struct CPUOpenRISCTLBContext {
 #endif
 
 typedef struct CPUOpenRISCState {
-    target_ulong gpr[32];     /* General registers */
+    target_ulong shadow_gpr[16][32]; /* Shadow registers */
+
     target_ulong pc;          /* Program counter */
     target_ulong ppc;         /* Prev PC */
     target_ulong jmp_pc;      /* Jump PC */
@@ -285,10 +289,11 @@ typedef struct CPUOpenRISCState {
     uint32_t sr;              /* Supervisor register, without SR_{F,CY,OV} */
     uint32_t vr;              /* Version register */
     uint32_t upr;             /* Unit presence register */
-    uint32_t cpucfgr;         /* CPU configure register */
     uint32_t dmmucfgr;        /* DMMU configure register */
     uint32_t immucfgr;        /* IMMU configure register */
     uint32_t esr;             /* Exception supervisor register */
+    uint32_t evbar;           /* Exception vector base address register */
+    uint32_t pmr;             /* Power Management Register */
     uint32_t fpcsr;           /* Float register */
     float_status fp_status;
 
@@ -303,6 +308,8 @@ typedef struct CPUOpenRISCState {
     CPU_COMMON
 
     /* Fields from here on are preserved across CPU reset. */
+    uint32_t cpucfgr;         /* CPU configure register */
+
 #ifndef CONFIG_USER_ONLY
     CPUOpenRISCTLBContext * tlb;
 
@@ -329,7 +336,6 @@ typedef struct OpenRISCCPU {
 
     CPUOpenRISCState env;
 
-    uint32_t feature;       /* CPU Capabilities */
 } OpenRISCCPU;
 
 static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env)
@@ -392,6 +398,16 @@ int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
 #define TB_FLAGS_R0_0  2
 #define TB_FLAGS_OVE   SR_OVE
 
+static inline uint32_t cpu_get_gpr(const CPUOpenRISCState *env, int i)
+{
+    return env->shadow_gpr[0][i];
+}
+
+static inline void cpu_set_gpr(CPUOpenRISCState *env, int i, uint32_t val)
+{
+    env->shadow_gpr[0][i] = val;
+}
+
 static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env,
                                         target_ulong *pc,
                                         target_ulong *cs_base, uint32_t *flags)
@@ -399,7 +415,7 @@ static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env,
     *pc = env->pc;
     *cs_base = 0;
     *flags = (env->dflag
-              | (env->gpr[0] == 0 ? TB_FLAGS_R0_0 : 0)
+              | (cpu_get_gpr(env, 0) == 0 ? TB_FLAGS_R0_0 : 0)
               | (env->sr & SR_OVE));
 }
 
diff --git a/target/openrisc/gdbstub.c b/target/openrisc/gdbstub.c
index b18c7e9f05..f9af6507f3 100644
--- a/target/openrisc/gdbstub.c
+++ b/target/openrisc/gdbstub.c
@@ -28,7 +28,7 @@ int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
     CPUOpenRISCState *env = &cpu->env;
 
     if (n < 32) {
-        return gdb_get_reg32(mem_buf, env->gpr[n]);
+        return gdb_get_reg32(mem_buf, cpu_get_gpr(env, n));
     } else {
         switch (n) {
         case 32:    /* PPC */
@@ -61,7 +61,7 @@ int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
     tmp = ldl_p(mem_buf);
 
     if (n < 32) {
-        env->gpr[n] = tmp;
+        cpu_set_gpr(env, n, tmp);
     } else {
         switch (n) {
         case 32: /* PPC */
diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c
index a2eec6fb32..3959671c59 100644
--- a/target/openrisc/interrupt.c
+++ b/target/openrisc/interrupt.c
@@ -60,12 +60,21 @@ void openrisc_cpu_do_interrupt(CPUState *cs)
     env->sr |= SR_SM;
     env->sr &= ~SR_IEE;
     env->sr &= ~SR_TEE;
+    env->pmr &= ~PMR_DME;
+    env->pmr &= ~PMR_SME;
     env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
     env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
     env->lock_addr = -1;
 
     if (cs->exception_index > 0 && cs->exception_index < EXCP_NR) {
-        env->pc = (cs->exception_index << 8);
+        hwaddr vect_pc = cs->exception_index << 8;
+        if (env->cpucfgr & CPUCFGR_EVBARP) {
+            vect_pc |= env->evbar;
+        }
+        if (env->sr & SR_EPH) {
+            vect_pc |= 0xf0000000;
+        }
+        env->pc = vect_pc;
     } else {
         cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
     }
diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c
index 686eaa30c9..a20cce705d 100644
--- a/target/openrisc/machine.c
+++ b/target/openrisc/machine.c
@@ -24,6 +24,63 @@
 #include "hw/boards.h"
 #include "migration/cpu.h"
 
+static int env_post_load(void *opaque, int version_id)
+{
+    CPUOpenRISCState *env = opaque;
+
+    /* Restore MMU handlers */
+    if (env->sr & SR_DME) {
+        env->tlb->cpu_openrisc_map_address_data =
+            &cpu_openrisc_get_phys_data;
+    } else {
+        env->tlb->cpu_openrisc_map_address_data =
+            &cpu_openrisc_get_phys_nommu;
+    }
+
+    if (env->sr & SR_IME) {
+        env->tlb->cpu_openrisc_map_address_code =
+            &cpu_openrisc_get_phys_code;
+    } else {
+        env->tlb->cpu_openrisc_map_address_code =
+            &cpu_openrisc_get_phys_nommu;
+    }
+
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_tlb_entry = {
+    .name = "tlb_entry",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINTTL(mr, OpenRISCTLBEntry),
+        VMSTATE_UINTTL(tr, OpenRISCTLBEntry),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_cpu_tlb = {
+    .name = "cpu_tlb",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT_2DARRAY(itlb, CPUOpenRISCTLBContext,
+                             ITLB_WAYS, ITLB_SIZE, 0,
+                             vmstate_tlb_entry, OpenRISCTLBEntry),
+        VMSTATE_STRUCT_2DARRAY(dtlb, CPUOpenRISCTLBContext,
+                             DTLB_WAYS, DTLB_SIZE, 0,
+                             vmstate_tlb_entry, OpenRISCTLBEntry),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+#define VMSTATE_CPU_TLB(_f, _s)                             \
+    VMSTATE_STRUCT_POINTER(_f, _s, vmstate_cpu_tlb, CPUOpenRISCTLBContext)
+
+
 static int get_sr(QEMUFile *f, void *opaque, size_t size, VMStateField *field)
 {
     CPUOpenRISCState *env = opaque;
@@ -47,10 +104,11 @@ static const VMStateInfo vmstate_sr = {
 
 static const VMStateDescription vmstate_env = {
     .name = "env",
-    .version_id = 4,
-    .minimum_version_id = 4,
+    .version_id = 6,
+    .minimum_version_id = 6,
+    .post_load = env_post_load,
     .fields = (VMStateField[]) {
-        VMSTATE_UINTTL_ARRAY(gpr, CPUOpenRISCState, 32),
+        VMSTATE_UINTTL_2DARRAY(shadow_gpr, CPUOpenRISCState, 16, 32),
         VMSTATE_UINTTL(pc, CPUOpenRISCState),
         VMSTATE_UINTTL(ppc, CPUOpenRISCState),
         VMSTATE_UINTTL(jmp_pc, CPUOpenRISCState),
@@ -79,9 +137,21 @@ static const VMStateDescription vmstate_env = {
         VMSTATE_UINT32(cpucfgr, CPUOpenRISCState),
         VMSTATE_UINT32(dmmucfgr, CPUOpenRISCState),
         VMSTATE_UINT32(immucfgr, CPUOpenRISCState),
+        VMSTATE_UINT32(evbar, CPUOpenRISCState),
+        VMSTATE_UINT32(pmr, CPUOpenRISCState),
         VMSTATE_UINT32(esr, CPUOpenRISCState),
         VMSTATE_UINT32(fpcsr, CPUOpenRISCState),
         VMSTATE_UINT64(mac, CPUOpenRISCState),
+
+        VMSTATE_CPU_TLB(tlb, CPUOpenRISCState),
+
+        VMSTATE_TIMER_PTR(timer, CPUOpenRISCState),
+        VMSTATE_UINT32(ttmr, CPUOpenRISCState),
+        VMSTATE_UINT32(ttcr, CPUOpenRISCState),
+
+        VMSTATE_UINT32(picmr, CPUOpenRISCState),
+        VMSTATE_UINT32(picsr, CPUOpenRISCState),
+
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c
index 56b11d3d68..ce2a29dd1a 100644
--- a/target/openrisc/mmu.c
+++ b/target/openrisc/mmu.c
@@ -124,7 +124,7 @@ static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
 {
     int ret = TLBRET_MATCH;
 
-    if (rw == 2) {    /* ITLB */
+    if (rw == MMU_INST_FETCH) {    /* ITLB */
        *physical = 0;
         ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
                                                           prot, address, rw);
@@ -221,12 +221,28 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
     OpenRISCCPU *cpu = OPENRISC_CPU(cs);
     hwaddr phys_addr;
     int prot;
+    int miss;
 
-    if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
-        return -1;
+    /* Check memory for any kind of address, since during debug the
+       gdb can ask for anything, check data tlb for address */
+    miss = cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0);
+
+    /* Check instruction tlb */
+    if (miss) {
+        miss = cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr,
+                                          MMU_INST_FETCH);
+    }
+
+    /* Last, fall back to a plain address */
+    if (miss) {
+        miss = cpu_openrisc_get_phys_nommu(cpu, &phys_addr, &prot, addr, 0);
     }
 
-    return phys_addr;
+    if (miss) {
+        return -1;
+    } else {
+        return phys_addr;
+    }
 }
 
 void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c
index 60c3193656..abdef5d6a5 100644
--- a/target/openrisc/sys_helper.c
+++ b/target/openrisc/sys_helper.c
@@ -22,6 +22,7 @@
 #include "cpu.h"
 #include "exec/exec-all.h"
 #include "exec/helper-proto.h"
+#include "exception.h"
 
 #define TO_SPR(group, number) (((group) << 11) + (number))
 
@@ -39,6 +40,10 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
         env->vr = rb;
         break;
 
+    case TO_SPR(0, 11): /* EVBAR */
+        env->evbar = rb;
+        break;
+
     case TO_SPR(0, 16): /* NPC */
         cpu_restore_state(cs, GETPC());
         /* ??? Mirror or1ksim in not trashing delayed branch state
@@ -88,6 +93,11 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
     case TO_SPR(0, 64): /* ESR */
         env->esr = rb;
         break;
+
+    case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */
+        idx = (spr - 1024);
+        env->shadow_gpr[idx / 32][idx % 32] = rb;
+
     case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
         idx = spr - TO_SPR(1, 512);
         if (!(rb & 1)) {
@@ -132,6 +142,15 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
     case TO_SPR(5, 2):  /* MACHI */
         env->mac = deposit64(env->mac, 32, 32, rb);
         break;
+    case TO_SPR(8, 0):  /* PMR */
+        env->pmr = rb;
+        if (env->pmr & PMR_DME || env->pmr & PMR_SME) {
+            cpu_restore_state(cs, GETPC());
+            env->pc += 4;
+            cs->halted = 1;
+            raise_exception(cpu, EXCP_HALTED);
+        }
+        break;
     case TO_SPR(9, 0):  /* PICMR */
         env->picmr |= rb;
         break;
@@ -206,6 +225,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
     case TO_SPR(0, 4): /* IMMUCFGR */
         return env->immucfgr;
 
+    case TO_SPR(0, 11): /* EVBAR */
+        return env->evbar;
+
     case TO_SPR(0, 16): /* NPC (equals PC) */
         cpu_restore_state(cs, GETPC());
         return env->pc;
@@ -226,6 +248,16 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
     case TO_SPR(0, 64): /* ESR */
         return env->esr;
 
+    case TO_SPR(0, 128): /* COREID */
+        return 0;
+
+    case TO_SPR(0, 129): /* NUMCORES */
+        return 1;
+
+    case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */
+        idx = (spr - 1024);
+        return env->shadow_gpr[idx / 32][idx % 32];
+
     case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
         idx = spr - TO_SPR(1, 512);
         return env->tlb->dtlb[0][idx].mr;
@@ -265,6 +297,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
         return env->mac >> 32;
         break;
 
+    case TO_SPR(8, 0):  /* PMR */
+        return env->pmr;
+
     case TO_SPR(9, 0):  /* PICMR */
         return env->picmr;
 
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index 7c4cbf205f..e49518e893 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -107,7 +107,8 @@ void openrisc_translate_init(void)
                                      "mac");
     for (i = 0; i < 32; i++) {
         cpu_R[i] = tcg_global_mem_new(cpu_env,
-                                      offsetof(CPUOpenRISCState, gpr[i]),
+                                      offsetof(CPUOpenRISCState,
+                                               shadow_gpr[0][i]),
                                       regnames[i]);
     }
     cpu_R0 = cpu_R[0];
@@ -1662,7 +1663,7 @@ void openrisc_cpu_dump_state(CPUState *cs, FILE *f,
 
     cpu_fprintf(f, "PC=%08x\n", env->pc);
     for (i = 0; i < 32; ++i) {
-        cpu_fprintf(f, "R%02d=%08x%c", i, env->gpr[i],
+        cpu_fprintf(f, "R%02d=%08x%c", i, cpu_get_gpr(env, i),
                     (i % 4) == 3 ? '\n' : ' ');
     }
 }
diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c
index ce461cc905..8d27363b07 100644
--- a/target/s390x/cpu_models.c
+++ b/target/s390x/cpu_models.c
@@ -376,12 +376,12 @@ static void cpu_model_from_info(S390CPUModel *model, const CpuModelInfo *info,
 
 static void qdict_add_disabled_feat(const char *name, void *opaque)
 {
-    qdict_put(opaque, name, qbool_from_bool(false));
+    qdict_put_bool(opaque, name, false);
 }
 
 static void qdict_add_enabled_feat(const char *name, void *opaque)
 {
-    qdict_put(opaque, name, qbool_from_bool(true));
+    qdict_put_bool(opaque, name, true);
 }
 
 /* convert S390CPUDef into a static CpuModelInfo */
diff --git a/tcg/mips/tcg-target.inc.c b/tcg/mips/tcg-target.inc.c
index 01ac7b2c81..2a7e1c7f5b 100644
--- a/tcg/mips/tcg-target.inc.c
+++ b/tcg/mips/tcg-target.inc.c
@@ -2093,11 +2093,11 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
                          args[3] + args[4] - 1, args[3]);
         break;
     case INDEX_op_extract_i32:
-        tcg_out_opc_bf(s, OPC_EXT, a0, a1, a2 + args[3] - 1, a2);
+        tcg_out_opc_bf(s, OPC_EXT, a0, a1, args[3] - 1, a2);
         break;
     case INDEX_op_extract_i64:
         tcg_out_opc_bf64(s, OPC_DEXT, OPC_DEXTM, OPC_DEXTU, a0, a1,
-                         a2 + args[3] - 1, a2);
+                         args[3] - 1, a2);
         break;
 
     case INDEX_op_brcond_i32:
diff --git a/tests/acpi-utils.h b/tests/acpi-utils.h
index 348e4d7931..f8d87236c6 100644
--- a/tests/acpi-utils.h
+++ b/tests/acpi-utils.h
@@ -87,6 +87,16 @@ typedef struct {
     g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \
 } while (0)
 
+#define ACPI_READ_GENERIC_ADDRESS(field, addr)       \
+    do {                                             \
+        ACPI_READ_FIELD((field).space_id, addr);     \
+        ACPI_READ_FIELD((field).bit_width, addr);    \
+        ACPI_READ_FIELD((field).bit_offset, addr);   \
+        ACPI_READ_FIELD((field).access_width, addr); \
+        ACPI_READ_FIELD((field).address, addr);      \
+    } while (0);
+
+
 uint8_t acpi_calc_checksum(const uint8_t *data, int len);
 uint32_t acpi_find_rsdp_address(void);
 void acpi_parse_rsdp_table(uint32_t addr, AcpiRsdpDescriptor *rsdp_table);
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 88dbf97853..9c96a67053 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -29,7 +29,7 @@ typedef struct {
     uint32_t rsdp_addr;
     AcpiRsdpDescriptor rsdp_table;
     AcpiRsdtDescriptorRev1 rsdt_table;
-    AcpiFadtDescriptorRev1 fadt_table;
+    AcpiFadtDescriptorRev3 fadt_table;
     AcpiFacsDescriptorRev1 facs_table;
     uint32_t *rsdt_tables_addr;
     int rsdt_tables_nr;
@@ -126,7 +126,7 @@ static void test_acpi_rsdt_table(test_data *data)
 
 static void test_acpi_fadt_table(test_data *data)
 {
-    AcpiFadtDescriptorRev1 *fadt_table = &data->fadt_table;
+    AcpiFadtDescriptorRev3 *fadt_table = &data->fadt_table;
     uint32_t addr;
 
     /* FADT table comes first */
@@ -168,10 +168,23 @@ static void test_acpi_fadt_table(test_data *data)
     ACPI_READ_FIELD(fadt_table->day_alrm, addr);
     ACPI_READ_FIELD(fadt_table->mon_alrm, addr);
     ACPI_READ_FIELD(fadt_table->century, addr);
-    ACPI_READ_FIELD(fadt_table->reserved4, addr);
-    ACPI_READ_FIELD(fadt_table->reserved4a, addr);
-    ACPI_READ_FIELD(fadt_table->reserved4b, addr);
+    ACPI_READ_FIELD(fadt_table->boot_flags, addr);
+    ACPI_READ_FIELD(fadt_table->reserved, addr);
     ACPI_READ_FIELD(fadt_table->flags, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->reset_register, addr);
+    ACPI_READ_FIELD(fadt_table->reset_value, addr);
+    ACPI_READ_FIELD(fadt_table->arm_boot_flags, addr);
+    ACPI_READ_FIELD(fadt_table->minor_revision, addr);
+    ACPI_READ_FIELD(fadt_table->Xfacs, addr);
+    ACPI_READ_FIELD(fadt_table->Xdsdt, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1a_event_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1b_event_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1a_control_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm1b_control_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm2_control_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xpm_timer_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xgpe0_block, addr);
+    ACPI_READ_GENERIC_ADDRESS(fadt_table->xgpe1_block, addr);
 
     ACPI_ASSERT_CMP(fadt_table->signature, "FACP");
     g_assert(!acpi_calc_checksum((uint8_t *)fadt_table, fadt_table->length));
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
index 81162ee572..be8d81f07b 100644
--- a/tests/check-qdict.c
+++ b/tests/check-qdict.c
@@ -47,7 +47,7 @@ static void qdict_put_obj_test(void)
     qdict = qdict_new();
 
     // key "" will have tdb hash 12345
-    qdict_put_obj(qdict, "", QOBJECT(qint_from_int(num)));
+    qdict_put_int(qdict, "", num);
 
     g_assert(qdict_size(qdict) == 1);
     ent = QLIST_FIRST(&qdict->table[12345 % QDICT_BUCKET_MAX]);
@@ -66,8 +66,8 @@ static void qdict_destroy_simple_test(void)
     QDict *qdict;
 
     qdict = qdict_new();
-    qdict_put_obj(qdict, "num", QOBJECT(qint_from_int(0)));
-    qdict_put_obj(qdict, "str", QOBJECT(qstring_from_str("foo")));
+    qdict_put_int(qdict, "num", 0);
+    qdict_put_str(qdict, "str", "foo");
 
     QDECREF(qdict);
 }
@@ -80,7 +80,7 @@ static void qdict_get_test(void)
     const char *key = "test";
     QDict *tests_dict = qdict_new();
 
-    qdict_put(tests_dict, key, qint_from_int(value));
+    qdict_put_int(tests_dict, key, value);
 
     obj = qdict_get(tests_dict, key);
     g_assert(obj != NULL);
@@ -98,7 +98,7 @@ static void qdict_get_int_test(void)
     const char *key = "int";
     QDict *tests_dict = qdict_new();
 
-    qdict_put(tests_dict, key, qint_from_int(value));
+    qdict_put_int(tests_dict, key, value);
 
     ret = qdict_get_int(tests_dict, key);
     g_assert(ret == value);
@@ -113,7 +113,7 @@ static void qdict_get_try_int_test(void)
     const char *key = "int";
     QDict *tests_dict = qdict_new();
 
-    qdict_put(tests_dict, key, qint_from_int(value));
+    qdict_put_int(tests_dict, key, value);
 
     ret = qdict_get_try_int(tests_dict, key, 0);
     g_assert(ret == value);
@@ -128,7 +128,7 @@ static void qdict_get_str_test(void)
     const char *str = "string";
     QDict *tests_dict = qdict_new();
 
-    qdict_put(tests_dict, key, qstring_from_str(str));
+    qdict_put_str(tests_dict, key, str);
 
     p = qdict_get_str(tests_dict, key);
     g_assert(p != NULL);
@@ -144,7 +144,7 @@ static void qdict_get_try_str_test(void)
     const char *str = "string";
     QDict *tests_dict = qdict_new();
 
-    qdict_put(tests_dict, key, qstring_from_str(str));
+    qdict_put_str(tests_dict, key, str);
 
     p = qdict_get_try_str(tests_dict, key);
     g_assert(p != NULL);
@@ -188,7 +188,7 @@ static void qdict_haskey_test(void)
     const char *key = "test";
     QDict *tests_dict = qdict_new();
 
-    qdict_put(tests_dict, key, qint_from_int(0));
+    qdict_put_int(tests_dict, key, 0);
     g_assert(qdict_haskey(tests_dict, key) == 1);
 
     QDECREF(tests_dict);
@@ -199,7 +199,7 @@ static void qdict_del_test(void)
     const char *key = "key test";
     QDict *tests_dict = qdict_new();
 
-    qdict_put(tests_dict, key, qstring_from_str("foo"));
+    qdict_put_str(tests_dict, key, "foo");
     g_assert(qdict_size(tests_dict) == 1);
 
     qdict_del(tests_dict, key);
@@ -226,9 +226,9 @@ static void qdict_iterapi_test(void)
 
     g_assert(qdict_first(tests_dict) == NULL);
 
-    qdict_put(tests_dict, "key1", qint_from_int(1));
-    qdict_put(tests_dict, "key2", qint_from_int(2));
-    qdict_put(tests_dict, "key3", qint_from_int(3));
+    qdict_put_int(tests_dict, "key1", 1);
+    qdict_put_int(tests_dict, "key2", 2);
+    qdict_put_int(tests_dict, "key3", 3);
 
     count = 0;
     for (ent = qdict_first(tests_dict); ent; ent = qdict_next(tests_dict, ent)){
@@ -294,20 +294,20 @@ static void qdict_flatten_test(void)
      * }
      */
 
-    qdict_put(dict1, "a", qint_from_int(0));
-    qdict_put(dict1, "b", qint_from_int(1));
+    qdict_put_int(dict1, "a", 0);
+    qdict_put_int(dict1, "b", 1);
 
-    qlist_append_obj(list1, QOBJECT(qint_from_int(23)));
-    qlist_append_obj(list1, QOBJECT(qint_from_int(66)));
-    qlist_append_obj(list1, QOBJECT(dict1));
-    qlist_append_obj(list2, QOBJECT(qint_from_int(42)));
-    qlist_append_obj(list2, QOBJECT(list1));
+    qlist_append_int(list1, 23);
+    qlist_append_int(list1, 66);
+    qlist_append(list1, dict1);
+    qlist_append_int(list2, 42);
+    qlist_append(list2, list1);
 
-    qdict_put(dict2, "c", qint_from_int(2));
-    qdict_put(dict2, "d", qint_from_int(3));
-    qdict_put_obj(dict3, "e", QOBJECT(list2));
-    qdict_put_obj(dict3, "f", QOBJECT(dict2));
-    qdict_put(dict3, "g", qint_from_int(4));
+    qdict_put_int(dict2, "c", 2);
+    qdict_put_int(dict2, "d", 3);
+    qdict_put(dict3, "e", list2);
+    qdict_put(dict3, "f", dict2);
+    qdict_put_int(dict3, "g", 4);
 
     qdict_flatten(dict3);
 
@@ -369,12 +369,12 @@ static void qdict_array_split_test(void)
      * This example is given in the comment of qdict_array_split().
      */
 
-    qdict_put(test_dict, "1.x", qint_from_int(0));
-    qdict_put(test_dict, "4.y", qint_from_int(1));
-    qdict_put(test_dict, "0.a", qint_from_int(42));
-    qdict_put(test_dict, "o.o", qint_from_int(7));
-    qdict_put(test_dict, "0.b", qint_from_int(23));
-    qdict_put(test_dict, "2", qint_from_int(66));
+    qdict_put_int(test_dict, "1.x", 0);
+    qdict_put_int(test_dict, "4.y", 1);
+    qdict_put_int(test_dict, "0.a", 42);
+    qdict_put_int(test_dict, "o.o", 7);
+    qdict_put_int(test_dict, "0.b", 23);
+    qdict_put_int(test_dict, "2", 66);
 
     qdict_array_split(test_dict, &test_list);
 
@@ -441,9 +441,9 @@ static void qdict_array_split_test(void)
 
     test_dict = qdict_new();
 
-    qdict_put(test_dict, "0", qint_from_int(42));
-    qdict_put(test_dict, "1", qint_from_int(23));
-    qdict_put(test_dict, "1.x", qint_from_int(84));
+    qdict_put_int(test_dict, "0", 42);
+    qdict_put_int(test_dict, "1", 23);
+    qdict_put_int(test_dict, "1.x", 84);
 
     qdict_array_split(test_dict, &test_list);
 
@@ -472,38 +472,38 @@ static void qdict_array_entries_test(void)
 
     g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
 
-    qdict_put(dict, "bar", qint_from_int(0));
-    qdict_put(dict, "baz.0", qint_from_int(0));
+    qdict_put_int(dict, "bar", 0);
+    qdict_put_int(dict, "baz.0", 0);
     g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 0);
 
-    qdict_put(dict, "foo.1", qint_from_int(0));
+    qdict_put_int(dict, "foo.1", 0);
     g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
-    qdict_put(dict, "foo.0", qint_from_int(0));
+    qdict_put_int(dict, "foo.0", 0);
     g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 2);
-    qdict_put(dict, "foo.bar", qint_from_int(0));
+    qdict_put_int(dict, "foo.bar", 0);
     g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, -EINVAL);
     qdict_del(dict, "foo.bar");
 
-    qdict_put(dict, "foo.2.a", qint_from_int(0));
-    qdict_put(dict, "foo.2.b", qint_from_int(0));
-    qdict_put(dict, "foo.2.c", qint_from_int(0));
+    qdict_put_int(dict, "foo.2.a", 0);
+    qdict_put_int(dict, "foo.2.b", 0);
+    qdict_put_int(dict, "foo.2.c", 0);
     g_assert_cmpint(qdict_array_entries(dict, "foo."), ==, 3);
     g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
 
     QDECREF(dict);
 
     dict = qdict_new();
-    qdict_put(dict, "1", qint_from_int(0));
+    qdict_put_int(dict, "1", 0);
     g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
-    qdict_put(dict, "0", qint_from_int(0));
+    qdict_put_int(dict, "0", 0);
     g_assert_cmpint(qdict_array_entries(dict, ""), ==, 2);
-    qdict_put(dict, "bar", qint_from_int(0));
+    qdict_put_int(dict, "bar", 0);
     g_assert_cmpint(qdict_array_entries(dict, ""), ==, -EINVAL);
     qdict_del(dict, "bar");
 
-    qdict_put(dict, "2.a", qint_from_int(0));
-    qdict_put(dict, "2.b", qint_from_int(0));
-    qdict_put(dict, "2.c", qint_from_int(0));
+    qdict_put_int(dict, "2.a", 0);
+    qdict_put_int(dict, "2.b", 0);
+    qdict_put_int(dict, "2.c", 0);
     g_assert_cmpint(qdict_array_entries(dict, ""), ==, 3);
 
     QDECREF(dict);
@@ -529,7 +529,7 @@ static void qdict_join_test(void)
 
         /* First iteration: Test movement */
         /* Second iteration: Test empty source and non-empty destination */
-        qdict_put(dict2, "foo", qint_from_int(42));
+        qdict_put_int(dict2, "foo", 42);
 
         for (i = 0; i < 2; i++) {
             qdict_join(dict1, dict2, overwrite);
@@ -541,7 +541,7 @@ static void qdict_join_test(void)
         }
 
         /* Test non-empty source and destination without conflict */
-        qdict_put(dict2, "bar", qint_from_int(23));
+        qdict_put_int(dict2, "bar", 23);
 
         qdict_join(dict1, dict2, overwrite);
 
@@ -552,14 +552,14 @@ static void qdict_join_test(void)
         g_assert(qdict_get_int(dict1, "bar") == 23);
 
         /* Test conflict */
-        qdict_put(dict2, "foo", qint_from_int(84));
+        qdict_put_int(dict2, "foo", 84);
 
         qdict_join(dict1, dict2, overwrite);
 
         g_assert(qdict_size(dict1) == 2);
         g_assert(qdict_size(dict2) == !overwrite);
 
-        g_assert(qdict_get_int(dict1, "foo") == overwrite ? 84 : 42);
+        g_assert(qdict_get_int(dict1, "foo") == (overwrite ? 84 : 42));
         g_assert(qdict_get_int(dict1, "bar") == 23);
 
         if (!overwrite) {
@@ -594,15 +594,15 @@ static void qdict_crumple_test_recursive(void)
     QList *rules;
 
     src = qdict_new();
-    qdict_put(src, "vnc.listen.addr", qstring_from_str("127.0.0.1"));
-    qdict_put(src, "vnc.listen.port", qstring_from_str("5901"));
-    qdict_put(src, "vnc.acl.rules.0.match", qstring_from_str("fred"));
-    qdict_put(src, "vnc.acl.rules.0.policy", qstring_from_str("allow"));
-    qdict_put(src, "vnc.acl.rules.1.match", qstring_from_str("bob"));
-    qdict_put(src, "vnc.acl.rules.1.policy", qstring_from_str("deny"));
-    qdict_put(src, "vnc.acl.default", qstring_from_str("deny"));
-    qdict_put(src, "vnc.acl..name", qstring_from_str("acl0"));
-    qdict_put(src, "vnc.acl.rule..name", qstring_from_str("acl0"));
+    qdict_put_str(src, "vnc.listen.addr", "127.0.0.1");
+    qdict_put_str(src, "vnc.listen.port", "5901");
+    qdict_put_str(src, "vnc.acl.rules.0.match", "fred");
+    qdict_put_str(src, "vnc.acl.rules.0.policy", "allow");
+    qdict_put_str(src, "vnc.acl.rules.1.match", "bob");
+    qdict_put_str(src, "vnc.acl.rules.1.policy", "deny");
+    qdict_put_str(src, "vnc.acl.default", "deny");
+    qdict_put_str(src, "vnc.acl..name", "acl0");
+    qdict_put_str(src, "vnc.acl.rule..name", "acl0");
 
     dst = qobject_to_qdict(qdict_crumple(src, &error_abort));
     g_assert(dst);
@@ -669,8 +669,8 @@ static void qdict_crumple_test_bad_inputs(void)
 
     src = qdict_new();
     /* rule.0 can't be both a string and a dict */
-    qdict_put(src, "rule.0", qstring_from_str("fred"));
-    qdict_put(src, "rule.0.policy", qstring_from_str("allow"));
+    qdict_put_str(src, "rule.0", "fred");
+    qdict_put_str(src, "rule.0.policy", "allow");
 
     g_assert(qdict_crumple(src, &error) == NULL);
     g_assert(error != NULL);
@@ -680,8 +680,8 @@ static void qdict_crumple_test_bad_inputs(void)
 
     src = qdict_new();
     /* rule can't be both a list and a dict */
-    qdict_put(src, "rule.0", qstring_from_str("fred"));
-    qdict_put(src, "rule.a", qstring_from_str("allow"));
+    qdict_put_str(src, "rule.0", "fred");
+    qdict_put_str(src, "rule.a", "allow");
 
     g_assert(qdict_crumple(src, &error) == NULL);
     g_assert(error != NULL);
@@ -692,7 +692,7 @@ static void qdict_crumple_test_bad_inputs(void)
     src = qdict_new();
     /* The input should be flat, ie no dicts or lists */
     qdict_put(src, "rule.a", qdict_new());
-    qdict_put(src, "rule.b", qstring_from_str("allow"));
+    qdict_put_str(src, "rule.b", "allow");
 
     g_assert(qdict_crumple(src, &error) == NULL);
     g_assert(error != NULL);
@@ -702,8 +702,8 @@ static void qdict_crumple_test_bad_inputs(void)
 
     src = qdict_new();
     /* List indexes must not have gaps */
-    qdict_put(src, "rule.0", qstring_from_str("deny"));
-    qdict_put(src, "rule.3", qstring_from_str("allow"));
+    qdict_put_str(src, "rule.0", "deny");
+    qdict_put_str(src, "rule.3", "allow");
 
     g_assert(qdict_crumple(src, &error) == NULL);
     g_assert(error != NULL);
@@ -713,8 +713,8 @@ static void qdict_crumple_test_bad_inputs(void)
 
     src = qdict_new();
     /* List indexes must be in %zu format */
-    qdict_put(src, "rule.0", qstring_from_str("deny"));
-    qdict_put(src, "rule.+1", qstring_from_str("allow"));
+    qdict_put_str(src, "rule.0", "deny");
+    qdict_put_str(src, "rule.+1", "allow");
 
     g_assert(qdict_crumple(src, &error) == NULL);
     g_assert(error != NULL);
@@ -733,8 +733,8 @@ static void qdict_put_exists_test(void)
     const char *key = "exists";
     QDict *tests_dict = qdict_new();
 
-    qdict_put(tests_dict, key, qint_from_int(1));
-    qdict_put(tests_dict, key, qint_from_int(2));
+    qdict_put_int(tests_dict, key, 1);
+    qdict_put_int(tests_dict, key, 2);
 
     value = qdict_get_int(tests_dict, key);
     g_assert(value == 2);
diff --git a/tests/check-qlist.c b/tests/check-qlist.c
index e16da5e5c6..4983867c27 100644
--- a/tests/check-qlist.c
+++ b/tests/check-qlist.c
@@ -74,7 +74,7 @@ static void qlist_destroy_test(void)
     qlist = qlist_new();
 
     for (i = 0; i < 42; i++)
-        qlist_append(qlist, qint_from_int(i));
+        qlist_append_int(qlist, i);
 
     QDECREF(qlist);
 }
@@ -103,7 +103,7 @@ static void qlist_iter_test(void)
     qlist = qlist_new();
 
     for (i = 0; i < iter_max; i++)
-        qlist_append(qlist, qint_from_int(i));
+        qlist_append_int(qlist, i);
 
     iter_called = 0;
     qlist_iter(qlist, iter_func, NULL);
diff --git a/tests/device-introspect-test.c b/tests/device-introspect-test.c
index c5637cc406..b1abb2ad89 100644
--- a/tests/device-introspect-test.c
+++ b/tests/device-introspect-test.c
@@ -32,9 +32,9 @@ static QList *qom_list_types(const char *implements, bool abstract)
     QList *ret;
     QDict *args = qdict_new();
 
-    qdict_put(args, "abstract", qbool_from_bool(abstract));
+    qdict_put_bool(args, "abstract", abstract);
     if (implements) {
-        qdict_put(args, "implements", qstring_from_str(implements));
+        qdict_put_str(args, "implements", implements);
     }
     resp = qmp("{'execute': 'qom-list-types',"
                " 'arguments': %p }", args);
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index 738c6b4a5e..325712e0f2 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -298,8 +298,8 @@ static void test_media_insert(void)
 
     /* Insert media in drive. DSKCHK should not be reset until a step pulse
      * is sent. */
-    qmp_discard_response("{'execute':'change', 'arguments':{"
-                         " 'device':'floppy0', 'target': %s, 'arg': 'raw' }}",
+    qmp_discard_response("{'execute':'blockdev-change-medium', 'arguments':{"
+                         " 'id':'floppy0', 'filename': %s, 'format': 'raw' }}",
                          test_image);
 
     dir = inb(FLOPPY_BASE + reg_dir);
@@ -330,7 +330,7 @@ static void test_media_change(void)
     /* Eject the floppy and check that DSKCHG is set. Reading it out doesn't
      * reset the bit. */
     qmp_discard_response("{'execute':'eject', 'arguments':{"
-                         " 'device':'floppy0' }}");
+                         " 'id':'floppy0' }}");
 
     dir = inb(FLOPPY_BASE + reg_dir);
     assert_bit_set(dir, DSKCHG);
@@ -564,7 +564,7 @@ int main(int argc, char **argv)
     /* Run the tests */
     g_test_init(&argc, &argv, NULL);
 
-    qtest_start(NULL);
+    qtest_start("-device floppy,id=floppy0");
     qtest_irq_intercept_in(global_qtest, "ioapic");
     qtest_add_func("/fdc/cmos", test_cmos);
     qtest_add_func("/fdc/no_media_on_start", test_no_media_on_start);
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 512c150266..84ecbd2bd8 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -446,6 +446,14 @@ void qmp_fd_sendv(int fd, const char *fmt, va_list ap)
     va_list ap_copy;
     QObject *qobj;
 
+    /* qobject_from_jsonv() silently eats leading 0xff as invalid
+     * JSON, but we want to test sending them over the wire to force
+     * resyncs */
+    if (*fmt == '\377') {
+        socket_send(fd, fmt, 1);
+        fmt++;
+    }
+
     /* Going through qobject ensures we escape strings properly.
      * This seemingly unnecessary copy is required in case va_list
      * is an array type.
diff --git a/tests/test-char.c b/tests/test-char.c
index da69f110e4..124d0c5439 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -1,18 +1,35 @@
 #include "qemu/osdep.h"
+#include <glib/gstdio.h>
 
 #include "qemu-common.h"
 #include "qemu/config-file.h"
+#include "qemu/sockets.h"
 #include "sysemu/char.h"
 #include "sysemu/sysemu.h"
 #include "qapi/error.h"
+#include "qom/qom-qobject.h"
 #include "qmp-commands.h"
 
+static bool quit;
+
 typedef struct FeHandler {
     int read_count;
     int last_event;
     char read_buf[128];
 } FeHandler;
 
+static void main_loop(void)
+{
+    bool nonblocking;
+    int last_io = 0;
+
+    quit = false;
+    do {
+        nonblocking = last_io > 0;
+        last_io = main_loop_wait(nonblocking);
+    } while (!quit);
+}
+
 static int fe_can_read(void *opaque)
 {
     FeHandler *h = opaque;
@@ -28,6 +45,7 @@ static void fe_read(void *opaque, const uint8_t *buf, int size)
 
     memcpy(h->read_buf + h->read_count, buf, size);
     h->read_count += size;
+    quit = true;
 }
 
 static void fe_event(void *opaque, int event)
@@ -35,9 +53,36 @@ static void fe_event(void *opaque, int event)
     FeHandler *h = opaque;
 
     h->last_event = event;
+    quit = true;
 }
 
 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
+#ifdef _WIN32
+static void char_console_test_subprocess(void)
+{
+    QemuOpts *opts;
+    Chardev *chr;
+
+    opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
+                            1, &error_abort);
+    qemu_opt_set(opts, "backend", "console", &error_abort);
+
+    chr = qemu_chr_new_from_opts(opts, NULL);
+    g_assert_nonnull(chr);
+
+    qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
+
+    qemu_opts_del(opts);
+    object_unparent(OBJECT(chr));
+}
+
+static void char_console_test(void)
+{
+    g_test_trap_subprocess("/char/console/subprocess", 0, 0);
+    g_test_trap_assert_passed();
+    g_test_trap_assert_stdout("CONSOLE");
+}
+#endif
 static void char_stdio_test_subprocess(void)
 {
     Chardev *chr;
@@ -53,7 +98,7 @@ static void char_stdio_test_subprocess(void)
     g_assert_cmpint(ret, ==, 4);
 
     qemu_chr_fe_deinit(&be);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
 }
 
 static void char_stdio_test(void)
@@ -64,7 +109,6 @@ static void char_stdio_test(void)
 }
 #endif
 
-
 static void char_ringbuf_test(void)
 {
     QemuOpts *opts;
@@ -103,7 +147,17 @@ static void char_ringbuf_test(void)
     g_free(data);
 
     qemu_chr_fe_deinit(&be);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
+
+    /* check alias */
+    opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
+                            1, &error_abort);
+    qemu_opt_set(opts, "backend", "memory", &error_abort);
+    qemu_opt_set(opts, "size", "2", &error_abort);
+    chr = qemu_chr_new_from_opts(opts, NULL);
+    g_assert_nonnull(chr);
+    object_unparent(OBJECT(chr));
+    qemu_opts_del(opts);
 }
 
 static void char_mux_test(void)
@@ -179,7 +233,295 @@ static void char_mux_test(void)
 
     qemu_chr_fe_deinit(&chr_be1);
     qemu_chr_fe_deinit(&chr_be2);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
+}
+
+typedef struct SocketIdleData {
+    GMainLoop *loop;
+    Chardev *chr;
+    bool conn_expected;
+    CharBackend *be;
+    CharBackend *client_be;
+} SocketIdleData;
+
+static gboolean char_socket_test_idle(gpointer user_data)
+{
+    SocketIdleData *data = user_data;
+
+    if (object_property_get_bool(OBJECT(data->chr), "connected", NULL)
+        == data->conn_expected) {
+        quit = true;
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+static void socket_read(void *opaque, const uint8_t *buf, int size)
+{
+    SocketIdleData *data = opaque;
+
+    g_assert_cmpint(size, ==, 1);
+    g_assert_cmpint(*buf, ==, 'Z');
+
+    size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
+    g_assert_cmpint(size, ==, 5);
+}
+
+static int socket_can_read(void *opaque)
+{
+    return 10;
+}
+
+static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
+{
+    g_assert_cmpint(size, ==, 5);
+    g_assert(strncmp((char *)buf, "hello", 5) == 0);
+
+    quit = true;
+}
+
+static int socket_can_read_hello(void *opaque)
+{
+    return 10;
+}
+
+static void char_socket_test(void)
+{
+    Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
+    Chardev *chr_client;
+    QObject *addr;
+    QDict *qdict;
+    const char *port;
+    SocketIdleData d = { .chr = chr };
+    CharBackend be;
+    CharBackend client_be;
+    char *tmp;
+
+    d.be = &be;
+    d.client_be = &be;
+
+    g_assert_nonnull(chr);
+    g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
+
+    addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
+    qdict = qobject_to_qdict(addr);
+    port = qdict_get_str(qdict, "port");
+    tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
+    QDECREF(qdict);
+
+    qemu_chr_fe_init(&be, chr, &error_abort);
+    qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read,
+                             NULL, &d, NULL, true);
+
+    chr_client = qemu_chr_new("client", tmp);
+    qemu_chr_fe_init(&client_be, chr_client, &error_abort);
+    qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello,
+                             socket_read_hello,
+                             NULL, &d, NULL, true);
+    g_free(tmp);
+
+    d.conn_expected = true;
+    guint id = g_idle_add(char_socket_test_idle, &d);
+    g_source_set_name_by_id(id, "test-idle");
+    g_assert_cmpint(id, >, 0);
+    main_loop();
+
+    g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
+    g_assert(object_property_get_bool(OBJECT(chr_client),
+                                      "connected", &error_abort));
+
+    qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1);
+    main_loop();
+
+    object_unparent(OBJECT(chr_client));
+
+    d.conn_expected = false;
+    g_idle_add(char_socket_test_idle, &d);
+    main_loop();
+
+    object_unparent(OBJECT(chr));
+}
+
+#ifndef _WIN32
+static void char_pipe_test(void)
+{
+    gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+    gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
+    Chardev *chr;
+    CharBackend be;
+    int ret, fd;
+    char buf[10];
+    FeHandler fe = { 0, };
+
+    in = g_strdup_printf("%s.in", pipe);
+    if (mkfifo(in, 0600) < 0) {
+        abort();
+    }
+    out = g_strdup_printf("%s.out", pipe);
+    if (mkfifo(out, 0600) < 0) {
+        abort();
+    }
+
+    tmp = g_strdup_printf("pipe:%s", pipe);
+    chr = qemu_chr_new("pipe", tmp);
+    g_assert_nonnull(chr);
+    g_free(tmp);
+
+    qemu_chr_fe_init(&be, chr, &error_abort);
+
+    ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
+    g_assert_cmpint(ret, ==, 9);
+
+    fd = open(out, O_RDWR);
+    ret = read(fd, buf, sizeof(buf));
+    g_assert_cmpint(ret, ==, 9);
+    g_assert_cmpstr(buf, ==, "pipe-out");
+    close(fd);
+
+    fd = open(in, O_WRONLY);
+    ret = write(fd, "pipe-in", 8);
+    g_assert_cmpint(ret, ==, 8);
+    close(fd);
+
+    qemu_chr_fe_set_handlers(&be,
+                             fe_can_read,
+                             fe_read,
+                             fe_event,
+                             &fe,
+                             NULL, true);
+
+    main_loop();
+
+    g_assert_cmpint(fe.read_count, ==, 8);
+    g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
+
+    qemu_chr_fe_deinit(&be);
+    object_unparent(OBJECT(chr));
+
+    g_assert(g_unlink(in) == 0);
+    g_assert(g_unlink(out) == 0);
+    g_assert(g_rmdir(tmp_path) == 0);
+    g_free(in);
+    g_free(out);
+    g_free(tmp_path);
+    g_free(pipe);
+}
+#endif
+
+static void char_udp_test(void)
+{
+    struct sockaddr_in addr = { 0, }, other;
+    SocketIdleData d = { 0, };
+    Chardev *chr;
+    CharBackend be;
+    socklen_t alen = sizeof(addr);
+    int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
+    char buf[10];
+    char *tmp;
+
+    g_assert_cmpint(sock, >, 0);
+    addr.sin_family = AF_INET ;
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    addr.sin_port = 0;
+    ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+    g_assert_cmpint(ret, ==, 0);
+    ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
+    g_assert_cmpint(ret, ==, 0);
+
+    tmp = g_strdup_printf("udp:127.0.0.1:%d",
+                          ntohs(addr.sin_port));
+    chr = qemu_chr_new("client", tmp);
+    g_assert_nonnull(chr);
+
+    d.chr = chr;
+    qemu_chr_fe_init(&be, chr, &error_abort);
+    qemu_chr_fe_set_handlers(&be, socket_can_read_hello, socket_read_hello,
+                             NULL, &d, NULL, true);
+    ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
+    g_assert_cmpint(ret, ==, 5);
+
+    alen = sizeof(addr);
+    ret = recvfrom(sock, buf, sizeof(buf), 0,
+                   (struct sockaddr *)&other, &alen);
+    g_assert_cmpint(ret, ==, 5);
+    ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
+    g_assert_cmpint(ret, ==, 5);
+
+    main_loop();
+
+    close(sock);
+    g_free(tmp);
+}
+
+static void char_file_test(void)
+{
+    char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+    char *out = g_build_filename(tmp_path, "out", NULL);
+    char *contents = NULL;
+    ChardevFile file = { .out = out };
+    ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
+                               .u.file.data = &file };
+    Chardev *chr;
+    gsize length;
+    int ret;
+
+    chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
+                           &error_abort);
+    ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
+    g_assert_cmpint(ret, ==, 6);
+    object_unref(OBJECT(chr));
+
+    ret = g_file_get_contents(out, &contents, &length, NULL);
+    g_assert(ret == TRUE);
+    g_assert_cmpint(length, ==, 6);
+    g_assert(strncmp(contents, "hello!", 6) == 0);
+    g_free(contents);
+
+#ifndef _WIN32
+    {
+        CharBackend be;
+        FeHandler fe = { 0, };
+        char *fifo = g_build_filename(tmp_path, "fifo", NULL);
+        int fd;
+
+        if (mkfifo(fifo, 0600) < 0) {
+            abort();
+        }
+
+        fd = open(fifo, O_RDWR);
+        ret = write(fd, "fifo-in", 8);
+        g_assert_cmpint(ret, ==, 8);
+
+        file.in = fifo;
+        file.has_in = true;
+        chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
+                               &error_abort);
+
+        qemu_chr_fe_init(&be, chr, &error_abort);
+        qemu_chr_fe_set_handlers(&be,
+                                 fe_can_read,
+                                 fe_read,
+                                 fe_event,
+                                 &fe, NULL, true);
+
+        main_loop();
+
+        close(fd);
+
+        g_assert_cmpint(fe.read_count, ==, 8);
+        g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
+        qemu_chr_fe_deinit(&be);
+        object_unref(OBJECT(chr));
+        g_unlink(fifo);
+        g_free(fifo);
+    }
+#endif
+
+    g_unlink(out);
+    g_rmdir(tmp_path);
+    g_free(tmp_path);
+    g_free(out);
 }
 
 static void char_null_test(void)
@@ -222,7 +564,7 @@ static void char_null_test(void)
     g_assert_cmpint(ret, ==, 4);
 
     qemu_chr_fe_deinit(&be);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
 }
 
 static void char_invalid_test(void)
@@ -235,6 +577,9 @@ static void char_invalid_test(void)
 
 int main(int argc, char **argv)
 {
+    qemu_init_main_loop(&error_abort);
+    socket_init();
+
     g_test_init(&argc, &argv, NULL);
 
     module_call_init(MODULE_INIT_QOM);
@@ -245,9 +590,19 @@ int main(int argc, char **argv)
     g_test_add_func("/char/ringbuf", char_ringbuf_test);
     g_test_add_func("/char/mux", char_mux_test);
 #ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
+#ifdef _WIN32
+    g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
+    g_test_add_func("/char/console", char_console_test);
+#endif
     g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
     g_test_add_func("/char/stdio", char_stdio_test);
 #endif
+#ifndef _WIN32
+    g_test_add_func("/char/pipe", char_pipe_test);
+#endif
+    g_test_add_func("/char/file", char_file_test);
+    g_test_add_func("/char/socket", char_socket_test);
+    g_test_add_func("/char/udp", char_udp_test);
 
     return g_test_run();
 }
diff --git a/tests/test-crypto-block.c b/tests/test-crypto-block.c
index 85e6603d59..95c4bd5da3 100644
--- a/tests/test-crypto-block.c
+++ b/tests/test-crypto-block.c
@@ -187,10 +187,10 @@ static struct QCryptoBlockTestData {
 
 
 static ssize_t test_block_read_func(QCryptoBlock *block,
-                                    void *opaque,
                                     size_t offset,
                                     uint8_t *buf,
                                     size_t buflen,
+                                    void *opaque,
                                     Error **errp)
 {
     Buffer *header = opaque;
@@ -204,8 +204,8 @@ static ssize_t test_block_read_func(QCryptoBlock *block,
 
 
 static ssize_t test_block_init_func(QCryptoBlock *block,
-                                    void *opaque,
                                     size_t headerlen,
+                                    void *opaque,
                                     Error **errp)
 {
     Buffer *header = opaque;
@@ -219,10 +219,10 @@ static ssize_t test_block_init_func(QCryptoBlock *block,
 
 
 static ssize_t test_block_write_func(QCryptoBlock *block,
-                                     void *opaque,
                                      size_t offset,
                                      const uint8_t *buf,
                                      size_t buflen,
+                                     void *opaque,
                                      Error **errp)
 {
     Buffer *header = opaque;
diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c
index c5c131479c..d357cd2a8e 100644
--- a/tests/test-io-channel-socket.c
+++ b/tests/test-io-channel-socket.c
@@ -125,12 +125,12 @@ static void test_io_channel_setup_sync(SocketAddress *listen_addr,
     lioc = qio_channel_socket_new();
     qio_channel_socket_listen_sync(lioc, listen_addr, &error_abort);
 
-    if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) {
+    if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
         SocketAddress *laddr = qio_channel_socket_get_local_address(
             lioc, &error_abort);
 
-        g_free(connect_addr->u.inet.data->port);
-        connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port);
+        g_free(connect_addr->u.inet.port);
+        connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
 
         qapi_free_SocketAddress(laddr);
     }
@@ -186,12 +186,12 @@ static void test_io_channel_setup_async(SocketAddress *listen_addr,
 
     g_assert(!data.err);
 
-    if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) {
+    if (listen_addr->type == SOCKET_ADDRESS_TYPE_INET) {
         SocketAddress *laddr = qio_channel_socket_get_local_address(
             lioc, &error_abort);
 
-        g_free(connect_addr->u.inet.data->port);
-        connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port);
+        g_free(connect_addr->u.inet.port);
+        connect_addr->u.inet.port = g_strdup(laddr->u.inet.port);
 
         qapi_free_SocketAddress(laddr);
     }
@@ -300,16 +300,14 @@ static void test_io_channel_ipv4(bool async)
     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
 
-    listen_addr->type = SOCKET_ADDRESS_KIND_INET;
-    listen_addr->u.inet.data = g_new(InetSocketAddress, 1);
-    *listen_addr->u.inet.data = (InetSocketAddress) {
+    listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
+    listen_addr->u.inet = (InetSocketAddress) {
         .host = g_strdup("127.0.0.1"),
         .port = NULL, /* Auto-select */
     };
 
-    connect_addr->type = SOCKET_ADDRESS_KIND_INET;
-    connect_addr->u.inet.data = g_new(InetSocketAddress, 1);
-    *connect_addr->u.inet.data = (InetSocketAddress) {
+    connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
+    connect_addr->u.inet = (InetSocketAddress) {
         .host = g_strdup("127.0.0.1"),
         .port = NULL, /* Filled in later */
     };
@@ -338,16 +336,14 @@ static void test_io_channel_ipv6(bool async)
     SocketAddress *listen_addr = g_new0(SocketAddress, 1);
     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
 
-    listen_addr->type = SOCKET_ADDRESS_KIND_INET;
-    listen_addr->u.inet.data = g_new(InetSocketAddress, 1);
-    *listen_addr->u.inet.data = (InetSocketAddress) {
+    listen_addr->type = SOCKET_ADDRESS_TYPE_INET;
+    listen_addr->u.inet = (InetSocketAddress) {
         .host = g_strdup("::1"),
         .port = NULL, /* Auto-select */
     };
 
-    connect_addr->type = SOCKET_ADDRESS_KIND_INET;
-    connect_addr->u.inet.data = g_new(InetSocketAddress, 1);
-    *connect_addr->u.inet.data = (InetSocketAddress) {
+    connect_addr->type = SOCKET_ADDRESS_TYPE_INET;
+    connect_addr->u.inet = (InetSocketAddress) {
         .host = g_strdup("::1"),
         .port = NULL, /* Filled in later */
     };
@@ -378,13 +374,11 @@ static void test_io_channel_unix(bool async)
     SocketAddress *connect_addr = g_new0(SocketAddress, 1);
 
 #define TEST_SOCKET "test-io-channel-socket.sock"
-    listen_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
-    listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
+    listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
 
-    connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
-    connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
+    connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
 
     test_io_channel(async, listen_addr, connect_addr, true);
 
@@ -427,13 +421,11 @@ static void test_io_channel_unix_fd_pass(void)
     fdsend[1] = testfd;
     fdsend[2] = testfd;
 
-    listen_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
-    listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
+    listen_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    listen_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
 
-    connect_addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
-    connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET);
+    connect_addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+    connect_addr->u.q_unix.path = g_strdup(TEST_SOCKET);
 
     test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst);
 
diff --git a/tests/test-keyval.c b/tests/test-keyval.c
index ba19560a22..c556b1b117 100644
--- a/tests/test-keyval.c
+++ b/tests/test-keyval.c
@@ -628,6 +628,7 @@ static void test_keyval_visit_alternate(void)
     visit_type_AltNumStr(v, "a", &ans, &error_abort);
     g_assert_cmpint(ans->type, ==, QTYPE_QSTRING);
     g_assert_cmpstr(ans->u.s, ==, "1");
+    qapi_free_AltNumStr(ans);
     visit_type_AltNumInt(v, "a", &ani, &err);
     error_free_or_abort(&err);
     visit_end_struct(v, NULL);
@@ -651,9 +652,12 @@ static void test_keyval_visit_any(void)
     g_assert(qlist);
     qstr = qobject_to_qstring(qlist_pop(qlist));
     g_assert_cmpstr(qstring_get_str(qstr), ==, "null");
+    QDECREF(qstr);
     qstr = qobject_to_qstring(qlist_pop(qlist));
     g_assert_cmpstr(qstring_get_str(qstr), ==, "1");
     g_assert(qlist_empty(qlist));
+    QDECREF(qstr);
+    qobject_decref(any);
     visit_check_struct(v, &error_abort);
     visit_end_struct(v, NULL);
     visit_free(v);
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
index 0ad74b464f..cc1bb1afdf 100644
--- a/tests/test-qemu-opts.c
+++ b/tests/test-qemu-opts.c
@@ -299,7 +299,7 @@ static void test_qemu_opt_get_size(void)
     dict = qdict_new();
     g_assert(dict != NULL);
 
-    qdict_put(dict, "size1", qstring_from_str("10"));
+    qdict_put_str(dict, "size1", "10");
 
     qemu_opts_absorb_qdict(opts, dict, &error_abort);
     g_assert(error_abort == NULL);
@@ -309,7 +309,7 @@ static void test_qemu_opt_get_size(void)
     g_assert(opt == 10);
 
     /* reset value */
-    qdict_put(dict, "size1", qstring_from_str("15"));
+    qdict_put_str(dict, "size1", "15");
 
     qemu_opts_absorb_qdict(opts, dict, &error_abort);
     g_assert(error_abort == NULL);
diff --git a/tests/test-qga.c b/tests/test-qga.c
index c780f0079a..c77f241036 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -146,14 +146,30 @@ static void test_qga_sync_delimited(gconstpointer fix)
     QDict *ret;
     gchar *cmd;
 
-    cmd = g_strdup_printf("%c{'execute': 'guest-sync-delimited',"
-                          " 'arguments': {'id': %u } }", 0xff, r);
+    cmd = g_strdup_printf("\xff{'execute': 'guest-sync-delimited',"
+                          " 'arguments': {'id': %u } }", r);
     qmp_fd_send(fixture->fd, cmd);
     g_free(cmd);
 
-    v = read(fixture->fd, &c, 1);
-    g_assert_cmpint(v, ==, 1);
-    g_assert_cmpint(c, ==, 0xff);
+    /*
+     * Read and ignore garbage until resynchronized.
+     *
+     * Note that the full reset sequence would involve checking the
+     * response of guest-sync-delimited and repeating the loop if
+     * 'id' field of the response does not match the 'id' field of
+     * the request. Testing this fully would require inserting
+     * garbage in the response stream and is left as a future test
+     * to implement.
+     *
+     * TODO: The server shouldn't emit so much garbage (among other
+     * things, it loudly complains about the client's \xff being
+     * invalid JSON, even though it is a documented part of the
+     * handshake.
+     */
+    do {
+        v = read(fixture->fd, &c, 1);
+        g_assert_cmpint(v, ==, 1);
+    } while (c != 0xff);
 
     ret = qmp_fd_receive(fixture->fd);
     g_assert_nonnull(ret);
@@ -172,8 +188,19 @@ static void test_qga_sync(gconstpointer fix)
     QDict *ret;
     gchar *cmd;
 
-    cmd = g_strdup_printf("%c{'execute': 'guest-sync',"
-                          " 'arguments': {'id': %u } }", 0xff, r);
+    /*
+     * TODO guest-sync is inherently limited: we cannot distinguish
+     * failure caused by reacting to garbage on the wire prior to this
+     * command, from failure of this actual command. Clients are
+     * supposed to be able to send a raw '\xff' byte to at least
+     * re-synchronize the server's parser prior to this command, but
+     * we are not in a position to test that here because (at least
+     * for now) it causes the server to issue an error message about
+     * invalid JSON. Testing of '\xff' handling is done in
+     * guest-sync-delimited instead.
+     */
+    cmd = g_strdup_printf("{'execute': 'guest-sync',"
+                          " 'arguments': {'id': %u } }", r);
     ret = qmp_fd(fixture->fd, cmd);
     g_free(cmd);
 
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index 0f81a98be2..acdded4d67 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -94,7 +94,7 @@ static void test_dispatch_cmd(void)
     QDict *req = qdict_new();
     QObject *resp;
 
-    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
+    qdict_put_str(req, "execute", "user_def_cmd");
 
     resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
     assert(resp != NULL);
@@ -111,7 +111,7 @@ static void test_dispatch_cmd_failure(void)
     QDict *args = qdict_new();
     QObject *resp;
 
-    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+    qdict_put_str(req, "execute", "user_def_cmd2");
 
     resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
     assert(resp != NULL);
@@ -122,10 +122,10 @@ static void test_dispatch_cmd_failure(void)
 
     /* check that with extra arguments it throws an error */
     req = qdict_new();
-    qdict_put(args, "a", qint_from_int(66));
+    qdict_put_int(args, "a", 66);
     qdict_put(req, "arguments", args);
 
-    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd")));
+    qdict_put_str(req, "execute", "user_def_cmd");
 
     resp = qmp_dispatch(&qmp_commands, QOBJECT(req));
     assert(resp != NULL);
@@ -164,14 +164,14 @@ static void test_dispatch_cmd_io(void)
     QDict *ret_dict_dict2, *ret_dict_dict2_userdef;
     QInt *ret3;
 
-    qdict_put_obj(ud1a, "integer", QOBJECT(qint_from_int(42)));
-    qdict_put_obj(ud1a, "string", QOBJECT(qstring_from_str("hello")));
-    qdict_put_obj(ud1b, "integer", QOBJECT(qint_from_int(422)));
-    qdict_put_obj(ud1b, "string", QOBJECT(qstring_from_str("hello2")));
-    qdict_put_obj(args, "ud1a", QOBJECT(ud1a));
-    qdict_put_obj(args, "ud1b", QOBJECT(ud1b));
-    qdict_put_obj(req, "arguments", QOBJECT(args));
-    qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2")));
+    qdict_put_int(ud1a, "integer", 42);
+    qdict_put_str(ud1a, "string", "hello");
+    qdict_put_int(ud1b, "integer", 422);
+    qdict_put_str(ud1b, "string", "hello2");
+    qdict_put(args, "ud1a", ud1a);
+    qdict_put(args, "ud1b", ud1b);
+    qdict_put(req, "arguments", args);
+    qdict_put_str(req, "execute", "user_def_cmd2");
 
     ret = qobject_to_qdict(test_qmp_dispatch(req));
 
@@ -190,9 +190,9 @@ static void test_dispatch_cmd_io(void)
     assert(!strcmp(qdict_get_str(ret_dict_dict2, "string"), "blah4"));
     QDECREF(ret);
 
-    qdict_put(args3, "a", qint_from_int(66));
+    qdict_put_int(args3, "a", 66);
     qdict_put(req, "arguments", args3);
-    qdict_put(req, "execute", qstring_from_str("guest-get-time"));
+    qdict_put_str(req, "execute", "guest-get-time");
 
     ret3 = qobject_to_qint(test_qmp_dispatch(req));
     assert(qint_get_int(ret3) == 66);
@@ -244,7 +244,7 @@ static void test_dealloc_partial(void)
         Visitor *v;
 
         ud2_dict = qdict_new();
-        qdict_put_obj(ud2_dict, "string0", QOBJECT(qstring_from_str(text)));
+        qdict_put_str(ud2_dict, "string0", text);
 
         v = qobject_input_visitor_new(QOBJECT(ud2_dict));
         visit_type_UserDefTwo(v, NULL, &ud2, &err);
diff --git a/tests/test-qmp-event.c b/tests/test-qmp-event.c
index 7bb621b027..4c0f09601d 100644
--- a/tests/test-qmp-event.c
+++ b/tests/test-qmp-event.c
@@ -153,7 +153,7 @@ static void test_event_a(TestEventData *data,
 {
     QDict *d;
     d = data->expect;
-    qdict_put(d, "event", qstring_from_str("EVENT_A"));
+    qdict_put_str(d, "event", "EVENT_A");
     qapi_event_send_event_a(&error_abort);
 }
 
@@ -162,7 +162,7 @@ static void test_event_b(TestEventData *data,
 {
     QDict *d;
     d = data->expect;
-    qdict_put(d, "event", qstring_from_str("EVENT_B"));
+    qdict_put_str(d, "event", "EVENT_B");
     qapi_event_send_event_b(&error_abort);
 }
 
@@ -177,16 +177,16 @@ static void test_event_c(TestEventData *data,
     b.has_enum1 = false;
 
     d_b = qdict_new();
-    qdict_put(d_b, "integer", qint_from_int(2));
-    qdict_put(d_b, "string", qstring_from_str("test1"));
+    qdict_put_int(d_b, "integer", 2);
+    qdict_put_str(d_b, "string", "test1");
 
     d_data = qdict_new();
-    qdict_put(d_data, "a", qint_from_int(1));
+    qdict_put_int(d_data, "a", 1);
     qdict_put(d_data, "b", d_b);
-    qdict_put(d_data, "c", qstring_from_str("test2"));
+    qdict_put_str(d_data, "c", "test2");
 
     d = data->expect;
-    qdict_put(d, "event", qstring_from_str("EVENT_C"));
+    qdict_put_str(d, "event", "EVENT_C");
     qdict_put(d, "data", d_data);
 
     qapi_event_send_event_c(true, 1, true, &b, "test2", &error_abort);
@@ -213,22 +213,22 @@ static void test_event_d(TestEventData *data,
     a.enum2 = ENUM_ONE_VALUE2;
 
     d_struct1 = qdict_new();
-    qdict_put(d_struct1, "integer", qint_from_int(2));
-    qdict_put(d_struct1, "string", qstring_from_str("test1"));
-    qdict_put(d_struct1, "enum1", qstring_from_str("value1"));
+    qdict_put_int(d_struct1, "integer", 2);
+    qdict_put_str(d_struct1, "string", "test1");
+    qdict_put_str(d_struct1, "enum1", "value1");
 
     d_a = qdict_new();
     qdict_put(d_a, "struct1", d_struct1);
-    qdict_put(d_a, "string", qstring_from_str("test2"));
-    qdict_put(d_a, "enum2", qstring_from_str("value2"));
+    qdict_put_str(d_a, "string", "test2");
+    qdict_put_str(d_a, "enum2", "value2");
 
     d_data = qdict_new();
     qdict_put(d_data, "a", d_a);
-    qdict_put(d_data, "b", qstring_from_str("test3"));
-    qdict_put(d_data, "enum3", qstring_from_str("value3"));
+    qdict_put_str(d_data, "b", "test3");
+    qdict_put_str(d_data, "enum3", "value3");
 
     d = data->expect;
-    qdict_put(d, "event", qstring_from_str("EVENT_D"));
+    qdict_put_str(d, "event", "EVENT_D");
     qdict_put(d, "data", d_data);
 
     qapi_event_send_event_d(&a, "test3", false, NULL, true, ENUM_ONE_VALUE3,
diff --git a/tests/test-qobject-output-visitor.c b/tests/test-qobject-output-visitor.c
index c213fceeb3..94b9518e40 100644
--- a/tests/test-qobject-output-visitor.c
+++ b/tests/test-qobject-output-visitor.c
@@ -343,9 +343,9 @@ static void test_visitor_out_any(TestOutputVisitorData *data,
 
     visitor_reset(data);
     qdict = qdict_new();
-    qdict_put(qdict, "integer", qint_from_int(-42));
-    qdict_put(qdict, "boolean", qbool_from_bool(true));
-    qdict_put(qdict, "string", qstring_from_str("foo"));
+    qdict_put_int(qdict, "integer", -42);
+    qdict_put_bool(qdict, "boolean", true);
+    qdict_put_str(qdict, "string", "foo");
     qobj = QOBJECT(qdict);
     visit_type_any(data->ov, NULL, &qobj, &error_abort);
     qobject_decref(qobj);
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index a61896c32d..9095af267e 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -491,7 +491,7 @@ static gboolean _test_server_free(TestServer *server)
     Chardev *chr = qemu_chr_fe_get_driver(&server->chr);
 
     qemu_chr_fe_deinit(&server->chr);
-    qemu_chr_delete(chr);
+    object_unparent(OBJECT(chr));
 
     for (i = 0; i < server->fds_num; i++) {
         close(server->fds[i]);
diff --git a/ui/console.c b/ui/console.c
index 189eecfd29..ac66b3c910 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2076,7 +2076,7 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds)
         s->t_attrib = s->t_attrib_default;
     }
 
-    qemu_chr_be_generic_open(chr);
+    qemu_chr_be_event(chr, CHR_EVENT_OPENED);
 }
 
 static void vc_chr_open(Chardev *chr,
diff --git a/ui/gtk.c b/ui/gtk.c
index a86848f3b0..7479ceef35 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1868,7 +1868,7 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
     gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), vc->tab_item,
                              gtk_label_new(vc->label));
 
-    qemu_chr_be_generic_open(vc->vte.chr);
+    qemu_chr_be_event(vc->vte.chr, CHR_EVENT_OPENED);
 
     return group;
 }
diff --git a/ui/input.c b/ui/input.c
index ed88cda6d6..830f912f99 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -41,6 +41,8 @@ static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue =
     QTAILQ_HEAD_INITIALIZER(kbd_queue);
 static QEMUTimer *kbd_timer;
 static uint32_t kbd_default_delay_ms = 10;
+static uint32_t queue_count;
+static uint32_t queue_limit = 1024;
 
 QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
                                                    QemuInputHandler *handler)
@@ -268,6 +270,7 @@ static void qemu_input_queue_process(void *opaque)
             break;
         }
         QTAILQ_REMOVE(queue, item, node);
+        queue_count--;
         g_free(item);
     }
 }
@@ -282,6 +285,7 @@ static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
     item->delay_ms = delay_ms;
     item->timer = timer;
     QTAILQ_INSERT_TAIL(queue, item, node);
+    queue_count++;
 
     if (start_timer) {
         timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
@@ -298,6 +302,7 @@ static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
     item->src = src;
     item->evt = evt;
     QTAILQ_INSERT_TAIL(queue, item, node);
+    queue_count++;
 }
 
 static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
@@ -306,6 +311,7 @@ static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
 
     item->type = QEMU_INPUT_QUEUE_SYNC;
     QTAILQ_INSERT_TAIL(queue, item, node);
+    queue_count++;
 }
 
 void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
@@ -381,7 +387,7 @@ void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
         qemu_input_event_send(src, evt);
         qemu_input_event_sync();
         qapi_free_InputEvent(evt);
-    } else {
+    } else if (queue_count < queue_limit) {
         qemu_input_queue_event(&kbd_queue, src, evt);
         qemu_input_queue_sync(&kbd_queue);
     }
@@ -405,12 +411,18 @@ void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
 
 void qemu_input_event_send_key_delay(uint32_t delay_ms)
 {
+    if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
+        return;
+    }
+
     if (!kbd_timer) {
         kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process,
                                  &kbd_queue);
     }
-    qemu_input_queue_delay(&kbd_queue, kbd_timer,
-                           delay_ms ? delay_ms : kbd_default_delay_ms);
+    if (queue_count < queue_limit) {
+        qemu_input_queue_delay(&kbd_queue, kbd_timer,
+                               delay_ms ? delay_ms : kbd_default_delay_ms);
+    }
 }
 
 InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 5ae29c14cf..3ade4a4918 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -510,12 +510,11 @@ vnc_socket_ip_addr_string(QIOChannelSocket *ioc,
         return NULL;
     }
 
-    if (addr->type != SOCKET_ADDRESS_KIND_INET) {
+    if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
         error_setg(errp, "Not an inet socket type");
         return NULL;
     }
-    ret = g_strdup_printf("%s;%s", addr->u.inet.data->host,
-                          addr->u.inet.data->port);
+    ret = g_strdup_printf("%s;%s", addr->u.inet.host, addr->u.inet.port);
     qapi_free_SocketAddress(addr);
     return ret;
 }
diff --git a/ui/vnc.c b/ui/vnc.c
index 349cfc9d86..9c4edcdbf5 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -113,26 +113,26 @@ static void vnc_init_basic_info(SocketAddress *addr,
                                 Error **errp)
 {
     switch (addr->type) {
-    case SOCKET_ADDRESS_KIND_INET:
-        info->host = g_strdup(addr->u.inet.data->host);
-        info->service = g_strdup(addr->u.inet.data->port);
-        if (addr->u.inet.data->ipv6) {
+    case SOCKET_ADDRESS_TYPE_INET:
+        info->host = g_strdup(addr->u.inet.host);
+        info->service = g_strdup(addr->u.inet.port);
+        if (addr->u.inet.ipv6) {
             info->family = NETWORK_ADDRESS_FAMILY_IPV6;
         } else {
             info->family = NETWORK_ADDRESS_FAMILY_IPV4;
         }
         break;
 
-    case SOCKET_ADDRESS_KIND_UNIX:
+    case SOCKET_ADDRESS_TYPE_UNIX:
         info->host = g_strdup("");
-        info->service = g_strdup(addr->u.q_unix.data->path);
+        info->service = g_strdup(addr->u.q_unix.path);
         info->family = NETWORK_ADDRESS_FAMILY_UNIX;
         break;
 
-    case SOCKET_ADDRESS_KIND_VSOCK:
-    case SOCKET_ADDRESS_KIND_FD:
+    case SOCKET_ADDRESS_TYPE_VSOCK:
+    case SOCKET_ADDRESS_TYPE_FD:
         error_setg(errp, "Unsupported socket address type %s",
-                   SocketAddressKind_lookup[addr->type]);
+                   SocketAddressType_lookup[addr->type]);
         break;
     default:
         abort();
@@ -398,26 +398,26 @@ VncInfo *qmp_query_vnc(Error **errp)
         }
 
         switch (addr->type) {
-        case SOCKET_ADDRESS_KIND_INET:
-            info->host = g_strdup(addr->u.inet.data->host);
-            info->service = g_strdup(addr->u.inet.data->port);
-            if (addr->u.inet.data->ipv6) {
+        case SOCKET_ADDRESS_TYPE_INET:
+            info->host = g_strdup(addr->u.inet.host);
+            info->service = g_strdup(addr->u.inet.port);
+            if (addr->u.inet.ipv6) {
                 info->family = NETWORK_ADDRESS_FAMILY_IPV6;
             } else {
                 info->family = NETWORK_ADDRESS_FAMILY_IPV4;
             }
             break;
 
-        case SOCKET_ADDRESS_KIND_UNIX:
+        case SOCKET_ADDRESS_TYPE_UNIX:
             info->host = g_strdup("");
-            info->service = g_strdup(addr->u.q_unix.data->path);
+            info->service = g_strdup(addr->u.q_unix.path);
             info->family = NETWORK_ADDRESS_FAMILY_UNIX;
             break;
 
-        case SOCKET_ADDRESS_KIND_VSOCK:
-        case SOCKET_ADDRESS_KIND_FD:
+        case SOCKET_ADDRESS_TYPE_VSOCK:
+        case SOCKET_ADDRESS_TYPE_FD:
             error_setg(errp, "Unsupported socket address type %s",
-                       SocketAddressKind_lookup[addr->type]);
+                       SocketAddressType_lookup[addr->type]);
             goto out_error;
         default:
             abort();
@@ -3161,13 +3161,13 @@ static void vnc_display_print_local_addr(VncDisplay *vd)
         return;
     }
 
-    if (addr->type != SOCKET_ADDRESS_KIND_INET) {
+    if (addr->type != SOCKET_ADDRESS_TYPE_INET) {
         qapi_free_SocketAddress(addr);
         return;
     }
     error_printf_unless_qmp("VNC server running on %s:%s\n",
-                            addr->u.inet.data->host,
-                            addr->u.inet.data->port);
+                            addr->u.inet.host,
+                            addr->u.inet.port);
     qapi_free_SocketAddress(addr);
 }
 
@@ -3423,9 +3423,8 @@ static int vnc_display_get_address(const char *addrstr,
     addr = g_new0(SocketAddress, 1);
 
     if (strncmp(addrstr, "unix:", 5) == 0) {
-        addr->type = SOCKET_ADDRESS_KIND_UNIX;
-        addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
-        addr->u.q_unix.data->path = g_strdup(addrstr + 5);
+        addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+        addr->u.q_unix.path = g_strdup(addrstr + 5);
 
         if (websocket) {
             error_setg(errp, "UNIX sockets not supported with websock");
@@ -3461,8 +3460,8 @@ static int vnc_display_get_address(const char *addrstr,
             }
         }
 
-        addr->type = SOCKET_ADDRESS_KIND_INET;
-        inet = addr->u.inet.data = g_new0(InetSocketAddress, 1);
+        addr->type = SOCKET_ADDRESS_TYPE_INET;
+        inet = &addr->u.inet;
         if (addrstr[0] == '[' && addrstr[hostlen - 1] == ']') {
             inet->host = g_strndup(addrstr + 1, hostlen - 2);
         } else {
@@ -3601,13 +3600,12 @@ static int vnc_display_get_addresses(QemuOpts *opts,
          * address for websocket too
          */
         if (*retnsaddr == 1 &&
-            (*retsaddr)[0]->type == SOCKET_ADDRESS_KIND_INET &&
-            wsaddr->type == SOCKET_ADDRESS_KIND_INET &&
-            g_str_equal(wsaddr->u.inet.data->host, "") &&
-            !g_str_equal((*retsaddr)[0]->u.inet.data->host, "")) {
-            g_free(wsaddr->u.inet.data->host);
-            wsaddr->u.inet.data->host =
-                g_strdup((*retsaddr)[0]->u.inet.data->host);
+            (*retsaddr)[0]->type == SOCKET_ADDRESS_TYPE_INET &&
+            wsaddr->type == SOCKET_ADDRESS_TYPE_INET &&
+            g_str_equal(wsaddr->u.inet.host, "") &&
+            !g_str_equal((*retsaddr)[0]->u.inet.host, "")) {
+            g_free(wsaddr->u.inet.host);
+            wsaddr->u.inet.host = g_strdup((*retsaddr)[0]->u.inet.host);
         }
 
         *retwsaddr = g_renew(SocketAddress *, *retwsaddr, *retnwsaddr + 1);
@@ -3648,8 +3646,8 @@ static int vnc_display_connect(VncDisplay *vd,
         error_setg(errp, "Expected a single address in reverse mode");
         return -1;
     }
-    /* TODO SOCKET_ADDRESS_KIND_FD when fd has AF_UNIX */
-    vd->is_unix = saddr[0]->type == SOCKET_ADDRESS_KIND_UNIX;
+    /* TODO SOCKET_ADDRESS_TYPE_FD when fd has AF_UNIX */
+    vd->is_unix = saddr[0]->type == SOCKET_ADDRESS_TYPE_UNIX;
     sioc = qio_channel_socket_new();
     qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-reverse");
     if (qio_channel_socket_connect_sync(sioc, saddr[0], errp) < 0) {
diff --git a/util/qemu-config.c b/util/qemu-config.c
index 5527100a01..405dd1a1d7 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -227,6 +227,12 @@ static QemuOptsList machine_opts = {
             .name = "dea-key-wrap",
             .type = QEMU_OPT_BOOL,
             .help = "enable/disable DEA key wrapping using the CPACF wrapping key",
+        },{
+            .name = "loadparm",
+            .type = QEMU_OPT_STRING,
+            .help = "Up to 8 chars in set of [A-Za-z0-9. ](lower case chars"
+                    " converted to upper case) to pass to machine"
+                    " loader, boot manager, and guest kernel",
         },
         { /* End of list */ }
     }
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 5ce1b5c246..5977bfc3e9 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -1054,17 +1054,15 @@ void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
 QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
 {
     QemuOpt *opt;
-    QObject *val;
 
     if (!qdict) {
         qdict = qdict_new();
     }
     if (opts->id) {
-        qdict_put(qdict, "id", qstring_from_str(opts->id));
+        qdict_put_str(qdict, "id", opts->id);
     }
     QTAILQ_FOREACH(opt, &opts->head, next) {
-        val = QOBJECT(qstring_from_str(opt->str));
-        qdict_put_obj(qdict, opt->name, val);
+        qdict_put_str(qdict, opt->name, opt->str);
     }
     return qdict;
 }
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 8188d9a8d7..d8183f79d7 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -22,6 +22,7 @@
 #endif /* CONFIG_AF_VSOCK */
 
 #include "monitor/monitor.h"
+#include "qapi/clone-visitor.h"
 #include "qapi/error.h"
 #include "qemu/sockets.h"
 #include "qemu/main-loop.h"
@@ -578,16 +579,15 @@ err:
 }
 
 /* compatibility wrapper */
-InetSocketAddress *inet_parse(const char *str, Error **errp)
+int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
 {
-    InetSocketAddress *addr;
     const char *optstr, *h;
     char host[65];
     char port[33];
     int to;
     int pos;
 
-    addr = g_new0(InetSocketAddress, 1);
+    memset(addr, 0, sizeof(*addr));
 
     /* parse address */
     if (str[0] == ':') {
@@ -595,20 +595,20 @@ InetSocketAddress *inet_parse(const char *str, Error **errp)
         host[0] = '\0';
         if (sscanf(str, ":%32[^,]%n", port, &pos) != 1) {
             error_setg(errp, "error parsing port in address '%s'", str);
-            goto fail;
+            return -1;
         }
     } else if (str[0] == '[') {
         /* IPv6 addr */
         if (sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos) != 2) {
             error_setg(errp, "error parsing IPv6 address '%s'", str);
-            goto fail;
+            return -1;
         }
         addr->ipv6 = addr->has_ipv6 = true;
     } else {
         /* hostname or IPv4 addr */
         if (sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos) != 2) {
             error_setg(errp, "error parsing address '%s'", str);
-            goto fail;
+            return -1;
         }
         if (host[strspn(host, "0123456789.")] == '\0') {
             addr->ipv4 = addr->has_ipv4 = true;
@@ -626,7 +626,7 @@ InetSocketAddress *inet_parse(const char *str, Error **errp)
         if (sscanf(h, "%d%n", &to, &pos) != 1 ||
             (h[pos] != '\0' && h[pos] != ',')) {
             error_setg(errp, "error parsing to= argument");
-            goto fail;
+            return -1;
         }
         addr->has_to = true;
         addr->to = to;
@@ -637,11 +637,7 @@ InetSocketAddress *inet_parse(const char *str, Error **errp)
     if (strstr(optstr, ",ipv6")) {
         addr->ipv6 = addr->has_ipv6 = true;
     }
-    return addr;
-
-fail:
-    qapi_free_InetSocketAddress(addr);
-    return NULL;
+    return 0;
 }
 
 
@@ -656,13 +652,12 @@ fail:
 int inet_connect(const char *str, Error **errp)
 {
     int sock = -1;
-    InetSocketAddress *addr;
+    InetSocketAddress *addr = g_new(InetSocketAddress, 1);
 
-    addr = inet_parse(str, errp);
-    if (addr != NULL) {
+    if (!inet_parse(addr, str, errp)) {
         sock = inet_connect_saddr(addr, NULL, NULL, errp);
-        qapi_free_InetSocketAddress(addr);
     }
+    qapi_free_InetSocketAddress(addr);
     return sock;
 }
 
@@ -793,26 +788,25 @@ static int vsock_listen_saddr(VsockSocketAddress *vaddr,
     return slisten;
 }
 
-static VsockSocketAddress *vsock_parse(const char *str, Error **errp)
+static int vsock_parse(VsockSocketAddress *addr, const char *str,
+                       Error **errp)
 {
-    VsockSocketAddress *addr = NULL;
     char cid[33];
     char port[33];
     int n;
 
     if (sscanf(str, "%32[^:]:%32[^,]%n", cid, port, &n) != 2) {
         error_setg(errp, "error parsing address '%s'", str);
-        return NULL;
+        return -1;
     }
     if (str[n] != '\0') {
         error_setg(errp, "trailing characters in address '%s'", str);
-        return NULL;
+        return -1;
     }
 
-    addr = g_new0(VsockSocketAddress, 1);
     addr->cid = g_strdup(cid);
     addr->port = g_strdup(port);
-    return addr;
+    return 0;
 }
 #else
 static void vsock_unsupported(Error **errp)
@@ -835,10 +829,11 @@ static int vsock_listen_saddr(VsockSocketAddress *vaddr,
     return -1;
 }
 
-static VsockSocketAddress *vsock_parse(const char *str, Error **errp)
+static int vsock_parse(VsockSocketAddress *addr, const char *str,
+                        Error **errp)
 {
     vsock_unsupported(errp);
-    return NULL;
+    return -1;
 }
 #endif /* CONFIG_AF_VSOCK */
 
@@ -1045,29 +1040,25 @@ SocketAddress *socket_parse(const char *str, Error **errp)
             error_setg(errp, "invalid Unix socket address");
             goto fail;
         } else {
-            addr->type = SOCKET_ADDRESS_KIND_UNIX;
-            addr->u.q_unix.data = g_new(UnixSocketAddress, 1);
-            addr->u.q_unix.data->path = g_strdup(str + 5);
+            addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+            addr->u.q_unix.path = g_strdup(str + 5);
         }
     } else if (strstart(str, "fd:", NULL)) {
         if (str[3] == '\0') {
             error_setg(errp, "invalid file descriptor address");
             goto fail;
         } else {
-            addr->type = SOCKET_ADDRESS_KIND_FD;
-            addr->u.fd.data = g_new(String, 1);
-            addr->u.fd.data->str = g_strdup(str + 3);
+            addr->type = SOCKET_ADDRESS_TYPE_FD;
+            addr->u.fd.str = g_strdup(str + 3);
         }
     } else if (strstart(str, "vsock:", NULL)) {
-        addr->type = SOCKET_ADDRESS_KIND_VSOCK;
-        addr->u.vsock.data = vsock_parse(str + strlen("vsock:"), errp);
-        if (addr->u.vsock.data == NULL) {
+        addr->type = SOCKET_ADDRESS_TYPE_VSOCK;
+        if (vsock_parse(&addr->u.vsock, str + strlen("vsock:"), errp)) {
             goto fail;
         }
     } else {
-        addr->type = SOCKET_ADDRESS_KIND_INET;
-        addr->u.inet.data = inet_parse(str, errp);
-        if (addr->u.inet.data == NULL) {
+        addr->type = SOCKET_ADDRESS_TYPE_INET;
+        if (inet_parse(&addr->u.inet, str, errp)) {
             goto fail;
         }
     }
@@ -1084,24 +1075,24 @@ int socket_connect(SocketAddress *addr, NonBlockingConnectHandler *callback,
     int fd;
 
     switch (addr->type) {
-    case SOCKET_ADDRESS_KIND_INET:
-        fd = inet_connect_saddr(addr->u.inet.data, callback, opaque, errp);
+    case SOCKET_ADDRESS_TYPE_INET:
+        fd = inet_connect_saddr(&addr->u.inet, callback, opaque, errp);
         break;
 
-    case SOCKET_ADDRESS_KIND_UNIX:
-        fd = unix_connect_saddr(addr->u.q_unix.data, callback, opaque, errp);
+    case SOCKET_ADDRESS_TYPE_UNIX:
+        fd = unix_connect_saddr(&addr->u.q_unix, callback, opaque, errp);
         break;
 
-    case SOCKET_ADDRESS_KIND_FD:
-        fd = monitor_get_fd(cur_mon, addr->u.fd.data->str, errp);
+    case SOCKET_ADDRESS_TYPE_FD:
+        fd = monitor_get_fd(cur_mon, addr->u.fd.str, errp);
         if (fd >= 0 && callback) {
             qemu_set_nonblock(fd);
             callback(fd, NULL, opaque);
         }
         break;
 
-    case SOCKET_ADDRESS_KIND_VSOCK:
-        fd = vsock_connect_saddr(addr->u.vsock.data, callback, opaque, errp);
+    case SOCKET_ADDRESS_TYPE_VSOCK:
+        fd = vsock_connect_saddr(&addr->u.vsock, callback, opaque, errp);
         break;
 
     default:
@@ -1115,20 +1106,20 @@ int socket_listen(SocketAddress *addr, Error **errp)
     int fd;
 
     switch (addr->type) {
-    case SOCKET_ADDRESS_KIND_INET:
-        fd = inet_listen_saddr(addr->u.inet.data, 0, false, errp);
+    case SOCKET_ADDRESS_TYPE_INET:
+        fd = inet_listen_saddr(&addr->u.inet, 0, false, errp);
         break;
 
-    case SOCKET_ADDRESS_KIND_UNIX:
-        fd = unix_listen_saddr(addr->u.q_unix.data, false, errp);
+    case SOCKET_ADDRESS_TYPE_UNIX:
+        fd = unix_listen_saddr(&addr->u.q_unix, false, errp);
         break;
 
-    case SOCKET_ADDRESS_KIND_FD:
-        fd = monitor_get_fd(cur_mon, addr->u.fd.data->str, errp);
+    case SOCKET_ADDRESS_TYPE_FD:
+        fd = monitor_get_fd(cur_mon, addr->u.fd.str, errp);
         break;
 
-    case SOCKET_ADDRESS_KIND_VSOCK:
-        fd = vsock_listen_saddr(addr->u.vsock.data, errp);
+    case SOCKET_ADDRESS_TYPE_VSOCK:
+        fd = vsock_listen_saddr(&addr->u.vsock, errp);
         break;
 
     default:
@@ -1143,12 +1134,12 @@ void socket_listen_cleanup(int fd, Error **errp)
 
     addr = socket_local_address(fd, errp);
 
-    if (addr->type == SOCKET_ADDRESS_KIND_UNIX
-        && addr->u.q_unix.data->path) {
-        if (unlink(addr->u.q_unix.data->path) < 0 && errno != ENOENT) {
+    if (addr->type == SOCKET_ADDRESS_TYPE_UNIX
+        && addr->u.q_unix.path) {
+        if (unlink(addr->u.q_unix.path) < 0 && errno != ENOENT) {
             error_setg_errno(errp, errno,
                              "Failed to unlink socket %s",
-                             addr->u.q_unix.data->path);
+                             addr->u.q_unix.path);
         }
     }
 
@@ -1160,13 +1151,13 @@ int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp)
     int fd;
 
     /*
-     * TODO SOCKET_ADDRESS_KIND_FD when fd is AF_INET or AF_INET6
+     * TODO SOCKET_ADDRESS_TYPE_FD when fd is AF_INET or AF_INET6
      * (although other address families can do SOCK_DGRAM, too)
      */
     switch (remote->type) {
-    case SOCKET_ADDRESS_KIND_INET:
-        fd = inet_dgram_saddr(remote->u.inet.data,
-                              local ? local->u.inet.data : NULL, errp);
+    case SOCKET_ADDRESS_TYPE_INET:
+        fd = inet_dgram_saddr(&remote->u.inet,
+                              local ? &local->u.inet : NULL, errp);
         break;
 
     default:
@@ -1199,8 +1190,8 @@ socket_sockaddr_to_address_inet(struct sockaddr_storage *sa,
     }
 
     addr = g_new0(SocketAddress, 1);
-    addr->type = SOCKET_ADDRESS_KIND_INET;
-    inet = addr->u.inet.data = g_new0(InetSocketAddress, 1);
+    addr->type = SOCKET_ADDRESS_TYPE_INET;
+    inet = &addr->u.inet;
     inet->host = g_strdup(host);
     inet->port = g_strdup(serv);
     if (sa->ss_family == AF_INET) {
@@ -1223,11 +1214,9 @@ socket_sockaddr_to_address_unix(struct sockaddr_storage *sa,
     struct sockaddr_un *su = (struct sockaddr_un *)sa;
 
     addr = g_new0(SocketAddress, 1);
-    addr->type = SOCKET_ADDRESS_KIND_UNIX;
-    addr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
+    addr->type = SOCKET_ADDRESS_TYPE_UNIX;
     if (su->sun_path[0]) {
-        addr->u.q_unix.data->path = g_strndup(su->sun_path,
-                                              sizeof(su->sun_path));
+        addr->u.q_unix.path = g_strndup(su->sun_path, sizeof(su->sun_path));
     }
 
     return addr;
@@ -1245,8 +1234,8 @@ socket_sockaddr_to_address_vsock(struct sockaddr_storage *sa,
     struct sockaddr_vm *svm = (struct sockaddr_vm *)sa;
 
     addr = g_new0(SocketAddress, 1);
-    addr->type = SOCKET_ADDRESS_KIND_VSOCK;
-    addr->u.vsock.data = vaddr = g_new0(VsockSocketAddress, 1);
+    addr->type = SOCKET_ADDRESS_TYPE_VSOCK;
+    vaddr = &addr->u.vsock;
     vaddr->cid = g_strdup_printf("%u", svm->svm_cid);
     vaddr->port = g_strdup_printf("%u", svm->svm_port);
 
@@ -1318,8 +1307,8 @@ char *socket_address_to_string(struct SocketAddress *addr, Error **errp)
     InetSocketAddress *inet;
 
     switch (addr->type) {
-    case SOCKET_ADDRESS_KIND_INET:
-        inet = addr->u.inet.data;
+    case SOCKET_ADDRESS_TYPE_INET:
+        inet = &addr->u.inet;
         if (strchr(inet->host, ':') == NULL) {
             buf = g_strdup_printf("%s:%s", inet->host, inet->port);
         } else {
@@ -1327,18 +1316,18 @@ char *socket_address_to_string(struct SocketAddress *addr, Error **errp)
         }
         break;
 
-    case SOCKET_ADDRESS_KIND_UNIX:
-        buf = g_strdup(addr->u.q_unix.data->path);
+    case SOCKET_ADDRESS_TYPE_UNIX:
+        buf = g_strdup(addr->u.q_unix.path);
         break;
 
-    case SOCKET_ADDRESS_KIND_FD:
-        buf = g_strdup(addr->u.fd.data->str);
+    case SOCKET_ADDRESS_TYPE_FD:
+        buf = g_strdup(addr->u.fd.str);
         break;
 
-    case SOCKET_ADDRESS_KIND_VSOCK:
+    case SOCKET_ADDRESS_TYPE_VSOCK:
         buf = g_strdup_printf("%s:%s",
-                              addr->u.vsock.data->cid,
-                              addr->u.vsock.data->port);
+                              addr->u.vsock.cid,
+                              addr->u.vsock.port);
         break;
 
     default:
@@ -1347,29 +1336,33 @@ char *socket_address_to_string(struct SocketAddress *addr, Error **errp)
     return buf;
 }
 
-SocketAddress *socket_address_crumple(SocketAddressFlat *addr_flat)
+SocketAddress *socket_address_flatten(SocketAddressLegacy *addr_legacy)
 {
     SocketAddress *addr = g_new(SocketAddress, 1);
 
-    switch (addr_flat->type) {
-    case SOCKET_ADDRESS_FLAT_TYPE_INET:
-        addr->type = SOCKET_ADDRESS_KIND_INET;
-        addr->u.inet.data = QAPI_CLONE(InetSocketAddress,
-                                       &addr_flat->u.inet);
+    if (!addr_legacy) {
+        return NULL;
+    }
+
+    switch (addr_legacy->type) {
+    case SOCKET_ADDRESS_LEGACY_KIND_INET:
+        addr->type = SOCKET_ADDRESS_TYPE_INET;
+        QAPI_CLONE_MEMBERS(InetSocketAddress, &addr->u.inet,
+                           addr_legacy->u.inet.data);
         break;
-    case SOCKET_ADDRESS_FLAT_TYPE_UNIX:
-        addr->type = SOCKET_ADDRESS_KIND_UNIX;
-        addr->u.q_unix.data = QAPI_CLONE(UnixSocketAddress,
-                                         &addr_flat->u.q_unix);
+    case SOCKET_ADDRESS_LEGACY_KIND_UNIX:
+        addr->type = SOCKET_ADDRESS_TYPE_UNIX;
+        QAPI_CLONE_MEMBERS(UnixSocketAddress, &addr->u.q_unix,
+                           addr_legacy->u.q_unix.data);
         break;
-    case SOCKET_ADDRESS_FLAT_TYPE_VSOCK:
-        addr->type = SOCKET_ADDRESS_KIND_VSOCK;
-        addr->u.vsock.data = QAPI_CLONE(VsockSocketAddress,
-                                        &addr_flat->u.vsock);
+    case SOCKET_ADDRESS_LEGACY_KIND_VSOCK:
+        addr->type = SOCKET_ADDRESS_TYPE_VSOCK;
+        QAPI_CLONE_MEMBERS(VsockSocketAddress, &addr->u.vsock,
+                           addr_legacy->u.vsock.data);
         break;
-    case SOCKET_ADDRESS_FLAT_TYPE_FD:
-        addr->type = SOCKET_ADDRESS_KIND_FD;
-        addr->u.fd.data = QAPI_CLONE(String, &addr_flat->u.fd);
+    case SOCKET_ADDRESS_LEGACY_KIND_FD:
+        addr->type = SOCKET_ADDRESS_TYPE_FD;
+        QAPI_CLONE_MEMBERS(String, &addr->u.fd, addr_legacy->u.fd.data);
         break;
     default:
         abort();
diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
index 73e3a0edf5..eacd99e497 100644
--- a/util/qemu-thread-posix.c
+++ b/util/qemu-thread-posix.c
@@ -14,6 +14,7 @@
 #include "qemu/thread.h"
 #include "qemu/atomic.h"
 #include "qemu/notify.h"
+#include "trace.h"
 
 static bool name_threads;
 
@@ -60,17 +61,30 @@ void qemu_mutex_lock(QemuMutex *mutex)
     err = pthread_mutex_lock(&mutex->lock);
     if (err)
         error_exit(err, __func__);
+
+    trace_qemu_mutex_locked(mutex);
 }
 
 int qemu_mutex_trylock(QemuMutex *mutex)
 {
-    return pthread_mutex_trylock(&mutex->lock);
+    int err;
+
+    err = pthread_mutex_trylock(&mutex->lock);
+    if (err == 0) {
+        trace_qemu_mutex_locked(mutex);
+        return 0;
+    }
+    if (err != EBUSY) {
+        error_exit(err, __func__);
+    }
+    return -EBUSY;
 }
 
 void qemu_mutex_unlock(QemuMutex *mutex)
 {
     int err;
 
+    trace_qemu_mutex_unlocked(mutex);
     err = pthread_mutex_unlock(&mutex->lock);
     if (err)
         error_exit(err, __func__);
@@ -130,7 +144,9 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
 {
     int err;
 
+    trace_qemu_mutex_unlocked(mutex);
     err = pthread_cond_wait(&cond->cond, &mutex->lock);
+    trace_qemu_mutex_locked(mutex);
     if (err)
         error_exit(err, __func__);
 }
diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c
index 59befd5202..653f29f442 100644
--- a/util/qemu-thread-win32.c
+++ b/util/qemu-thread-win32.c
@@ -19,6 +19,7 @@
 #include "qemu-common.h"
 #include "qemu/thread.h"
 #include "qemu/notify.h"
+#include "trace.h"
 #include <process.h>
 
 static bool name_threads;
@@ -55,6 +56,7 @@ void qemu_mutex_destroy(QemuMutex *mutex)
 void qemu_mutex_lock(QemuMutex *mutex)
 {
     AcquireSRWLockExclusive(&mutex->lock);
+    trace_qemu_mutex_locked(mutex);
 }
 
 int qemu_mutex_trylock(QemuMutex *mutex)
@@ -62,11 +64,16 @@ int qemu_mutex_trylock(QemuMutex *mutex)
     int owned;
 
     owned = TryAcquireSRWLockExclusive(&mutex->lock);
-    return !owned;
+    if (owned) {
+        trace_qemu_mutex_locked(mutex);
+        return 0;
+    }
+    return -EBUSY;
 }
 
 void qemu_mutex_unlock(QemuMutex *mutex)
 {
+    trace_qemu_mutex_unlocked(mutex);
     ReleaseSRWLockExclusive(&mutex->lock);
 }
 
@@ -118,7 +125,9 @@ void qemu_cond_broadcast(QemuCond *cond)
 
 void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
 {
+    trace_qemu_mutex_unlocked(mutex);
     SleepConditionVariableSRW(&cond->var, &mutex->lock, INFINITE, 0);
+    trace_qemu_mutex_locked(mutex);
 }
 
 void qemu_sem_init(QemuSemaphore *sem, int init)
diff --git a/util/trace-events b/util/trace-events
index b44ef4f895..fa540c620b 100644
--- a/util/trace-events
+++ b/util/trace-events
@@ -55,3 +55,7 @@ lockcnt_futex_wait_prepare(const void *lockcnt, int expected, int new) "lockcnt
 lockcnt_futex_wait(const void *lockcnt, int val) "lockcnt %p waiting on %d"
 lockcnt_futex_wait_resume(const void *lockcnt, int new) "lockcnt %p after wait: %d"
 lockcnt_futex_wake(const void *lockcnt) "lockcnt %p waking up one waiter"
+
+# util/qemu-thread-posix.c
+qemu_mutex_locked(void *lock) "locked mutex %p"
+qemu_mutex_unlocked(void *lock) "unlocked mutex %p"
diff --git a/vl.c b/vl.c
index 10f3afd860..ce2b392d8b 100644
--- a/vl.c
+++ b/vl.c
@@ -3728,26 +3728,21 @@ int main(int argc, char **argv, char **envp)
                 qdev_prop_register_global(&kvm_pit_lost_tick_policy);
                 break;
             }
-            case QEMU_OPTION_accel:
+            case QEMU_OPTION_accel: {
+                QemuOpts *accel_opts;
+
                 accel_opts = qemu_opts_parse_noisily(qemu_find_opts("accel"),
                                                      optarg, true);
                 optarg = qemu_opt_get(accel_opts, "accel");
-
-                olist = qemu_find_opts("machine");
-                if (strcmp("kvm", optarg) == 0) {
-                    qemu_opts_parse_noisily(olist, "accel=kvm", false);
-                } else if (strcmp("xen", optarg) == 0) {
-                    qemu_opts_parse_noisily(olist, "accel=xen", false);
-                } else if (strcmp("tcg", optarg) == 0) {
-                    qemu_opts_parse_noisily(olist, "accel=tcg", false);
-                } else {
-                    if (!is_help_option(optarg)) {
-                        error_printf("Unknown accelerator: %s", optarg);
-                    }
-                    error_printf("Supported accelerators: kvm, xen, tcg\n");
+                if (!optarg || is_help_option(optarg)) {
+                    error_printf("Possible accelerators: kvm, xen, hax, tcg\n");
                     exit(1);
                 }
+                accel_opts = qemu_opts_create(qemu_find_opts("machine"), NULL,
+                                              false, &error_abort);
+                qemu_opt_set(accel_opts, "accel", optarg, &error_abort);
                 break;
+            }
             case QEMU_OPTION_usb:
                 olist = qemu_find_opts("machine");
                 qemu_opts_parse_noisily(olist, "usb=on", false);
@@ -4730,6 +4725,7 @@ int main(int argc, char **argv, char **envp)
     audio_cleanup();
     monitor_cleanup();
     qemu_chr_cleanup();
+    /* TODO: unref root container, check all devices are ok */
 
     return 0;
 }